Skip to content

feat(sandbox): 只读输入、有界日志与原子 Artifact 输出(Issue #39) - #61

Merged
pppolf merged 3 commits into
CWNU-Open-Source-Community:mainfrom
pppolf:feat/docker-container-io-contract
Aug 14, 2026
Merged

pppolf merged 3 commits into
CWNU-Open-Source-Community:mainfrom
pppolf:feat/docker-container-io-contract

Conversation

@pppolf

@pppolf pppolf commented Aug 14, 2026

Copy link
Copy Markdown
Member

Closes #39

Summary

  • 只读输入投影 sandbox_docker_input_projection.v1(schema v98):规范化相对路径 + SHA-256 + 大小 + 媒体类型封印到 lifecycle attempt/generation、Plan、Observation、Run/Mission/Workspace 与 Spec 指纹;输入挂载固定 /run/cyberagent/inputs 只读;新增真实 inspect Mounts 隔离校验——唯一可写挂载必须是专用输出挂载,输入/工作区树必须只读(容器无法写原始 Workspace)。
  • 有界日志捕获 sandbox_docker_log_capture.v1:只经 POST containers/{id}/attach?logs=1&stderr=1&stdout=1&stream=0(无 live streaming);解复用器按流限制 256 KiB / 4096 行 + 墙钟时限,拒绝畸形/超大帧,非法 UTF-8 替换并计数,Secret 脱敏,只落库元数据与摘要回执(raw 不持久化)。
  • 输出暂存 sandbox_docker_output_staging.v1:只导出专用输出挂载的 GET containers/{id}/archive;tar 走查在 Windows/Linux 同一路径规则下拒绝 absolute/traversal/反斜杠/盘符、symlink/hardlink/设备节点、重复项,限制 64 文件 / 单文件 4 MiB / 总量 16 MiB,媒体类型检测与文本脱敏后写入进程内暂存目录;被拒归档不带受信清单。
  • 原子 Artifact 提交 sandbox_docker_output_commit.v1:接受清单必须与已完成暂存回执逐项精确一致;从暂存目录重读复哈希后,回执与全部条目在同一 SQLite 事务写入(operation key 幂等);失败不残留半提交行。Artifact 含 SHA-256、字节数、媒体类型、Run/Attempt/generation 与创建时间。
  • 传输白名单只开放上述两个端点;新增 15 个事件类型;应用服务不接 CLI/HTTP/Desktop(与 v97 生命周期切片相同的无产品入口边界)。容器输出始终是不可信证据,不会自动变成 Prompt/审批/命令/可执行内容。
  • stdin 默认关闭:本切片没有引入任何 stdin/exec 端点(保持关闭);网络默认关闭不变(spec 仍要求 network default-deny)。

Validation

  • go build ./...、go vet ./...
  • go test ./internal/sandbox ./internal/store ./internal/application ./internal/events -count=1 全量通过(含 v83-v97 迁移重放测试链更新至 v98)
  • go test -race ./internal/sandbox ./internal/application -count=1 通过
  • 黄金向量:attach 帧解复用(completed/字节截断/行截断/非法流/超大帧/UTF-8 违规+脱敏/deadline)
  • 对抗路径矩阵(Windows 分隔符/盘符/NUL/traversal 在单一规则集下拒绝)+ tar symlink/duplicate/超限拒绝 + 挂载隔离接受/拒绝矩阵
  • Store 幂等/原子性:commit 失败不残留部分行,operation key 重放
  • README schema 时间线 v98 行 + TestREADMEListsEverySchemaVersionInOrder
  • 真实 Docker daemon 的 attach/archive 实机验证(与 v97 相同,留待有 Docker 环境时执行;传输层用 scripted doer 全覆盖)

Audit

  • 无凭证或本地数据入库;raw 日志与暂存文件只存在于进程内目录
  • Policy/Workspace/Sandbox/持久化边界复核:所有新路径 fail-closed,无提权入口
  • 项目记忆账本与 ADR 0098 已更新

pppolf added 3 commits August 14, 2026 15:23
Schema v98 adds the sealed read-only input projection ledger, bounded
stdout/stderr log capture receipts, strict output staging receipts, and
atomic output commit receipts with per-file entries. The sandbox domain
pins one path rule set for Windows and Linux, demuxes and redacts the
attach stream under byte/line/deadline caps, walks the exported archive
with traversal/symlink/duplicate/size rejection, and commits accepted
manifests in one replay-safe store transaction. The I/O transport exposes
exactly two closed daemon endpoints (attach with stream=0 and archive of
the dedicated output mount). The application service stays unwired from
any product entry, matching the lifecycle slice boundary.
Update the project memory, status, progress, and task ledgers with the
schema-v98 slice for issue CWNU-Open-Source-Community#39 and add ADR 0098 documenting the sealed
read-only input projection, bounded log capture, strict output staging,
atomic commit, and the closed two-endpoint daemon surface.
@pppolf
pppolf merged commit 8e8fe04 into CWNU-Open-Source-Community:main Aug 14, 2026
5 checks passed
@pppolf
pppolf deleted the feat/docker-container-io-contract branch August 14, 2026 07:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(sandbox): 只读输入、有界日志与原子 Artifact 输出

1 participant