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 账单仍是硬门禁。
This commit is contained in:
1 parent
2f3ff8b3ec
commit
54f20dfe55
4 files changed
+1759
No files matched your search
@@ -572,3 +572,216 @@
|
||||
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 宿主 + 审计结论)。
|
||||
Reference in new issue
Block a user