Files
codex-app-server/docs/chv-architecture.md
T
host c908a0147a feat(chv): 架构与代码质量提升——WarmPool 定案、长函数提取、严格测试替身、Docker 同步守卫、配置统一校验、类型注解与 ADR
堆叠于 #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 套件
确定性全过。
2026-10-31 05:50:56 +00:00

81 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/<pid>/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 项测试,不得改语义。