Files
codex-app-server/docs/chv-production-readiness.md
T
host 54f20dfe55 feat-chv-closeup:收尾(executor 覆盖到 100%、合并/灰度准备,堆叠于 #264)
- 后端新增 cloud/tests/test_chv_closeup.py 85 项:唤醒失败
  (vm.create/vm.boot/API 超时/guest 就绪超时/host key 不匹配/
  provisioned 缺钉死)、恢复与快照失败、取消与清理(残留
  socket/登记/磁盘/密钥、脏标记)、中途死亡分类、只读
  execute 归类、入口校验、preflight 事后改写、防御性
  except、worker_adapter 剩余分支;executor.py 覆盖 100%。
- 前端新增 src/api/chv.closeup.test.ts 13 项:显式 false、
  undefined、可用性优先级、Workers 旧 bug 文案不复发、
  120 秒边界;控制按钮与新页面仍不做。
- 新增 tools/chv_merge_precheck.py(只读):逐个核 base/head/
  mergeable/CI/链衔接,实测 11 个 PR 全 NOT-READY(CI 全
  FAIL、mergeState 全 UNSTABLE),退出码 1,绝不合并。
- docs/chv-production-readiness.md 新增 §14:审计落盘运维
  runbook(定位/轮转/读取/清理,ADR-14 取舍不变)、mypy
  默认口径 2 错评估(沙箱验证过的标注修法,本轨不改
  其它链文件)、灰度三阶段可执行清单、V-1~V-9 检查表
  (全部未验证)、逐项评分。
- 安全语义不变:egress、key seed 投递、磁盘删除、默认
  provisioned、tap 校验、前端不绕后端白名单均未放宽。
- 只到 PR OPEN,不合并、不部署;CI 账单仍是硬门禁。
2026-10-31 12:15:56 +00:00

788 lines
47 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 执行器生产就绪清单
> 状态图例:✅ 代码已完成 · 🧪 mock 测试已覆盖(无真 VM) ·
> ⏳ 需 KVM 宿主实测 · 🏗️ 需镜像构建 · 📈 需压测 · 🔒 需安全审计
>
> 本清单是 PR 的一部分,不是事后补的口号。凡是标 ⏳/🏗️/📈/🔒
> 的项,在本轨内一律不声称已验证、已建成、已通过。
## 0. 交付点卡在哪一关(必读,先于逐项清单)
- **CI 门禁(未过,交付点 = PR OPEN)**:CI 必须通过才能合并。
此前全仓 CI 因 GitHub 账单问题 0 步骤失败;若账单未恢复、
CI 仍失败,本 PR 只到 OPEN,不合并,更不为变绿改 CI 配置
或绕过检查。
- **真 VM 门禁(未过,执行器默认关闭)**:生产启用(把真实任务
路由到 cloud-hypervisor、部署到生产主机)必须先有带 /dev/kvm
的宿主并完成真实 VM 启动、快照恢复、任务端到端验证。
当前事实:生产主机 124.222.165.170 本身就是 CVM
(systemd-detect-virt=kvm,DMI product=CVM),/dev/kvm 不存在、
无 vmx/svm 标志、无 kvm 模块、未装 cloud-hypervisor,无嵌套
虚拟化透传;本 VM 容器内同样无 /dev/kvm。
故真 VM、快照恢复、压测在本轨内一律不声称已验证;执行器
默认关闭(server 默认仍是 docker,worker 默认仍是 local,
CHV 只在任务创建时显式选 `executor=cloud-hypervisor` 且有
CHV worker 认领时才跑),不进入生产任务路由。
- **还差什么才能真正上生产**(按顺序):① 用户侧开通带 /dev/kvm
的裸金属或开启嵌套虚拟化的实例;② 在该宿主上构建并发布
chv-guest 镜像(见 §4);③ 在该宿主上跑通真实 VM 启动、
快照恢复、任务端到端、预热池与压测;④ 安全审计通过(§6);
⑤ CI 账单恢复且本 PR CI 变绿后,按当时 main 头复核 diff 再合并、
再部署。缺任何一项,都不把 CHV 推上生产。
## 1. 单任务单 VM 隔离
- ✅🧪 一个任务一个 VM:dispatch/run/goal 均走 wake → 跑 → finally
shutdown,同一任务重复 wake 先关旧 VM;VM 名、api-socket、
每任务磁盘路径均按任务派生,互不相同(测试断言)。
- ✅🧪 每任务磁盘独立:copy 模式复制基础镜像为每任务磁盘;
reuse 模式仅单租户实验,preflight 拦截(须显式实验二次确认并审计放行,feat-chv-fix 起代码真正拦截;此前“代码与文档双写”的说法是错的,代码当时并不拦截)。
- ✅🧪 租户无共享路径:执行器不挂载宿主根、宿主代码目录或含
密钥目录;客机代码在镜像内 `/app`,不在宿主共享挂载上。
- ✅🧪 密钥不进镜像/代码/prompt:SSH argv 只有 key 文件路径;
模型 key 由客机 cloud-init 预置的环境变量名注入;测试断言
命令中不含哨兵密钥值。feat-chv-secfix 起网关密钥不再走
SSH env 前缀(旧路径值进 argv 已废除),改走 provisioned
seed 盘客内文件(/etc/chv/guest-env,0600),keyscan 模式
下密钥投递 fail-closed;审计 detail 里绝无密钥值。
- ✅🧪 SSH host key 按 VM 钉死(优化轨,#216 的 no + /dev/null
已废除):每 VM 在 state_dir/<vm>/known_hosts 有独立文件,
首次启动经 ssh-keyscan 在解析出的 SSH 目标上捕获 key 写入该文件,
此后 SSH 一律 StrictHostKeyChecking=yes + 该文件校验;
非 root 客机用户(CHV_SSH_USER,显式空串直接拒绝)与端口
(CHV_SSH_PORT,1-65535)为显式配置。mock 只验证捕获→
写文件→钉死选项的管线,不验证首次密钥真实性。
- ✅🧪 Host key 预置方案(补缺口轨,替代 TOFU 为生产路径):
宿主在启动前为每 VM 生成一次性 ed25519 host key 对,
公钥立即写进该 VM 的 known_hosts 钉死,私钥只进 per-VM
cloud-init seed(随 VM 关闭/回收而删),客机镜像硬性
要求见 chv-guest/README.md §5(cloud-init NoCloud、
首启先应用 seed 再起 sshd、不得无条件重生成 host key)。
ssh-keyscan 首次捕获只保留为弱回落(须显式设
CHV_HOST_KEY_MODE=keyscan),生产默认值已是 provisioned
(feat-chv-secfix,H4,此前默认值 keyscan 是反的);TOFU 首次
真实性仍待预置 key 方案在真机上验证,安全审计时须单独立项确认。
- 🔒 需安全审计:VM 逃逸面(virtio 设备、tap 桥接、SSH 配置)、
客机 root 提权面、租户间东西向隔离的宿主网络配置,须由
安全审计逐项确认,代码自查不能代替审计。
## 2. 快速启动:预热快照池 + 镜像缓存
- ✅🧪 快照/恢复接口:snapshot_vm / restore_vm(restore 后显式
resume,见 §3),WarmPool 接口与状态机(cold → prewarming →
warm → assigned → running → recycled/destroyed)。
- ⚠️ 定案(feat-chv-arch95,ADR-5):WarmPool 是实验性、非生产
路径。dispatch 永远冷启动,_run_with_vm 绝不查池;池空回落
冷启动的说法不再作为生产特性宣称,acquire/resume 只保留为
实验接口。
- ✅🧪 预热条目一次性:acquire 消耗、release 一律销毁,绝不跨
任务复用脏 VM。
- ✅🧪 预热池 registry 与孤儿清理(优化轨):池状态落
state_dir/warm-pool.json(原子写),worker 重启后载入的
条目一律当孤儿、只能 reconcile_orphans() 清理,绝不重新
发给任务;registry 损坏时 quarantine 成 .corrupt 并从空池
开始;registry 之外的残留 socket 仍由 cleanup_stale_vms()
扫描处理。
- ⏳ 需 KVM 宿主实测:预热池的真实冷启动耗时、resume 耗时、
池大小与命中率、快照来源一致性,均需真机数据,mock 数字
不能当性能结论。
- 📈 需压测:多 VM 并行预热/分配/销毁的宿主 CPU/内存/磁盘
压力、快照存储增长,均未测。
## 3. 完整生命周期
- ✅🧪 create / boot:API 模式 wake_vm(vmm.ping → vm.create →
vm.boot → SSH 就绪)。
- ✅🧪 pause-resume(sleep-wake):pause_vm / resume_vm(ch-remote)。
- ✅🧪 snapshot-restore:restore_vm(restore + 显式 resume +
SSH 就绪),恢复后默认 paused 的坑已在代码与测试里钉住。
- ✅🧪 hibernate:CHV 无原生 hibernate 端点,本轨用 pause +
snapshot + shutdown 等价实现,文档与代码双写“等价实现”,
不声称接了原生端点;唤醒走 restore_vm。
- ✅🧪 shutdown-destroy / recycle:shutdown_vm(ch-remote
shutdown + 杀进程 + 删 socket)、recycle_vm(保留
task_checkpoints/task_attempts,丢失 guest /tmp 与未拷出
的 worktree 临时物,绝不声称恢复临时文件)。
feat-chv-secfix 起 stop 即删任务 disk.raw(保留期 0,
需取证须在 shutdown 前经 SSH 拷出),残留盘由
gc_stale_disks 扫描清理,删失败记审计 + 脏标记。
- ✅🧪 execute 只读已运行 VM(优化轨):execute() 先查 VM
是否在运行(登记活进程或 api-socket 存在),未运行报
ChvFailure(kind=vm_not_running),不为一次 status 起 VM,
也不向不存在的端口发 SSH 再拿连接失败冒充任务状态。
- ✅🧪 长任务中途死亡判 interrupted(优化轨):客内命令抛
传输异常、或非 goal 结果已 failed 且登记 VMM 进程已死时,
_run_with_vm 改判 interrupted(断点可续跑)而非笼统
failed;VM 还活着时的异常/失败原样处理。中途心跳未做:
host.py 单次 SSH 长回合没有客内进度信号可采,另起一路
SSH 轮询只能证明 VM 活着、不能证明任务在进展,评估后
认为风险大于收益,宁可只做死亡分类。
- ⏳ 需 KVM 宿主实测:上述全部生命周期在真机上的状态转换、
快照恢复后 guest 状态一致性、休眠后文件/worktree 保留,
均未在真机验证。
## 4. 完整开发环境(客机镜像)
- ✅ 客机镜像内容清单:`chv-guest/README.md` 按
`cloud/docker/Dockerfile` 能力对齐(Python 3.12、git、
pandoc/poppler/latex、python-docx/openpyxl/pptx/PyMuPDF/
Pillow、codex 0.164.0-alpha.9 成套、Playwright + Chromium、
openssh-server、cloud-init)。
- ✅ 构建脚本实做(补缺口轨):`chv-guest/build.sh`(参数校验、
KVM 宿主检查、下载 Ubuntu 云镜像、qemu-img 转 raw、
virt-customize 装清单、拷入 /app 代码、virt-get-kernel、
BUILDINFO.json 生成与 tag 校验;--dry-run 只打印命令)。
- 🏗️ 需镜像构建:镜像本身未构建、未发布;BUILDINFO 版本核对、
浏览器版本钉死、中文 LaTeX 单独一版,均待构建时做。
- ⏳ 需 KVM 宿主实测:镜像在真 VM 里启动、codex/Playwright/
git/文档工具链逐项跑通,均未验证。
## 5. 资源与成本
- ✅🧪 每 VM 配额:CPU/内存进 VmConfig(CHV_CPU/CHV_MEM),
磁盘配额门(CHV_DISK_GB,默认 50 GB 总量预算、超限拒绝,
feat-chv-secfix 起默认开启,此前未设即不查),快照上限
(每 VM 数量默认 10、总量默认 20 GB、保留期默认 30 天,
超量最旧优先剪枝),宿主容量门
(CHV_MAX_VMS,超限明确拒绝排队,不降级;残留 socket
须真连通才计数,死 socket 不再占满容量)。
- ✅ 超时与最大轮次:SSH 单次超时(CHV_TASK_TIMEOUT)+
worker task_timeout 外层护栏;goal 最大轮次 100(与 Local
同款),执行器内部不重试(重试是 worker max_retries 语义)。
- ✅ 成本复用:不另起一套计费;worker 现有 quota/成本语义
(per-user USD 配额、quota 看门狗、成本写库)仍是唯一口径,
执行器只把 host.py 用量原样返回。
- ✅ 空闲休眠省成本:hibernate_vm(pause + snapshot +
shutdown)+ WarmPool 释放即销毁,空闲 VM 不占 vCPU/内存
(快照只占磁盘,见 §2 压测项)。
- ✅ autoscaler:按 executor 过滤队列深度(已有)+ 本轨透传
`--executor` 给拉起的 worker(否则 CHV 池永远饿死)。
- 📈 需压测:配额下的真实资源占用、超限拒绝的排队行为、
成本与配额在长任务下的实际表现,均未测。
## 6. 网络与治理
- ✅🧪 受控 egress:默认 fail-closed(CHV_EGRESS_PROXY 未设且
未显式允许直连时 preflight 直接失败);客机命令加 env
代理前缀,出口只走白名单代理(Tinyproxy 思路复用)。
feat-chv-secfix 措辞纠正:env 前缀只是代码门,不是网络层
隔离——客内 root 可 unset/裸 socket 绕过;真正的隔离是
“代码门 + 宿主防火墙缺一不可”(见 §11 部署清单),
代码不再把 fail-closed 写成已隔离。
- ⏳🔒 需宿主网络配置 + 安全审计:tap 桥接是否真的只路由到
白名单代理、VM 能否绕过代理直连外网,是宿主网络配置问题,
执行器代码不能自证,必须在 KVM 宿主上实测并审计。
代码已做:每 VM 独立 tap/mac/ip 校验(共享即拒绝并审计)、
net 条目字段白名单、egress 代理地址校验。
- ✅ 审批门:任务 approval 经 `_approval_cli_args` 进客内 host.py
顶层参数,VM 内 agent 不能自改;delete/deploy/spend 类动作
仍走 server 的 approval/merge_gate,不由 VM 内 agent 自批
(本轨不改 approval/merge_gate 语义,只复用)。
- ✅ 工具与系统调用范围收敛:VM 边界本身就是系统调用边界
(客机独立内核);plan 任务走 read-only 沙箱参数;最大步数
(goal 100 轮)、时间(task_timeout)、重试(worker 1 次)
超限即停并审计(vm_failed 带 kind)。
## 7. 可观测与审计
- ✅🧪 VM 事件审计:create/boot/ready/pause/resume/snapshot/
restore/shutdown/destroy/failed/recycled/warm_pool_acquire/
release 均经 audit_callback 发出;worker 接线后转 AuthStore
审计(_audit 本身 best-effort)。feat-chv-secfix 起补齐:
host_key_generated/host_key_captured/host_key_mismatch、
preflight_failed、wake 前置失败(容量/配额/net 冲突)、
vm_disk_deleted/vm_disk_delete_failed/vm_disk_gc、
host_secret_residue_cleaned、net_config_dual、快照剪枝;
审计回调失败记宿主 error 日志,不再双重静默。
- ✅🧪 失败分类:ChvFailure 带 kind(kvm_missing/binary_missing/
kernel_missing/image_missing/ssh_key_missing/cpu_flag_missing/
egress_not_configured/api_timeout/guest_not_ready/vm_create_failed/
vm_boot_failed/host_capacity_exceeded/disk_quota_exceeded),
不笼统 failed。
- ✅ 断点对齐(补缺口轨已接线):VM 快照/休眠与现有
task_checkpoints/task_attempts 语义对齐(recycle 保留两者,
丢失临时文件);worker 通用分支对任何提供
goal_resume_breakpoint_task 的执行器调用它(Local 仍走
原路径,网关任务仍被 loud fail 守卫拦住);WarmPool
reconcile_orphans 已由 worker 启动与关闭时显式调用,
失败不炸主流程但进审计;VM 中途死亡改判 interrupted
后走同一断点路径,不再落 failed 死信(见 §3 与新增测试)。
- ⏳ 需 KVM 宿主实测:审计事件在真机任务 timeline 里的完整
呈现、失败分类与真实故障的对应关系,均未验证。
## 8. 多 VM 并发与容量
- ✅🧪 worker 注册:`_executor_name()` 返回 cloud-hypervisor,
worker register/heartbeat 已上报 executor + capacity(现有
机制复用,无需新表)。
- ✅🧪 多 VM 并行:`_vms` 登记 + 锁保护,wake 按任务名登记,
不同任务互不覆盖;容量门在 wake 前检查。
- ✅🧪 残留 VM 清理:cleanup_stale_vms 处理已死/已关/socket
残留三种情况,只清 chv- 前缀 socket;feat-chv-secfix 起
清理前先跑残留盘 GC 与残留密钥扫描(不依赖 socket 是否
存在,覆盖 worker 崩溃后 socket 已删、文件仍在的情形)。
- ✅🧪 容量不足明确拒绝:kind=host_capacity_exceeded,调用方
排队/拒绝,绝不降级 Docker/Local(测试断言 launcher 未调用)。
- 📈 需压测:多 VM 并行下的宿主容量、VM 启动并发上限、残留
清理在高压下的表现,均未测。
## 9. 默认关闭与生产启用条件(重申)
- ✅ 默认关闭:server 默认执行器仍是 docker,worker 默认 local;
CHV 只在显式选 executor 且有 CHV worker 时才跑;无 CHV_*
配置时 preflight 直接失败。
- ⏳ 生产启用前置(全部未完成):带 /dev/kvm 的宿主开通 →
chv-guest 镜像构建发布 → 真实 VM 启动/快照恢复/任务端到端
验证 → 压测 → 安全审计 → CI 变绿后按当时 main 头复核 diff
再合并部署。缺一不可。
## 10. 审核修复轨 feat-chv-fix(堆叠于 #230 之上)
- ✅🧪 P0 已修:seed 磁盘(CIDATA ISO,第二块只读盘)挂进
VmConfig;restore 不回落 keyscan(provisioned 下复用已钉
死 known_hosts、缺失 fail-fast,快照内 host key 不重预置);
reuse 由 preflight 拦截(显式实验二次确认 + 审计放行);
SSH 目标选客机 IP 方案(显式 host > net 静态 ip > 显式
转发宣称下的回环,三者皆无 fail-fast;vsock 与纯 NAT 方案
未选,理由见 config.py)。
- ✅🧪 P1 已修或有结论:网关 extra_env 经 SSH env 前缀注入,
worker 守卫收窄到 Local/CHV;取消/清理/看门狗接 CHV 通用
路径;WarmPool acquire 内 resume(本轨定案为实验性,见 ADR-5,
不再是生产特性);容量门改持久化
计数(socket 联合计数);磁盘配额改总量+余量、已存在磁盘
校验重拷;API 客户端按 Content-Length 验完整性;快照
file:// 目标验存在且非空再 shutdown;execute 死端口归类
vm_not_running。
- ⚠️ 仍未验证(不得声称已交付):CHV + 网关真实任务;真机 wake/boot/SSH(含 seed
注入与 NAT/客机 IP 实测);快照恢复端到端;压测;安全审计;
CI 账单恢复。另:P0-2 审计原说法“restore 须把 seed 接入
VmConfig”已纠正——restore 不走 vm.create,seed 无从挂盘,
正确不变量是复用钉死 known_hosts。
- ✅🧪 P2 已做(范围已恢复为全做,上一条收窄令作废):
test_chv_gaps.py 的 grep 文本断言改成真实 Worker._run_attempt
行为断言;stop_vm 删除失败记 vm_key_cleanup_failed 审计
(同名复用旧 key 的彻底根治在本轨之前列为遗留——
feat-chv-secfix 起已根治:清理失败写脏标记,同名 VM
拒绝启动,见 §11 M2);配置校验时机统一到 preflight(CPU/内存非法
进 preflight,kind=config_invalid);build.sh 与 README 口径
对齐(章节顺序 §5 host key → §6 对接、BUILDINFO contents
纠正为名字列表无逐项版本、Node.js 不装写实);第二启动路径
清理(build_vm_command 降级为私有 _build_vm_command,手动
等价写法保留;Docker goal 内联解析顶部加指向正典
parse_goal_result 的分叉说明 + 同步检查清单);长函数只做
小提取(preflight 的 reuse/CPU/内存校验块抽成
_preflight_config_checks,语义不变;config.py 字段解析与
其余长函数深耦合,本轨如实停、不硬拆)。
## 11. 安全审计修复轨 feat-chv-secfix(堆叠于 #239 之上)
> 审计报告:`~/workspace/chv-security-audit/REPORT.md`(只读静态
> 审计,verdict No-Go,Critical 0 / High 7 / Medium 8 / Low 5)。
> 本节逐项给结论:代码已做 = 本轨代码 + mock 测试已覆盖;
> 真机未验证 = 代码改了,但动态实效仍须 KVM 宿主验证,
> 绝不把静态通过写成动态已验。审计 verdict 本身仍是 No-Go,
> 直到 §11 末的真机清单全部通过——本轨只修代码层,不改 verdict。
### 11.1 High(全部代码已做、真机未验证)
- H1 egress 网络层强制:代码能做的全部做了——egress 代理
地址校验(http/https + 主机名)、直连仍须显式允许 + 审计、
每 VM 独立 tap/mac/ip 校验(共享即拒绝并审计)、net 条目
字段白名单。代码做不到的宿主防火墙规则见 §11.4 部署清单,
文档明写“代码门 + 宿主防火墙缺一不可”;env 前缀不再被
写成已隔离。
- H2 网关 key 移出 argv:密钥子集(SUB2API_API_KEY)在
provisioned 模式下随 seed 写进客内 /etc/chv/guest-env
(0600 root),远程命令 source 该文件;传输层对密钥名
进 argv 直接 ValueError(fail-closed)。比 argv 安全的理由:
值既不在宿主进程表(ps /proc cmdline)里,也不在宿主子
进程环境(/proc environ)里,只活在 seed.iso(0600,随
VM 销毁而删)与客机内——客内 agent 本来就有该 key,修
的是“宿主暴露面”,不是“客内可见性”。与 Docker 线的差异:
Docker 是“-e 只传名、值由 CLI 子进程环境提供”(值仍在
宿主进程环境里),CHV 是“值只进 seed 客内文件”(宿主
进程环境里也没有),比 Docker 线更严。keyscan 模式无
seed 可投递,有密钥即 fail-closed(secret_env_requires_
provisioned),不再将就跑。残留清理:seed 目录与 seed.iso
随 stop 而删,崩溃残留由 cleanup_stale_secrets 扫描。
- H3 任务盘删除:stop/recycle/cleanup 路径删 disk.raw
(保留期 0,需取证须在 shutdown 前经 SSH 拷出),删失败
记 vm_disk_delete_failed 审计 + 脏标记;gc_stale_disks
扫描非 live VM 的残留盘并审计。
- H4 默认值改 provisioned:CHV_HOST_KEY_MODE 默认
provisioned,keyscan 只作显式 opt-in;旧测试的
CHV_SSH_FORWARD=1 等实验室宣称已明确标注为实验室路径,
不再写成生产默认。
- H5 seed.iso 权限与私钥清理:seed.iso 生成即 0600;宿主
私钥在 seed 盘建好后即删(只留公钥 + known_hosts),删
失败 fail-fast(VM 尚未启动);私钥 chmod 失败不再静默;
启动/清理时 cleanup_stale_secrets 扫描残留私钥与 seed。
- H6 state_dir 出 /tmp:默认
~/.local/share/codex-app-server/chv-vms,preflight 建目录
并保证 0700(失败即 state_dir_insecure);api-socket 组/
其它可写即 fail-fast(socket_permissions_insecure;仅禁
写位,VMM 默认 0755 类权限不误杀——VMM 默认值代码控制
不了,真机权限仍须按清单核对)。
- H7 tap 隔离校验:NET_JSON 透传前校验 tap/mac/ip 跨 VM
不重复(wake 成功后登记 net.json,stop 时释放预约),
共用即拒绝并审计;东西向隔离的宿主防火墙部分见 §11.4,
不写进代码假装已防。
### 11.2 Medium(每项有修复或有理由的结论)
- M1 SSH 远程命令转义:远程 token 全部 shlex.quote 后仍以
列表返回(ssh 拼接后远程解析结果与本地 list 语义一致),
prompt 里的 ;/$()/引号不再改写执行语义。边界写清:客内
已是 root,本项防的是语义篡改与审计失真,不是客内提权。
- M2 清理失败同名复用旧 key:彻底根治,选“清理失败即拒起”
(脏标记 + provision/wake 双重拒绝),不再写“已审计即可”。
- M3 磁盘配额默认与快照上限:CHV_DISK_GB 默认 50 GB
(未设不再不查,0/负数拒绝);快照每 VM 数量默认 10、
总量默认 20 GB(超帽最旧优先剪枝)、保留期默认 30 天。
- M4 供应链版本钉死:已钉死——云镜像 SHA256 必填(干跑验
“已设”、全量验哈希)、Ubuntu 版本与 codex 版本均为必填
环境变量;BUILDINFO 新增 versions(构建时从客机读回的
dpkg + pip freeze 实际版本,可审计、可复现比对)。未钉死
的清单:apt/pip 事前精确版本 lockfile(须在构建宿主上
生成一次、再固化进脚本,本轨无构建宿主、未编造版本号);
Playwright Chromium 二进制版本同样只随 playwright pip
版本记录,未单独钉死。
- M5 审计补齐:host_key_generated/host_key_captured/
host_key_mismatch(stderr 含钉死拒绝标记时立即 fail-fast,
不轮询成普通超时)、preflight_failed、wake 前置失败
(容量/配额/net 冲突)均独立审计;审计回调失败记宿主
error 日志,不再双重静默。worker 层 _audit 本身仍
best-effort(未改,见 §7 既定语义)。
- M6 reuse 实验标志单租户校验:代码能校验的已校验——
实验放行须同时声明 CHV_SINGLE_TENANT_PROJECT,否则
preflight 拒绝(reuse_tenant_undeclared);不能校验的
部分明写:代码无法验证数据库里是否真的只有一个租户,
声明 + 审计就是本项的机制,不假装已校验。
- M7 容量计数残留 socket 误伤:只有真能连通的 socket 才
计数,空文件/死 socket 不计入 CHV_MAX_VMS;竞态窗口
写清(刚启动未 listen 的 VMM 会被判死,容量门是护栏
不是分布式锁)。
- M8 sshd 加固进构建:build.sh 写入
/etc/ssh/sshd_config.d/99-chv.conf(PasswordAuthentication no、
PermitRootLogin prohibit-password、ChallengeResponseAuthentication no、
KbdInteractiveAuthentication no、PubkeyAuthentication yes),
并经 sshd -t + grep 断言;README 声称与构建一致。
### 11.3 Low(顺手做)
- L1 磁盘拷贝符号链接:目标是链接时先删链接本身再拷贝,
不跟随写入目标文件(TOCTOU 窗口已在 disk.py 写清,
state_dir 0700 是前提)。
- L2 磁盘/快照路径白名单:task_disk/seed_disk 须在
state_dir 内(reuse 的基础镜像本身除外);file:// 快照
须在 state_dir 或 CHV_SNAPSHOT_DIR 内,远端协议须显式
CHV_ALLOW_REMOTE_SNAPSHOT=1。
- L3 失败审计:preflight/容量/配额/net 冲突失败均发
vm_failed 审计(见 M5)。
- L4 CHV_NET 与 CHV_NET_JSON 双变量:双设时发
net_config_dual 警告审计(不硬拒,CHV_NET 是手动直接
启动命令的透传值);NET_JSON 条目字段白名单
(tap/mac/ip/mask),未知字段直接拒绝。
- L5 WarmPool 预热盘与任务盘对应关系:定义已写进
pool.acquire 文档——预热盘是干净快照盘,不是任务盘;
本轨定案为实验性(ADR-5),不再作为接线待办。
### 11.4 宿主防火墙部署清单(代码做不到的部分,缺一不可)
- 每 VM 独立 tap + 独立 mac + 独立静态 ip(运维分配,
代码在 wake 时校验冲突,但分配本身是运维责任);
- tap 桥接默认 DROP,只放行到 egress 代理的流量
(iptables/nftables:默认 DROP + 仅代理地址/端口 ACCEPT,
不给 tap 直连外网的 NAT,不把 tap 桥接到宿主内网网段);
- 东西向隔离:VM 间默认禁通(每 VM 独立 tap + 桥接隔离,
或每 tap 独立网段 + 转发禁令),ARP spoof 场景下 SSH
钉死仍是第二道门,不是唯一门;
- 宿主进程隔离:worker 用户最小化、VMM api-socket 所在
state_dir 0700 且仅 worker 用户可访、宿主启用 hidepid
收紧 /proc 可见性、进程表采集不记录完整 cmdline;
- 部署后核对:state_dir 权限、socket 实际权限、
tap 规则实测(见 §11.5 否定测试)。
### 11.5 仍需真机验证的清单(本轨一律未做,不声称已验)
1. 否定测试:客内 unset 代理后 curl 外网必须不通;
VM A 扫 VM B / spoof B 的 ip 后 SSH 必须被钉死拒绝;
2. provisioned 首启时序:seed 先应用再起 sshd、不重生成
host key;sshd -T 实际输出与密码登录关闭;
3. 宿主 SSH argv 实测:真机 ps 下网关 key 不可见;
4. 长跑/崩溃注入:残留盘总量、快照增长、残留 socket 与
seed/私钥残留的实际表现、GC 覆盖;
5. 压测:配额与容量门在并发下的实际表现;
6. 渗透类:任何以“拿到宿主 shell / 读到别租户数据”为
目标的真实攻击尝试——本轨一律未做,静态通过不等于
已证明不可逃逸;
7. 审计 verdict:以上全部通过后,才能把 verdict 从 No-Go
改为“有条件启用(默认关闭 + 灰度单租户/受信项目)”,
不直接全量多租户。
### 11.6 本轨明确不做
- VM 控制按钮、预热池管理页、成本/配额新页面(前端零改动);
- 真机动态渗透、压测(无 KVM,做不了,只列清单);
- WarmPool dispatch 前查池接线(已定案不做,见 ADR-5;重启须先
实现任务盘重供给并补不变量测试)。
## 12. 架构 9.5+ 提升轨 feat-chv-arch95plus(堆叠于 #252 之上)
> 验证方式标注(本轨新增,逐条不混淆):静态 = 代码 + mock
> 测试已覆盖;真机 = 须 KVM 宿主验证;压测 = 须并发负载验证。
> 凡写“代码已做”而未标真机/压测的,一律只代表静态通过。
- 长函数:cloud/chv/ 全部函数 ≤50 行(静态,mock 测试覆盖
提取后的 stop/wait/restore/清理/接收/校验/组装段)。
- WarmPool 生产隔离:生产路径只调 reconcile facade(静态);
预热收益仍是实验性,真机收益未验证(真机)。
- #215 对齐:目录门与 tmpfs 口径已落代码(静态);超时与
美元配额无映射,#215 合并后替换为 import 仍须重跑测试
(合并后,静态)。
- 审计失败:记日志 + 计数 + 不中断(静态);审计完整性在
DB 故障下的实际表现仍须真机/故障注入验证(真机)。
- 供应链:BUILDINFO 事后 lockfile 校验脚本已落(静态);
事前 apt/pip 精确 lockfile 仍缺(须构建宿主,外部)。
- 只读 VM 字段:chv_vm_dead 派生自 worker 已写回的
interrupted_reason(静态,mock 测试覆盖);live VM 状态
仍无字段,VM 控制按钮仍不做(后端无控制端点 + 安全 No-Go)。
- 合并前 diff 复核清单(合并时逐项打勾,不在本轨内做):
server 白名单、worker 断点分支、sandbox re-export、
console.html 构建产物与 src 一致、#215 合并后的 import
替换点。
- 真机验证清单(沿用 §11.5,另加本轨项):VM 死亡横幅在
真任务中断后是否出现、审计失败计数在 DB 故障时是否
累加且任务不中断、快照白名单目录门在符号链接逃逸时
是否拒绝。
- 灰度启用清单(启用时逐项打勾):CI 变绿 → 按 #216→#252→
本 PR 顺序合并 → KVM 宿主 + 防火墙清单 → 镜像构建发布
→ §11.5 + 本节真机清单全过 → 默认关闭下单租户/受信项目
灰度 → 全量多租户(须另行决策,不在本轨内默认开启)。
## 13. to10 提升轨 feat-chv-to10(堆叠于 #257 之上)
本节是准备工作,不是启用结论:代码侧的 to10 项已做,
生产就绪与动态安全仍未到 10 分(见 §13.4 外部关卡)。
### 13.1 合并前 diff 复核清单(以当前 main 头预填)
- 当前 main 头(本轨核查时):`aebc6238a613066316ec18796b83ea8fc2d8835e`
(Merge PR #201)。链上 10 个 PR 在核查时全部
OPEN / MERGEABLE(#216 base main,#221→#257 依次堆叠,
本 PR base 为 feat-chv-arch-maint-fe)。合并时必须重新
核查:main 头若已前进,整条链须逐个 rebase 并重跑测试,
绝不直接合并旧基底。
- 逐项复核点(合并执行者逐项打勾,任一项不符即停):
1. server 任务创建白名单含 `cloud-hypervisor`,环境创建
白名单为 local/docker/cloud-hypervisor(不含 cloud),
两处白名单差异仍在前端文案里写清。
2. worker 断点分支:Local 原路径不变,CHV 经
`worker_adapter.call_goal_resume_breakpoint`(薄包装名
`_call_goal_resume_breakpoint` 仍在 worker.py,旧测试
导入点不变)。
3. sandbox re-export:`cloud/chv` 不再 export WarmPool
(#257 已移实验模块),`cloud/sandbox.py` 的 CHV
re-export 与 `cloud/chv/__init__.py` 一致。
4. 前端产物:`cloud/console.html` 与 `dist/index.html`
的 sha256 一致(本轨:`269820d1…f389`,353163 字节),
产物内含新文案(“无法判断 VM 状态”1 处、
“CHV worker 在线数未知”3 处);合并时重建后复核,
不直接沿用本轨哈希。
5. `package.json` 的 vitest 测试脚本与 lockfile 增量只含
vitest 新条目,无旧包版本变动。
6. 本轨新增文件:`cloud/chv/worker_adapter.py`、
`cloud/tests/test_chv_to10.py`、
`chv-guest/generate_lockfile.py`;本轨改动文件:
`cloud/worker.py`(薄包装 + 删多余 `inspect` import)、
`cloud/chv/executor.py`(审计落盘 + 两函数抽 helper)、
`cloud/chv/config.py`、`disk.py`、`hardening.py`、
`hostkeys.py`、`ssh_transport.py`、`experimental_pool.py`、
`compat215.py`(类型注解 + ruff 整理)、前端 6 文件。
7. CI:链上全部 PR 的 `verify` 仍是账单故障秒级失败模式
(本轨核查时 #257 等均为 UNSTABLE,非代码失败);
CI 变绿前不合并,绝不改 CI 配置绕过。
8. 旧链 #199→#205→#207 与 #209–#215 仍全部 OPEN:
合并前复核它们与本链的交集(server 白名单、worker
断点分支、sandbox re-export),有冲突先解决冲突方,
不静默覆盖。
### 13.2 真机验证清单(用例与验收标准细化)
以下用例全部待 KVM 宿主,验收标准是“通过才算”,不是
“跑过就算”;任一用例未跑即记为未验证,不写进已验。
- V-1 冷启动:CHV worker 在 KVM 宿主上起 VM → guest
SSH 就绪(钉死 known_hosts,provisioned 模式)→ 跑通
一个真实任务(host.py 在客机内执行)→ 任务完成且 VM
已销毁、任务盘已删。验收:任务状态 completed,宿主
state_dir 无该任务残留盘与 seed。
- V-2 seed 首启时序:provisioned 模式下客机 cloud-init
在 sshd 启动前应用 seed(host key 不再生、客内密钥文件
0600)。验收:`sshd -T` 显示 PasswordAuthentication no
等加固项,known_hosts 钉死校验通过,非 TOFU 回落。
- V-3 快照恢复:任务中途 hibernate(pause + snapshot +
shutdown)→ restore 后显式 resume → 断点续跑完成。
验收:恢复后 known_hosts 不变(不重预置),快照文件
落盘非空且经 `snapshot_not_persisted` 校验。
- V-4 网关真实任务:sub2api 网关任务在 CHV 上跑通,
密钥只走 seed 客内文件,宿主 `ps` / `/proc/*/cmdline`
里看不到密钥值。验收:任务完成 + 宿主进程表抽查无密钥。
- V-5 取消与配额真杀:同步 SSH 阻塞中取消任务、配额超限
时,看门狗调 `cancel_vm` 真关 VM。验收:VM 进程消失,
任务状态 interrupted 且原因写回正确。
- V-6 审计落盘:DB 审计回调失败时,`chv-audit-spill.jsonl`
里有该事件行、`audit_failure_count` +1、任务不中断。
验收:落盘行 event/task_id/detail 与丢失事件一致。
- V-7 动态安全负向:客机 root unset 代理后直连(应被
tap/防火墙挡住)、跨 VM 探活与 IP 冒用(SSH 钉死应拒)、
崩溃注入后残留扫描(私钥/seed/盘应被清理或脏标记拒起)。
验收:每一项都有“被挡住”的证据,不是有代码就过。
- V-8 负载:4 VM 并发(`CHV_MAX_VMS` 默认值)下容量门
计数含重启后残留 socket 扫描,死 socket 不占名额、活
VM 不被超发。验收:并发任务全部完成或明确排队拒绝,
无静默降级到 Docker/Local。
- V-9 供应链清单:`generate_lockfile.py` 在构建宿主上跑
出真实 lockfile,`--verify` 通过且 unresolved 为空;
再用 `check_lockfile.py` 对 BUILDINFO.versions 复核。
验收:lockfile 由构建宿主产出,不是本轨合成数据。
### 13.3 灰度启用清单
- 阶段 0(合并后、默认关闭):合并整条链,CHV 仍默认
关闭,不进生产任务路由;先跑 §13.2 的 V-1~V-9。
- 阶段 1(单租户可信项目):只对明确指定的单租户项目
开 CHV(`CHV_REUSE_SINGLE_TENANT_EXPERIMENT` 与
`CHV_SINGLE_TENANT_PROJECT` 的声明口径不变,复用
实验仍需同时声明,两者缺一即 preflight 拒绝)。
- 阶段 2(受限多租户):放开到受邀项目,监控 VM 残留盘、
审计落盘、容量门与快照配额三项指标一周无异常。
- 阶段 3(全量多租户):仅在阶段 2 指标干净 + 动态安全
审计结论由 No-Go 改为有条件启用后,才可讨论;绝不
从阶段 0 直跳全量。
### 13.4 外部关卡(本轨代码做不到,逐项列出)
1. CI 账单恢复变绿(硬门禁,合并前提)。
2. 链上 10 个 PR 按顺序合并 + 本 PR 合并(需先过 §13.1)。
3. 用户侧 provision KVM 宿主(裸金属或嵌套虚拟化实例,
须见 `/dev/kvm`;生产宿主与本 VM 均无 KVM,无法替代)。
4. 客机镜像真实构建与发布(`build.sh` 全量跑通 + V-9)。
5. §13.2 真机验证全部通过(含 V-7 动态安全负向)。
6. 负载测试(V-8)与安全审计结论更新(No-Go → 有条件启用)。
7. 前端 live 点击验证(用户侧 live browser 检查清单见
本 PR 描述;回环地址限制下浏览器任务无法代劳)。
## 14. 收尾轨 feat-chv-closeup(堆叠于 #264 之上)
本节是准备工作,不是启用结论。本轨只到 PR OPEN,不合并、
不部署;生产就绪与动态安全的外部关卡(§13.4)原样未动。
### 14.1 本轨量化结果(实测,非上一轨回执转述)
- 后端:232 项 → 317 项(新增 `cloud/tests/test_chv_closeup.py`
85 项),全过。命令(仓库根目录,cwd 须为根目录——
在 `cloud/` 下跑会撞 `cloud/queue.py` 遮蔽 stdlib queue,
mypy 同理):
`python3 -m unittest cloud.tests.test_chv_arch95
cloud.tests.test_chv_arch95plus cloud.tests.test_chv_arch_maint_fe
cloud.tests.test_chv_fix cloud.tests.test_chv_gaps
cloud.tests.test_chv_optimize cloud.tests.test_chv_secfix
cloud.tests.test_chv_to10 cloud.tests.test_cloud_hypervisor
cloud.tests.test_chv_closeup`
- 覆盖率(同命令 + `coverage run --source=cloud/chv`):
chv 总 87%(1925 行,缺 258)→ 96%(缺 80);
`executor.py` 85%(缺 157)→ 100%(缺 0);
`worker_adapter.py` 82%(缺 16)→ 100%(缺 0)。
本轨基线与上一轨回执的行数口径略有出入(上一轨称
1826 行/缺 242,本轨同命令实测 1925 行/缺 258),
本轨前后对比只用本轨同一命令,不混用上一轨数字。
- 剩余未覆 80 行(按模块,全部在 executor/worker_adapter
之外,本轨未声称覆盖):
`api_client.py` 11 行(socket 层 chunked/超时/异常分支,
需 socket 级故障注入);`compat215.py` 2 行(旧兼容回落);
`config.py` 5 行(非法 env 构造分支);`disk.py` 22 行
(快照登记/剪枝边角与配额异常分支);`experimental_pool.py`
16 行(实验池,非生产路径);`hardening.py` 11 行
(真实 socket 权限与 net 校验边角);`hostkeys.py` 13 行
(ssh-keygen/genisoimage 子进程失败分支)。以上均非死
代码的断言——未逐行证伪,留待后续轨按模块补,不在本
轨凑数。
- mypy:silent 口径 `cloud/chv/` 0 错(不变);
默认口径 `cloud/marker_tools.py` 仍 2 错(见 §14.3,
本轨未改该文件)。
- ruff:`--select F,E9,W,I` 口径 `cloud/chv/` +
本轨新测试 0 错(不变;默认全规则基线不声称通过)。
- 前端:Vitest 23 项 → 36 项(新增
`src/api/chv.closeup.test.ts` 13 项),全过。
### 14.2 审计落盘文件运维 runbook(ADR-14 取舍不变,只补可操作性)
- 定位:`<state_dir>/chv-audit-spill.jsonl` 与轮转文件
`<state_dir>/chv-audit-spill.jsonl.old`。`state_dir`
默认 `~/.local/share/codex-app-server/chv-vms`,
可由 `CHV_STATE_DIR` 改址;以部署的实际值为准,
不要猜。目录本身 0700(见 §13.1 的 H6 门)。
- 触发:只有 `_emit` 的审计回调抛错时才写一行;回调
成功、无回调(只记日志)时不写。触发时宿主日志必有
`chv_audit_failed`,且 `audit_failure_count` +1——
落盘行是“哪次事件丢了”的唯一取证,计数只是数字。
- 格式:JSONL,每行 `{ts, event, kind, detail, task_id}`。
`detail` 沿用 `_emit` 契约,只含 VM 名/路径/URL/kind,
绝不含密钥值;读文件时仍按敏感文件对待(0700 目录内)。
- 轮转:当前文件 >1MB 时,先 `os.replace` 成 `.old`
再写新行;只留最新两代,更早的丢失事件会丢——
这是 ADR-14 已定的取舍,不是 bug,不要指望它当
完整审计账本。
- 读取(宿主侧,只读):
`cat <state_dir>/chv-audit-spill.jsonl`;
按事件过滤:`jq -c 'select(.event=="vm_failed")'
<state_dir>/chv-audit-spill.jsonl`;
两代一起看时先 `.old` 后当前文件(时间顺序)。
- 清理:`.old` 可随时删(删的是已被轮转覆盖的旧代);
当前 `.jsonl` 只有在已人工核对、且确认丢失事件已
无需追查时才删——删了就再也找不回那批事件。
落盘文件不是 DB 替代:任务 timeline 查询看不到它,
不要把它当成审计表去对账;审计完整性本身仍无保证
(见 ADR-14),保证需要 DB 事务级审计写入,那是
worker 全局语义改动,不在本轨。
- 落盘写失败:只记 `chv_audit_spill_failed` 日志,
绝不中断任务;此时连落盘都没有,唯一信号就是这条
日志与计数。
### 14.3 mypy 默认口径剩余 2 错评估(结论:本轨不修)
- 位置:`cloud/marker_tools.py:142`,`try: from zoneinfo
import ZoneInfo / except Exception: ZoneInfo = None`。
mypy 把 import 推断为 `type[ZoneInfo]`,再把 `None`
赋值判为两错(misc + assignment)。
- 仅标注修法(沙箱验证过,未进仓库):在 import 区后加
`from typing import Any` 与 `ZoneInfo: Any`(标注语句
本身不产生绑定),默认口径 2 错 → 0 错;运行时
`ZoneInfo` 仍是 stdlib `zoneinfo.ZoneInfo` 同一对象,
行为不变。验证在 `/tmp` 副本上做,不碰仓库文件。
- 不修的理由(两条,任一条已足够):① 该文件属标记
工具链(git 历史为标记工具提交),不在本链 §13.1
文件清单内,本轨改它就是动其它链的文件,徒增与
仍 OPEN 的审计/标记 PR 的 rebase 冲突面;② CHV 链
自己的门是 silent 口径(`--follow-imports=silent
cloud/chv/`),该口径已 0 错,默认口径的 2 错是
作用域外既有问题。修法留给 marker_tools 的归属轨,
本轨只把配方写在这里,不为清零越界改文件。
### 14.4 合并前检查脚本(只读)
- 脚本:`tools/chv_merge_precheck.py`,用法见文件头。
只读:`gh pr view` / `gh api` 查询 + 本地 `git` 读
remote,不 fetch、不 checkout、不 merge、不改 CI。
退出码:0 就绪、1 未就绪、2 查询失败(结论不可信)。
- 本轨实测(未含本轨新 PR,建好后须追加新 PR 号重跑):
`python3 tools/chv_merge_precheck.py` → 退出码 1,
结论 NOT-READY:11 个 PR 全部 OPEN / MERGEABLE,
链衔接全部 OK,当前 main 头仍 `aebc6238`(与 §13.1
一致),但 11 个 PR 的 CI 全部 `FAIL [verify:FAILURE]`、
mergeState 全部 UNSTABLE。脚本不诊断失败原因,
不把秒级失败改判——账单恢复变绿前结论保持 NOT-READY。
### 14.5 灰度三阶段可执行清单(准备工作,未执行、未验证)
通用停止条件(任一触发即停在该阶段,不进下一阶段):
`vm_failed` 审计激增、脏标记(`dirty_marker`)出现、
`chv-audit-spill.jsonl` 持续增长、残留盘/残留密钥扫描
清出本阶段不应有的项、任一任务静默降级到 Docker/Local。
通用回滚:停止向 CHV 路由新任务(改回 docker/local
执行器选择),已起 VM 走取消/关闭路径(`cancel_vm` /
`shutdown_vm`);代码回滚另议(revert 合并),不与
“停路由”混为一谈。
- 阶段 0(合并后、默认关闭):
1. 按 §14.4 脚本逐项核对,退出码 0 前不合并;合并
顺序即 §14.4 的链序,不得跳号。
2. 合并后确认 CHV 仍默认关闭(无生产任务路由到
`cloud-hypervisor`,任务创建白名单外的执行器值
仍被后端拒绝)。
3. 在 KVM 宿主(须见 `/dev/kvm`,本 VM 与生产宿主
均无 KVM,不能替代)上跑 §14.6 的 V-1~V-9,
全部通过才可谈阶段 1;任一未跑即记未验证。
回滚点:合并本身可 revert;未进生产路由前无任务影响。
- 阶段 1(单租户可信项目):
1. 只对明确指定的单租户项目派发 CHV 任务;复用
实验仍需 `CHV_REUSE_SINGLE_TENANT_EXPERIMENT` 与
`CHV_SINGLE_TENANT_PROJECT` 同时声明,缺一即
preflight 拒绝(代码行为,不放宽)。
2. 检查点:每任务 VM 销毁后 `state_dir` 无该任务
残留盘与 seed;`chv-audit-spill.jsonl` 无新增;
取消路径真关 VM(V-5 口径)。
3. 停止条件见通用条件;回滚:该项目任务改回原
执行器,CHV worker 停接新任务。
- 阶段 2(受限多租户):
1. 放开到受邀项目,连续观察一周:VM 残留盘、
审计落盘、容量门(`CHV_MAX_VMS`,含重启后残留
socket 扫描)、快照配额四项指标。
2. 检查点:每周复核四项指标零异常 + §14.2 落盘
文件复核;任一指标异常即退回阶段 1。
3. 停止条件见通用条件;回滚:收紧到阶段 1 项目集。
- 阶段 3(全量多租户):仅在阶段 2 指标干净 +
动态安全审计结论由 No-Go 改为有条件启用后,才可
讨论;绝不从阶段 0 直跳全量。本轨不给阶段 3 的
时间表,不写成已就绪。
### 14.6 真机验证用例 V-1~V-9 验收检查表(全部未验证)
每行格式:用例 — 验收标准(§13.2 细化)— 证据栏(待填)。
状态栏一律“未验证”,跑过才改,跑过≠通过。
- [ ] V-1 冷启动 — 任务 completed,宿主 state_dir 无该
任务残留盘与 seed。证据:______ 状态:未验证
- [ ] V-2 seed 首启时序 — `sshd -T` 显示
PasswordAuthentication no 等加固项,known_hosts 钉死
校验通过,非 TOFU 回落。证据:______ 状态:未验证
- [ ] V-3 快照恢复 — 恢复后 known_hosts 不变,快照文件
落盘非空且经 `snapshot_not_persisted` 校验。证据:______
状态:未验证
- [ ] V-4 网关真实任务 — 任务完成 + 宿主进程表抽查无密钥
(密钥只走 seed 客内文件)。证据:______ 状态:未验证
- [ ] V-5 取消与配额真杀 — VM 进程消失,任务 interrupted
且原因写回正确。证据:______ 状态:未验证
- [ ] V-6 审计落盘 — 落盘行 event/task_id/detail 与丢失
事件一致,`audit_failure_count` +1,任务不中断。
证据:______ 状态:未验证
- [ ] V-7 动态安全负向 — 直连被 tap/防火墙挡、跨 VM 探活
与 IP 冒用被 SSH 钉死拒、崩溃注入后残留被清理或脏
标记拒起,每项都有“被挡住”的证据。证据:______
状态:未验证
- [ ] V-8 负载 — 4 VM 并发下容量门计数含重启后残留
socket 扫描,死 socket 不占名额、活 VM 不被超发,
无静默降级。证据:______ 状态:未验证
- [ ] V-9 供应链清单 — 构建宿主产出真实 lockfile,
`--verify` 通过且 unresolved 为空,再用
`check_lockfile.py` 对 BUILDINFO.versions 复核。
证据:______ 状态:未验证
### 14.7 本轨逐项评分(目标 10,无一项硬写 10)
- 代码质量 9.8 → 9.8,未达 10:executor/worker_adapter
覆盖到 100%,但 chv 仍有 80 行未覆(非 executor
模块),且默认口径 mypy 余 2 错在作用域外。差:代码内。
- 架构 9.7 → 9.7,未达 10:本轨未改架构,ADR-13/14
取舍不变。差:外部(生产验证后才可复评)。
- 可维护性 9.7 → 9.8,未达 10:新增合并检查脚本与
§14 运维/灰度文档,落盘可操作性补齐;但跨链文件
的 mypy 归属未落。差:代码内(小)。
- 文档 9.8 → 9.9,未达 10:§14 补齐 runbook、灰度
清单、V 检查表、评分表;仍缺真机证据填表。差:外部。
- 测试 9.7 → 9.8,未达 10:后端 317 项、前端 36 项全过,
executor 100%;但 chv 总覆盖 96% 未满,且真机用例
0 项已跑。差:代码内(80 行)+ 外部(真机)。
- 静态安全 9.6 → 9.6,未达 10:取舍不变,只补落盘
运维;lockfile 仍待构建宿主产出,绝不编造。差:外部。
- 前端 9.5 → 9.6,未达 10:只读四态与可用性文案边角
全覆盖(显式 false、undefined、优先级、旧 bug 文案
不复发、120 秒边界);控制按钮与新页面仍不做,
live 点击未验。差:代码内(有意不做)+ 外部(live)。
- 生产就绪 5.0 → 5.5,未达 10:仅因合并/灰度准备
工作(可跑脚本 + 可执行清单)小幅上升;CI 仍
UNSTABLE、未合并、未部署、真机 0 项。差:外部为主。
- 动态安全 2.0 → 2.0,未达 10:本轨无任何动态验证,
V-7 未跑。差:外部(KVM 宿主 + 审计结论)。