Document dual gates for nested sandbox tests
Why: Nested Bubblewrap tests fail inside the credential-isolated candidate boundary, and a green main gate alone would hide unrun product isolation checks.
Evidence: Dev 1ea93a5 make test SELF receipt; Backend and RDM test inventory; RDM CI workflow inspection; diff and relative-link checks.
Impact: Adds a pending written design and index entry only. No execution behavior or source lock changes.
Refs: Dev PR #537; Documents PR #100; approved remediation plan 20ada84
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# 版本依赖迁移:嵌套沙箱测试的双必需门禁修订设计 r1
|
||||
|
||||
状态:**书面设计待用户评审;尚未批准实施**(2026-10-14)。用户已同意先把“双必需门禁”写成正式修订设计;该回复不批准本文件、实施计划、独立环境配置或代码改动。本文件拟补充已批准的[独立 Review 整改设计](2026-10-14-versioned-dependency-review-remediation.md)及其[实施计划](2026-10-14-versioned-dependency-review-remediation-plan.md)。在书面修订获批前,原执行边界继续有效,Dev PR #537 等迁移 PR 保持 WIP。
|
||||
|
||||
## 触发事实与目标
|
||||
|
||||
Dev 候选 `1ea93a5f7254f5a4bac8fc65cd47dad9f9e51ea9` 的本地正式 `make test` **失败**(SELF 收据 `/tmp/dependency-task5-dev-test-20261014-01a1345f.json`):外层 Bubblewrap 已遮蔽宿主凭据,但 Backend 的真实沙箱集成测试再启动内层 `bwrap` 时返回 `No permissions to create a new namespace`。外层进程的 AppArmor 标识为 `bwrap//&unpriv_bwrap (enforce)`;最小嵌套探针复现失败。无 Docker socket、丢弃 capabilities 的独立 Docker 子容器探针也未能运行 `bwrap`;放宽该探针的 seccomp 或 AppArmor 配置仍失败。这些只说明**已试环境**不具备嵌套能力,不证明所有容器或独立主机都不可用。
|
||||
|
||||
同一次 `make test` 还出现 Backend runtime 测试缺少 `python-docx` 的失败;它是另一个未解决问题,不能因本修订设计而计作通过。本地 `make build` 在绕过本机 npm 代理故障后于同一 Dev SHA 通过,RDM `d8a7098` 的固定产品构建及其自身 CI run3130 通过;这些结果均不替代失败的 Dev 测试或下述独立重放。RDM 当前工作流在获取步骤后直接执行 `GOWORK=off make test`,没有该作业候选进程的无 socket 负例,因此 run3130 也不能证明 RDM CI 的执行隔离。
|
||||
|
||||
目标是在不暴露本机凭据、不把 Docker socket 交给候选代码、不改主机 AppArmor 或共享 runner 的前提下,同时证明普通组合功能及真实执行沙箱的产品语义。所有门禁绑定实际 Dev、Backend、RDM 固定提交;旧 SHA 的成功记录不迁移给新候选。
|
||||
|
||||
## 方案选择
|
||||
|
||||
| 方案 | 结论 |
|
||||
| --- | --- |
|
||||
| 在现有本地/CI 候选沙箱中强行嵌套 `bwrap` | 已试环境失败。若提升当前候选容器权限或改主机策略,会改变已批准的凭据与执行边界;本轮不采用。 |
|
||||
| 在主门禁隐藏 `bwrap` 或让测试自然 Skip,并把主门禁绿色当成完整通过 | 会漏掉沙箱逃逸、进程限制、overlay 等真实行为;不采用。 |
|
||||
| **双必需门禁**:现有隔离主门禁 + 独立、无凭据的原生沙箱重放 | 用户同意作为本轮书面设计基线。两份证据齐全、同源且通过,才可请求阶段 7 验收与后续合入。 |
|
||||
|
||||
### 门禁 A:隔离的组合验证
|
||||
|
||||
Dev 本地 `make test/build` 仍在现有 Bubblewrap 内运行;Dev CI 的 `test`、`test-pg`、`svc-realcombo` 仍由受信父步骤启动无 Docker socket 的候选子容器。RDM 自身的 `make test`/CI 也计入 A,须给出相同的用例状态报告及候选进程的 socket/凭据负例;在受信获取后直接于原作业容器执行候选 Makefile 的现状不能作为隔离证据。实施计划须为 RDM 候选步骤采用无 socket 子容器,或在同等受信边界下证明其执行环境天然无 socket、无凭据。其环境若能实际运行单层 `bwrap`,可记录真实 PASS,但不能免除 B 的独立重放。不得关闭外层隔离、向子容器挂载父 HOME/密钥/socket、增加特权,或让候选命令在受信父步骤直接运行。
|
||||
|
||||
主门禁只对**需要再次创建用户/挂载/PID namespace 的真实沙箱集成用例**实行显式的、有界的 `NOT_RUN_IN_A` 选择。Go 测试报告必须列出固定源码 SHA、包、每个排除的测试名及原因,核对源码中的实际测试清单,并证明其余测试实际运行且通过。嵌套用例清单出现缺失、新增、重命名、意外跳过或排除规则扩大,或主门禁出现其他失败时,A 失败。不能用 `bwrap` 缺席后 Go 的普通 Skip 作为“全部通过”,也不能在汇总中隐去这些用例;现有源测试若无法表达此状态,实施时增设可机器检查的清单/报告,而不是修改测试来伪造绿灯。
|
||||
|
||||
当前最小清单以**源码复核**为准:Dev 固定 Backend `48649a37ee92373c639a384a2c5a9dfaa2ec4bbb` 的 `internal/tools` 含 `TestSandboxHomeHidden`、`TestSandboxSiblingSessionUnreadable`、`TestSandboxNoNetwork`、`TestSandboxForkBombContained`、`TestSandboxOrphansDieWithNamespace`、`TestSandboxTimeoutKills`、`TestSandboxSessionWriteVisible`,以及 `TestSandboxWorkspaceOverlayRoundtrip`、`TestSandboxWorkspaceOverlayTimeoutDiscards`、`TestOverlayCleansShellDir`。RDM `d8a70988492ad0aad02768badc85502cc8c77820` 的 `internal/rdmapp` 含 `TestRDMExecIsolation_HomeSecretHidden`、`TestRDMExecIsolation_SiblingSessionUnreadable`、`TestRDMExecIsolation_CrossProjectUnreadable`、`TestRDMExecIsolation_ProcLimit`、`TestRDMExecIsolation_CancelKillsSandbox`。参数组装、策略选择、硬关闭及不启动 `bwrap` 的 `TestSandboxOrphanProbeScopesScript` 仍在 A 中运行,不能按名称前缀整组排除。若最终 RDM 组合或其他固定提供方实际包含更多启动 `bwrap` 的用例,须先更新可核验清单并经 Review,不能让它们自然 Skip。
|
||||
|
||||
### 门禁 B:原生沙箱独立重放
|
||||
|
||||
另在**独立、无凭据、无 Docker socket** 的短生命周期主机或 VM 上运行上述真实集成用例。该环境不能继承开发者 HOME、SSH agent、Gitea/npm token、父 CI 文件系统或 Docker socket;由受信获取步骤先固定并验证源码和所需模块,再以不含凭据的包交给重放环境。环境可访问所需本地测试依赖,但不得靠给现有 A 容器提权来实现。当前尚无可用环境的正例,因此 B 状态是 `NOT_RUN`,也没有“预计会通过”的承诺。实施计划须先安排最小环境探针并决定可重复执行的交付方式;若无法建立该环境,本轮迁移保持 WIP。
|
||||
|
||||
B 开始测试前须验证:`bwrap` 能实际启动目标 namespace、内部 `/home` 与外部假标记隔离、宿主/父凭据及 Docker socket 不存在;只看 `command -v bwrap` 不够。运行固定 SHA 的真实测试时,采用 `go test -json -count=1` 或等价逐用例记录,核对预期测试均存在、实际 `PASS` 且没有 `SKIP`;测试包退出码和正向沙箱启动探针都必须为零。现有若干“秘密不可读”断言在 `bwrap` 根本没启动时仍可能误判,因此 B 的正向启动证据是这些负例成立的前提,必要时加强测试本身。任何命名用例失败、跳过、缺失或探针失败,B 失败。
|
||||
|
||||
B 至少覆盖两个不同的 Backend 对象:Dev 应用清单的 `48649a37...`,以及 RDM 产品所用 Go 模块图的 Backend 固定提交(当前产品构建清单为 `f1302ed...`);还须覆盖 RDM 自身提交 `d8a7098...` 的隔离用例。最终 SHA 由候选清单和 Go 图现场解析,不能只按这里的前缀代替核验。不同 Backend 提交分别运行、分别记录,即使测试名相同也不互借结果。提供方提交或测试清单改变时,A 与 B 的旧结果一并失效。
|
||||
|
||||
重放由独立审阅者操作并以 `REPLAY` 记录其身份、环境身份/配置摘要、源码完整 SHA、清单/模块图、命令、退出码、逐用例结果和完整脱敏输出;若以后由可验证身份的受信 CI 运行,可记为 `GATE`。作者自测只能记 `SELF`,不能把本地收据改标签充当独立证据。无凭据状态用假标记与环境/挂载检查证明,不读取或输出真实密钥值。
|
||||
|
||||
## 汇总、恢复与授权边界
|
||||
|
||||
现有三个 Dev CI context 必须在**最终 Dev HEAD** 通过,并在产出物中显式声明 A 的 `NOT_RUN_IN_A` 清单;RDM 当前 HEAD 的产品构建与 CI 也须重新核验其候选进程边界和用例报告。协调者对最终 Dev/Backend/RDM 固定 SHA 建立一份门禁对照:A 的 GATE 身份与链接、B 的独立 REPLAY/GATE 身份与完整收据、每个排除用例到 B 通过用例的一一映射,以及其余 `make test/build`、浏览器和交付检查的真实状态。B 不是把 A 的失败改名为通过;A 中除约定清单外的任何失败(包括当前 `python-docx` 问题)都须正常修复并重跑。
|
||||
|
||||
只有 A、B 和其他原有必需检查在同一最终来源图上全部通过,才整理新的阶段 7 正式验收材料、请求用户审阅;之后仍须独立 Stage 8 Review、最新 `task-sync`、当前 HEAD CI 和队列窗口核验,再按现有规则合入。B 为 `NOT_RUN`、身份不可核、结果含 Skip、源码不匹配、环境不满足边界或 A 未绿时,明确阻塞验收与合入,不用旧 run3130、旧 Dev run3076 或口头结果补位。PR 保持 WIP,保留失败收据和现场以便重试。
|
||||
|
||||
本文件不授权创建/变更共享 runner、改主机 AppArmor、扩大 CI token 权限、改保护规则、发布、部署、删除来源引用、回收实际工作区或更改迁移的语言版本权威。独立 VM/主机的提供方式、成本、来源交付及身份校验须在本文件获批后的实施计划中写清并经用户评审;若方案需要上述更高权限操作,先停在设计阶段另行审议。
|
||||
|
||||
## 书面设计的验收线
|
||||
|
||||
1. 普通 Dev clone 的正式组合仍须证明本地 Bubblewrap 隔离;Dev CI 三个必需 job 仍须证明无 socket 子容器且候选命令不在父容器执行。RDM CI 的候选测试同样须证明无 socket、无凭据执行边界。
|
||||
2. A 的清单精确区分真实嵌套用例与可在外层运行的测试,并公开 `NOT_RUN_IN_A`;未知/新增测试不能默认排除。当前 `make test` 失败保持失败记录,直到非嵌套问题被修复并获新证据。
|
||||
3. B 在无凭据、无 socket 的独立环境中先证明原生 `bwrap` 真正启动,再在最终两个 Backend 来源及 RDM 来源上逐用例零 Skip 通过;新 SHA 必须重放。
|
||||
4. 阶段 7/8 和合入材料同时给出 A 与 B 的命令、对象 SHA、输出及来源等级;任一缺失即停止。
|
||||
|
||||
本文件是设计,不是实施计划;具体脚本入口、测试选择器、无凭据来源包和环境探针的实现步骤,待书面设计评审通过后另编计划。
|
||||
@@ -14,6 +14,7 @@
|
||||
正式验收、共享部署和发布保留原审批边界。
|
||||
[独立 Review 整改设计 r1](2026-10-14-versioned-dependency-review-remediation.md)记录三项 Stage 8 阻塞的本地/CI 沙箱、规范缓存重试与生成工作区安全回收边界;书面设计 `68c658a` 已获用户批准,旧候选不得据旧 CI 合入。
|
||||
[整改实施计划](2026-10-14-versioned-dependency-review-remediation-plan.md)细化每单元红绿回归、CI 沙箱、重新验收与合入停止条件;计划 `20ada84` 已获用户批准并由本会话逐项实施。Dev Task 1–4 本地候选已提交,Task 5 文档/来源锁对齐进行中;新 HEAD 的平台 CI、阶段 7 人工验收与 Stage 8 独立复审尚未完成。
|
||||
[嵌套沙箱双必需门禁修订设计 r1](2026-10-14-versioned-dependency-nested-sandbox-amendment.md)针对新候选 `make test` 的嵌套 `bwrap` 阻塞;**书面设计待用户评审,尚未批准实施**,独立重放环境及最终门禁均未就位。
|
||||
|
||||
- [IAM I1 权限边界与公开扩展合同 r1](2026-10-13-iam-i1-permission-contract.md):
|
||||
依据已批准的[用户、职位角色与分层权限统一方案 r1](2026-10-13-identity-role-permission-plan.md)
|
||||
|
||||
Reference in New Issue
Block a user