堆叠于 #246(feat-chv-secfix),只到 PR OPEN,未合并、未部署。 安全语义不变:egress、key seed 投递、磁盘删除、默认 provisioned、 tap 校验一律保留;前端零改动。 - WarmPool 定案为实验性(ADR-5):dispatch 永远冷启动, wired_to_dispatch 恒 False,acquire/resume 只保留实验接口, worker 仍调 reconcile_orphans 清理残留。 - 长函数提取:preflight 126→31、wake_vm 135→36、__init__ 69→31、 build_chv_config 159→58;错误文案逐字不变。 - 严格测试替身:fake API 校验 VmConfig(任务盘+seed 盘、net 无重复),fake SSH 校验 known_hosts 钉死;新增 5 项测试。 - Docker 同步守卫:8 个真实标记用例下 Docker 内联版与正典 parse_goal_result 状态全等,改分叉即 fail。 - 配置统一校验:preflight 以 config_invalid 统一兜底端口/配额/ 超时/快照/host-key 模式(构造时已校验正常值,preflight 兜底 事后改写);CHV_NET 与 CHV_NET_JSON 双设仍警告不硬拒。 - 类型与 lint:chv 叶子模块公开 API 补类型注解;stdlib 扫描 揪出 executor 内 1 个真死 import(host_key_paths)并删除。 - ADR:docs/chv-architecture.md(ADR-1 至 ADR-7)。 测试:CHV 163 项全过;cloud 全量 1593 项三跑结果为 8 errors (首跑详细日志因 tail 截断丢失)、全过、1 失败(浏览器代理 时序测试,与 CHV 无关),全量本身存在时序偶发,CHV 套件 确定性全过。
4.6 KiB
4.6 KiB
Cloud Hypervisor 执行器架构决策记录(ADR)
范围:cloud/chv/ 执行器链(#216 → #221 → #230 → #232 → #234 → #239 → #246 → 本轨)。 本文件只记录已落代码的决策,不记录未验证为已验证;真机、压测、动态安全 仍见 docs/chv-production-readiness.md §11。
ADR-1 SSH 目标:客机 IP 发现(已选) vs vsock / 纯 NAT(未选)
- 决策:显式 CHV_SSH_HOST > CHV_NET_JSON 首个带 ip 的 net 条目 > 显式 CHV_SSH_FORWARD=1 宣称下的回环;三者皆无报 ssh_target_undeclared,绝不无条件假设 127.0.0.1:2222 能通。
- 未选 vsock:需客内 agent + 宿主代理两套新代码,当前客机镜像 无此组件,写进代码仍是假保证。
- 未选纯 NAT:DNAT 是宿主防火墙外部状态,执行器代码既不能 创建也不能校验它,写进代码仍是假保证;宿主防火墙见就绪 清单 §11.4 部署清单,代码门 + 防火墙缺一不可。
ADR-2 网关 key 走 seed 投递(已选) vs argv / 宿主环境(已弃)
- 决策:provisioned 模式下密钥子集随 seed 写进客内 /etc/chv/guest-env(0600),远程命令 source 它;传输层密钥 进 argv 直接 ValueError;keyscan 模式有密钥即 fail-closed。
- 放弃 argv:宿主 ps / /proc//cmdline 可读;放弃宿主子进程 环境:Docker 线 -e 只传名、值仍在 CLI 子进程环境,CHV 比它 更严(值连宿主子进程环境都不进)。
- 残留:seed 随 stop 删,私钥在 seed 盘建好后即删, cleanup_stale_secrets 扫崩溃残留;删失败 fail-fast 或脏标记拒起。
ADR-3 磁盘 copy 默认,reuse 只作单租户实验(已选)
- 决策:CHV_DISK_MODE 默认 copy,每任务独立 disk.raw; reuse 须同时满足 CHV_REUSE_SINGLE_TENANT_EXPERIMENT=1 与 CHV_SINGLE_TENANT_PROJECT 声明,且 wake 时审计放行。
- 边界:代码无法验证数据库多租户状态,声明 + 审计即机制, 不假装已校验;生产多租户下 reuse 一律不启用。
ADR-4 restore 不重预置(纠正,见 #232 审计)
- 纠正:审计原说法“restore 须把 seed 接入 VmConfig”是错的—— restore 不走 vm.create,无 VmConfig 可挂盘;快照内已固化原 VM host key,重预置反而破坏钉死。
- 正确不变量:provisioned 下复用已钉死 known_hosts、缺失 fail-fast(host_key_not_pinned),绝不 keyscan 回落。
ADR-5 WarmPool:实验性,生产 dispatch 永远冷启动(本轨定案)
- 决策(二选一的 B 项):把 WarmPool 从生产路径宣称里摘掉, 明确标为实验/停用,不再留“半接线”悬空状态。
- 原因:预热 VM 的磁盘是干净快照盘,不是任务盘;dispatch 前 查池若要真正接线,必须在派任务前给已暂停 VM 重新供给任务 盘(热换盘 / 二盘挂载 / host.py 磁盘语义三者都未实现), 把预热盘直接当任务盘用会击穿任务盘隔离不变量。
- 落地:WarmPool.wired_to_dispatch 恒为 False;_run_with_vm 绝不查池,dispatch 永远冷启动;acquire 内 resume 只保留为 实验接口;worker 启动/关闭仍调 reconcile_orphans()(上一世 残留清理是池子保留的唯一生产价值)。
- 重启条件:将来要重新接线,必须先实现任务盘重供给并补 “任务盘来源”不变量测试,否则不得把 wired 改成 True。
ADR-6 Docker goal 解析分叉:共享正典 + 同步守卫(本轨定案)
- 决策:Local/CHV 共用 parse_goal_result 正典;Docker goal_task 内联版保留,但与正典的 8 个真实标记用例(met/unmet/ interrupted 标记/无结论异常退出/永久错误/无结论 rc0/ goal-resume 拒绝/已存在撞名)由 test_chv_arch95.py 的 DockerSyncGuardTest 行为测试钉住状态全等,任一实现改了 分叉测试即 fail,不再只靠文档清单。
- 注意:Docker 的超时证据路径仍与内联解析绑在一起,那是 有意保留的第二处差异,不在 8 用例的状态等价范围内。
ADR-7 #215 未合并时的复用边界(不复制模块)
- 现状:#215(timeouts/gates/quota/sandbox_policy)未合并, 本链 base 里无其模块,本轨不复制其代码。
- 接口对齐点(#215 合并后机械替换,非重写):超时类 api/ready/task 解析 → timeouts;门禁类 preflight/容量/ 磁盘配额/egress fail-closed → gates;配额类 max_vms/disk_gb (任务成本仍走 worker quota)→ quota;隔离类单任务单 VM/ 磁盘 copy/egress 代理/SSH 钉死/池一次性与孤儿清理 → sandbox_policy。替换时须重跑本链 163 项测试,不得改语义。