Repository navigation
feat(sandbox):持久化 Docker 容器生命周期所有权、代际租约与崩溃恢复(#38) - #58
Merged
Merged
Conversation
在 SQLite schema v97 中新增不可变启动意图、代际租约、写前动作、哈希链状态迁移和唯一清理收据。 为 Docker create/start/wait/TERM/KILL/delete 增加逐动作 fencing,并通过精确九标签、完整配置和资源指纹实现数据库主导的崩溃恢复。 补充抢占、陈旧写入、取消与超时重放、异常 daemon 响应、隐私边界及真实 Docker 生命周期验证。
Qiyuanqiii
marked this pull request as ready for review
August 14, 2026 05:38
将 nanoid override 与锁文件从 3.3.17 升级到首个受影响版本线的修复版本 3.3.18,解除 GHSA-2v37-7h3g-55p8 导致的 TypeScript CI 阻塞。 该提交仅修改 web/package.json 与 web/package-lock.json,不包含现有工作区中的其他 Web 或 Provider 改动。
5 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
Issue #38 要求把 Docker 容器从一次性、进程内的生命周期探针,提升为可持久化、可抢占、可恢复且能够拒绝陈旧写入的生命周期协调机制。
此前的实现虽然已经具备固定本地端点、确定性容器名、严格配置校验和基础清理逻辑,但仍存在几个根本缺口:
create/start/TERM/KILL/delete可能先发生,持久状态只能在整个流程结束后一次性返回,崩溃后无法区分“尚未调用”“调用结果未知”和“已生效但未提交”。LeaseGeneration只参与请求指纹,没有在每次 Docker 写入前校验当前租约的完整身份与有效期。Run无法从已经 created、running、exited 或 cleaning 的中间状态继续收敛,也无法安全处理 supervisor 竞争和 takeover。本次改动
1. 新增独立的 SQLite schema v97 生命周期聚合
新增不可变且非授权的 Docker lifecycle ledger,包括:
lease_id + owner_id + lease_generation + resource_generation + expiry做 fencing;created -> started -> exited/cleaning -> cleaned,并保留显式 failure facts;迁移中的 CHECK、UNIQUE 与 trigger 共同约束:
cleaning原因、cleaned终态和 receipt outcome 的一致性;v56 rehearsal 表及其“容器从未启动”语义保持不变。
2. 为实际 Docker 生命周期拆分可检查点操作
在现有固定端点 HTTP transport 上增加可恢复的窄操作:
ObserveStartWaitTerminateCleanupCREATE/START/WAIT/TERM/KILL/DELETE都会在发出 daemon 请求前调用逐动作 fence;有副作用的动作还会先持久化 prepared action。调用上下文严格受当前租约到期时间约束,避免旧 owner 在 takeover 后继续写 Docker。保留已有 transport 与 endpoint allowlist:
/var/run/docker.sock;DOCKER_HOST和远程/TCP endpoint;3. 增加九标签精确所有权与安全 adoption
在既有六个
io.cyberagent.*基础标签上增加:恢复和 adoption 必须同时满足:
未知容器、旧六标签容器、缺少标签、额外标签、Run/Attempt/generation/intent 不匹配、配置被修改或 inspect 证据不一致时,协调器都会 fail closed,并保持零 POST/DELETE 副作用。
4. 新增数据库主导的 lifecycle supervisor 与启动恢复
新增 package-private supervisor,提供:
BeginAndRun:先提交 launch intent 与 lease,再接触 Docker;RecoverOne:抢占过期租约,重新校验 Run/Workspace/permission/capability,然后按精确观察状态继续;RecoverStartup:只扫描数据库中可恢复 intent,不枚举或收养 daemon 中的未知对象。覆盖并收敛以下崩溃窗口:
当恢复时已经存在 durable
cleaning且容器仍在运行,supervisor 会沿用 sticky timeout/cancel reason,直接继续 TERM/KILL/cleanup,不会重新等待完整 timeout。自然退出、取消、超时和重复启动恢复最终只生成一个逻辑 cleaned 事实和一个 cleanup receipt。5. 稳定的失败关闭与隐私边界
新增或补充测试,确保:
connection_failed;configuration_mismatch;并发与恢复测试覆盖
本 PR 新增的回归场景包括:
CI 基线依赖修复
PR 首轮 GitHub Actions 中,生命周期相关的 Go、Rust 与 Windows job 均通过,但 TypeScript console 在最后的
npm audit --audit-level=high阶段失败。该失败与 lifecycle diff 无关:仓库基线通过 override 将间接依赖nanoid固定在3.3.17,而更新后的GHSA-2v37-7h3g-55p8要求该版本线至少升级到3.3.18。为恢复所有 PR 共用的依赖安全门禁,本 PR 增加一个独立且最小的后续提交:
web/package.json:仅将nanoidoverride 从3.3.17升级到3.3.18;web/package-lock.json:仅同步 nanoid 的 version、resolved URL 与 integrity;验证结果
已在只包含本 issue 改动的隔离工作树中完成:
go mod verifygo test -timeout 20m -count=1 ./...go vet ./...go test -race ./internal/sandbox ./internal/store ./internal/application -run 'Docker.*Lifecycle' -count=1npm cinpm ls nanoid --all:完整依赖树使用nanoid@3.3.18npm audit --audit-level=high:0 vulnerabilitiesnpm run typechecknpm test:59 个测试文件、229 个测试全部通过npm run build安全边界与非目标
本 PR 只提供 package-private、非授权的生命周期持久化与恢复基础设施:
新的 supervisor 与九标签 recovery 通过持久 fake daemon 做端到端崩溃/竞争测试;真实 Docker opt-in 测试继续验证固定本地 transport 与强制清理路径。产品接入、daemon-wide orphan 策略、secret materialization、bounded logs 和 Artifact 导出仍需后续独立 gate。
详细设计与不变量记录见 ADR 0096。
Closes #38