host
e31354dc58
fix(chv-muse-r12fix3-1): worker 开机时序竞态:Condition + path 触发,不赌重启预算(P6 缺口 ①)
...
R12 复测 2 钉死:剩下的 226 只点名 /home/chv/workspace——工作区由
cloud-final 的 chv-sync boot 克隆出来,晚于 multi-user.target 约
9 秒,worker 的 5 次启动预算在工作区出现前耗尽(5 台 VM 2 台
failed,手工 reset-failed + start 后立即 active,二进制无辜)。
修法三选一,选 (a)——让服务根本不在工作区出现前启动:
新单元 chv-gitea-worker.path(PathExists=/home/chv/workspace,
工作区一出现即触发启动)+ 服务加
ConditionPathExists=/home/chv/workspace(开机那次启动在命名空间
搭建之前干净跳过,不 226、不耗重启预算)。两者缺一不可:
Condition 本身绝不重试,没有 .path 它就是一次跳过、服务永远不
起;只有 .path 而无 Condition,开机那次启动仍会在命名空间搭建
时 226 撞上限速。WantedBy=multi-user.target 保留(is-enabled 仍
为 enabled),runcmd 只启动 .path 单元(cloud-final 时工作区尚
未 clone,直接 start 服务会 226);.path 进 buildinfo contents
与两处 lockfile 登记,P6 预检由三件扩为四件。
不用 (b) 放宽 StartLimit:放宽只是把竞态窗口拉大,wake 时间在
负载下已翻倍(R12 复测 2),预算仍可能耗尽,仍是时序赌博。
不用 (c) 把工作区创建提前到 tmpfiles-setup 之前:/home/chv 本身
07:23:40 才出现(cloud-init 建 chv 用户),晚于 tmpfiles-setup
(07:23:24);硬约束:绝不盲目补 tmpfiles 行。ExecStartPre 也不
行——命名空间搭建在它之前,救不了 226。
测试:WorkerUnitBootRaceTest 新增 8 项——Condition 在位、
StartLimit 未放宽(修法语义钉)、.path 触发配对(PathExists +
WantedBy、无 Unit= 覆盖)、服务 WantedBy 保留、build.sh 启用
.path + runcmd 只起 .path、绝无工作区 tmpfiles 行、buildinfo 与
lockfile 登记;BuildInfoContentsTest 的 P6 件加 .path;P2/P4 干
跑夹具一并拷入 .path。P6/P2/P4 三模块 174 项全过。
2026-11-08 09:45:48 +00:00
host
7c517f7fcc
fix(chv-muse-r12fix2-2): chv-sync 回落显性化:警告 + 每回落一行审计(P6-2)
...
R12 复测:worker 226 期间 chv-sync 全程静默走直接路径回落,pull/
push/status 表面 rc=0,privsep/safety 一行没跑——回落只有一句 stderr
警告,无事后可数的痕。本提交让一次回落留两处痕:stderr 警告保留
“worker 不在”标记(措辞加“未走 worker,privsep 未生效”,供驱动
识别)+ 追加一行 JSON 审计到
$USER_HOME/.chv-sync-fallback-audit.log(CHV_SYNC_FALLBACK_LOG 可改
位置;事件/动作/仓/时间戳,delegated_to_worker=false、
privsep_active=false)。审计写失败只记 stderr,绝不中断同步(与
worker _audit 同款口径)。gap 文档诚实边界第 4 条同步更新。
取舍:不改 fail-closed,仍是 fail-open。理由:旧镜像(无 worker)
须仍能同步,改 fail-closed 会把所有旧镜像的同步当场 brick,且无
镜像外恢复手段;本轮项 1 已让新镜像的 worker 开机即起,回落只在
worker 真挂 / 旧镜像时发生,不再是常态路径。旧镜像退役后改为无
worker 即 fail-closed(原定方向不变,见 chv-sync.sh 头注)。
测试:ChvSyncDelegationTest 新增——回落审计一行 JSON(字段全)、
两次回落两行、审计落盘失败不中断同步;走 worker 时不留回落审计
(反向对照)。
2026-11-08 06:01:54 +00:00
host
35d9c3ff3f
fix(chv-muse-r12fix2-1): tmpfiles.d 预建 worker 运行时路径(P6-1)
...
R12 复测钉死的根因:chv-gitea-worker.service 用 ProtectSystem=strict
+ ReadWritePaths=/home/chv/workspace /run/chv-gitea
/var/log/chv-gitea-worker.log,systemd 建 mount namespace 时要求每个
列出路径事先存在,否则 226/NAMESPACE crash-loop(NRestarts=12);
交付镜像里 /run/chv-gitea(/run 是 tmpfs)与
/var/log/chv-gitea-worker.log(worker 首次写审计才建)两处都不存在,
worker 从未起来过。
取舍:只用 tmpfiles.d(/etc/tmpfiles.d/chv.conf,加 d /run/chv-gitea
0700 与 f /var/log/chv-gitea-worker.log 0600,与 P4 的 /run/chv 同款
写法、同一文件)。ExecStartPre 不行——命名空间搭建在任何
ExecStartPre 之前,226 发生在它运行之前;改 ReadWritePaths 为已存在
目录(/var/log)会把写权限放大到整个目录。tmpfiles.d 由
systemd-tmpfiles-setup 在 sysinit 跑、早于 multi-user 的服务启动;
不新增进镜像的文件(chv.conf 本就是 build.sh 内联生成),lockfile
无需登记。unit 文件只加注释说明耦合,不改 ReadWritePaths 本身。
测试:WorkerUnitTmpfilesTest 钉住 ReadWritePaths 每一项挥发路径都有
对应的 tmpfiles 行(类型 + 模式)、P4 四行仍在、unit 无 ExecStartPre。
2026-11-08 06:00:58 +00:00
host
a18a530bfd
fix(chv-muse-r12fix-5): UsageLedger.record() 读-改-写原子化(P11)
...
R12 真机:4 线程 × 10 条记账 0 写错,但 verify_chain 返回
(False, first_bad=11),链 G、链 H 两次复现同一断点;根因是
record() 先 SELECT 链头、再算摘要、再 INSERT 提交,无锁无
事务,两线程读到同一 prev_hash 各写一条,链分叉。修法:
同一实例用 threading.Lock 串行化;SELECT 前 BEGIN IMMEDIATE
持库级写锁(WAL + busy_timeout 下等待而非立即失败),使另一
实例/进程读到的链头必是已提交最新值。record_warning 委托
record(),同款覆盖。新增并发测试:同款 4×10 复测两轮,
verify_chain 全真、40 条一条不丢(旧代码下该测试失败)。
2026-11-08 04:32:35 +00:00
host
0ebcdfb2a7
fix(chv-muse-r12fix-4): detect_checkout 接进 CDP broker(P10)
...
R12 真机:detect_checkout 在 chv-guest/、host.py、
executor.py 里零引用,结账页无任何拦截。按 P10 gap §4.1
接线:broker 加载 cloud/chv/checkout_detect.py(同目录
优先,仓库路径兜底;缺失时降级关闭检测、写警告,绝不
crash-loop);snapshot() 每次重算 verdict(aria 行拼伪节点,
与 _form_risk 同形),open() 导航前后两道门——落点是结账
页时返回 form_submit ask 并暂停,上一页是结账页时下一次
导航先审批;ask 批过后同 URL 不再重复 ask(批准即放行,
与 form_risk 同口径);verdict 进 snapshot()/status() 回包。
build.sh:checkout_detect.py 条件拷入 /usr/local/bin/(0644,
P3/P6 同款只警告口径,M4 不硬要求 cloud/),
extra_contents 与两处 lockfile 登记补齐。钱包三腿不在本轮
范围,未动。
2026-11-08 04:31:36 +00:00
host
1da0d86159
fix(chv-muse-r12fix-3): pull_memory_home 打包不再含顶层目录名(P7)
...
R12 真机:pull_memory_home 用 tar -czf - -C <父目录> <家目录名>
打包,解到镜像后文件落在 mirror/memory/MEMORY.md,而
MemoryFiles(mirror) 读的是 mirror/MEMORY.md——拉取与读取差
一层,host_pull_files=1 却报 memory file missing: MEMORY.md,
state-DB 备份与 host forget 同因失败。改为 -C <家目录> . 只打
包内容,MEMORY.md 直接落在镜像根;两处钉住的测试同步改形状
(旧测试本身钉的就是多一层的错误形状)。
2026-11-08 04:26:13 +00:00
host
33ca6c75ed
fix(chv-muse-r12fix-2): P6 worker 接进镜像(build.sh + BUILDINFO + lockfile)
...
R12 真机:chv-gitea-worker / chv-sync-worker-client /
privsep.py / safety.py / chv-gitea-worker.service 5 文件全不在
镜像内,build.sh 从未有 P6 拷入行,全链路无法跑。按 gap 文档
§2 接入说明落地:worker 三件硬校验 + 拷入 /usr/local/bin/
与 /etc/systemd/system/(mv 去后缀 + chmod +x + systemctl
enable);privsep/safety 叶子模块条件拷入
/usr/local/lib/chv-gitea/(与 P3 同款口径,缺失只警告);
叶子树 __init__ 用 stub(绝不拷真实 cloud/chv/__init__.py,
round-11 层 1 教训),stub 需 errors.py 故一并拷入;runcmd
在 chv-sync boot 前加 systemctl start chv-gitea-worker。
BUILDINFO contents 列入 worker 三件(无条件)与 privsep/
safety(条件,extra_contents);两处 lockfile 登记补齐 P6
五项,另补 P4 三件自 P4 起缺失的登记。
2026-11-08 04:25:33 +00:00
host
b923d0291b
fix(chv-muse-r12fix-1): /run/chv 改为组 chv-browser 可写(P4 broker 权限)
...
R12 真机:/run/chv root 所有 0755,chv-browser 建不了
cdp-broker.sock,chv-cdp-broker bind 报 PermissionError 而
crash-loop,P4 在交付镜像上永远起不来。改为 2775 root
chv-browser(setgid,沿用真机手工修复 chgrp + chmod 2775
后全过的口径);绝不用 0666/0777 放宽,与 round-11 authd
socket 组权限 0660 同款口径。建目录时的 chmod 与 tmpfiles
登记两处同改。
2026-11-08 04:23:41 +00:00
host
dafb0c6606
fix(chv-muse-r12fix-0): build.sh 建 /usr/local/share/chv 目录(认领 c3bf9fd)
...
纯 114b444 建不出镜像:P4 步骤把 browser-blocklist.txt 拷进
/usr/local/share/chv/,脚本里没有任何 --mkdir,virt-customize
报 target is not a directory。R12 真机靠本地-only 提交 c3bf9fd
(1 行,未推未合)绕过;本提交把该行合回分支,此后测试镜像
须从已推分支纯建出来。
2026-11-08 04:23:41 +00:00
host
114b444554
fix(chv-muse-round12): 移植 round-11 的 Page.aria_snapshot() 纠正到 CDP broker
...
Playwright 1.64.1 没有 page.accessibility(Puppeteer 的 API),
broker 的 snapshot 调它必走异常分支。改调 Page.aria_snapshot()
(字符串);guard 的 truncate_a11y 换成字符串版 truncate_aria
(179a86d 原样),detect_injection/detect_form_risk 加字符串
分支(dict 分支保留);两边 fake 与 P4 文档同步改。a11y-only
契约不变:不读原始 DOM、不走 JS eval。
测试:test_chv_muse_p2 + test_chv_muse_p4 114 OK;全量 2523 OK
(skipped=10)。
2026-11-07 18:24:58 +00:00
host
9da74c2a78
merge(chv-muse-round12): 合入 round-11 修复轮 HEAD 50cae2a (RETEST6 全绿)
...
按 hunk 合入,不整文件覆盖。冲突 3 处:
- chv-guest/build.sh:取 P4 的 copy-in(cdp-broker/guard/blocklist/
chv-memory)+ cdp-broker service/enable 三件;取 R11 的 git
config(去掉 credential.helper store,层 5);tmpfiles 两边
并存(/run/chv/ask-queue + /run/chv-browser)。
- chv-guest/chv-browser.py:P4 架构保留(CDP broker 客户端 +
guard 模块);取 R11 两处仍适用的运行期修复:BROWSER_SOCK
移进 /run/chv-browser(缺陷 4,合入后的 broker 已指该路径)
与 handle_request 认 op=browser/action 透传;R11 的直连
Playwright 代码(validate_url/truncate_aria/_load_playwright/
_page snapshot)由 P4 取代,不带回。
- cloud/tests/test_chv_muse_p2.py:truncate 三测取 P4 的
GUARD.truncate_a11y(dict 树);FakeCdpBroker 取 P4 版,删
R11 的 FakePage 系列;干跑夹具取 R11 的 _fixture 调用,并
给 _fixture 补 P4 四件(否则合入后 build.sh fail-fast)。
合入内移植(R11 修复在 P4 里移了位置,不移植即静默丢失):
- chv-guest/chv-cdp-broker.py:_load_playwright 返回
sync_playwright()(原 R11 在 chv-browser.py 修过的同形
bug);回归测试由 test_p2 移植到 test_chv_muse_p4.py。
- test_chv_muse_p2.py:HOST 由模块级 eager 改懒加载(_host()):
host.py 顶层 import queue 会把 stdlib queue 缓进 sys.modules,
使同进程后加载的 test_queue_sandbox 取不到 cloud/queue.py
遮蔽而 ImportError(全量唯一失败)。
未移植(见报告):R11 的 Page.aria_snapshot() 纠正未进
chv-cdp-broker.py(仍调 accessibility.snapshot(),且 guard
的 dict 树 API 须配套改,属 P4 返工,不在本轮合入做)。
全量 cloud 套件:2522 tests OK (skipped=10),基线 a6f9597
为 2474 OK (skipped=12);+48 来自 R11 新增测试(p2 +36、
p3 +7、closeup +3、gaps +1、p4 +1 移植)。
2026-11-07 18:13:31 +00:00
host
50cae2a0af
part 6 修复:worktree 根移出 /app——RETEST5 挂载点回归
...
RETEST5:part 5 的 --bind=<workspace>/.chv-worktrees:/app/work
(adc7bf6,排在 --bind-ro=/app 之后)让所有 cell 启动失败:
后挂的 bind 只有在挂载点已存在时才能盖住,挂载点不存在时
nspawn 在只读 /app 下连建都建不起来(Failed to create mount
point .../app/work: Read-only file system,全量 73 次,
CELL-RC=0 共 0 次),缺陷 1 的 15/15 回退为 0/15。
三选一取 (a) worktree 根移出 /app:
- chv-cell 不再发任何指向 /app 之下的 bind,删
--bind=...:/app/work 与 worktrees_dir 参数;WORKTREE_DIR
(/home/chv/workspace/.chv-worktrees)改经
--setenv=CHV_WORKTREE_ROOT 传进单元——该路径在已可写绑进
单元的 workspace 之下,挂载点问题按构造即不存在;backing
仍在客机 workspace 下随磁盘持久化,隔离与落盘语义不变,
只是单元内路径从 /app/work/host-worktrees 改为
/home/chv/workspace/.chv-worktrees/host-worktrees。
- host.py 新增 worktree_base():CHV_WORKTREE_ROOT 优先;
CHV_CELL=1 但变量未设时回落到同一单元内路径(旧版 chv-cell
/ 单元内手动跑 host.py 仍不出 /app);单元外沿用
HERE/work/host-worktrees,行为不变。make_worktree 与
dispatch_from_branch(第二个 HERE/work 调用方)同走该函数,
goal/fork/依赖链一并修到。
- 不选 (b) 默认 --no-worktree:隔离丢了,且 goal/fork 同样
调 make_worktree,照样撞 Errno 30;不选 (c) 镜像预建空
目录 /app/work:修法耦合镜像构建,某次重建漏建即静默回归,
且单测无法钉住镜像内容。
- 根因 1(39084ce)与根因 3(0203f32)代码未动。
单测:删 part 5 钉 argv 顺序的 4 项(该顺序本身已被真机证伪),
新增 CellPart6WorktreeTest 4 项 + HostWorktreeBaseTest 5 项:
argv 里无任何指向 /app 之下的 bind、CHV_WORKTREE_ROOT 经
setenv 进单元、worktree 根只经可写 workspace 绑定可达、
两处同值常量一致、worktree_base 三路选择、make_worktree
真 git worktree 落点、dispatch_from_branch 同根。
全量:cloud/ 下 discover -s tests,2067 项 OK(skipped=9)。
(注:仓库根跑 discover 会把 queue 解析成标准库、致
test_queue_sandbox 导入失败,须在 cloud/ 下跑。)
2026-11-07 14:23:48 +00:00
host
0203f32627
part 5 修复 3:P2-9 degraded_logged=False——降级日志文案漂移
...
定位结论(已定位,不是时序、不是日志路径变化):part 4 提交
7a22732 把 serve() 从 peer_allowed 切到 peer_allowed_multi 时,
降级分支的 reason 与警告行都被改写成了“无 cell pid 文件”,
“cell.pid 缺失”这个串自此再也没进过 journal——P2-9 驱动
grep 'cell.pid 缺失' 自然命中不了,RETEST4 的
degraded_logged=False 即由此来。RETEST3 同项为 True,是因为
当时跑的还是 part 4 之前的 broker(serve 直接打印含该串的
警告行)。降级 ping 本身一直 ok=True,降级逻辑没坏,坏的是
日志里的认领字符串。
修复:peer_allowed_multi 无 pid 文件时的 reason 改回与单 cell
版 peer_allowed 完全一致的“uid 在范围内(cell.pid 缺失,未做
pid ns 对照)”;serve() 的警告行改走新 helper
_degraded_warning(reason, pid, uid),把 reason 原样打进日志
(不再手写第二份文案,避免两者再次悄悄漂移;今后改文案只改
reason 一处)。journalctl grep 'cell.pid 缺失' 恢复命中。
新测试 cloud/tests/test_chv_muse_p2.py::BrokerMultiTest(2 项):
reason 含“cell.pid 缺失”、警告行含该串且带 pid/uid。
2026-11-07 12:07:32 +00:00
host
adc7bf6666
part 5 修复 2:默认 dispatch 在只读 /app 下建不了 worktree——workspace 绑定 /app/work
...
RETEST4 新发现 2:make_worktree 把 worktree 建在 HERE/work/
host-worktrees,单元内 HERE=/app 而 /app 是 --bind-ro,带 repo
的默认 dispatch 撞 OSError Errno 30(--no-worktree 的同任务
越过此关、跑到真实 turn)。
二选一取 (a) 给 worktree 一条单元内可写路径:客机 workspace
下的 .chv-worktrees 以可写 --bind 挂到单元内 /app/work 上
(build_nspawn_argv 新增 worktrees_dir 参数,默认
WORKTREE_DIR=/home/chv/workspace/.chv-worktrees;run_cell 起
单元前 _ensure_bind_source 建好该目录并 chown 回 chv)。
取舍:
- 不选 (b) 执行器默认 dispatch 带 --no-worktree:worktree
隔离就丢了——任务改动直接落进 repo 本身,多任务同仓互撞,
merge/discard/seed-dir 语义全坏;且只修 dispatch,goal/fork
同样调 make_worktree,照样撞 Errno 30。
- (a) 内不选可写 tmpfs:tmpfs 随单元退出即丢 worktree,跨
cell 的 run/merge 续跑找不着工作区;workspace 绑定随客机
磁盘持久化,worktree 语义、隔离与落盘位置(仍是
/app/work/host-worktrees/<任务>)全都不变,也不碰 P2 的
/usr 只读约束。
- bind 必须排在 --bind-ro=/app 之后(nspawn 按顺序挂载,后挂
的才盖住只读子树下的子路径),单测钉住该顺序。
未决(须 RETEST5 真机验证):nspawn 对 --bind 目的路径的
处理(目的不存在时是否自动建挂载点)与挂载叠加顺序只能在
真机上验证,单测只能钉住 argv 形状;本轮不建镜像、不跑真机。
新测试 cloud/tests/test_chv_muse_p2.py::CellPart5WorktreeTest
(4 项):可写 bind 在位且在 workspace 下、顺序在
--bind-ro=/app 之后、自定义目录参数生效。
2026-11-07 12:07:01 +00:00
host
39084ce2bf
part 5 修复 1:单元内 health 恒 false——default_codex_bin() 回落 shutil.which
...
RETEST4 新发现 1:单元内无 CODEX_BIN、无 HERE/bin/codex 时
default_codex_bin() 返回裸 "codex",run_health_check 的
os.path.exists("codex") 以相对路径判恒为 False,health 的 ok
恒 False(execpath4、p2_7v4、P1 resident_health、P1B 两 call
全因此失败;定界探针证实单元内 which codex 就是
/usr/local/bin/codex,加 CODEX_BIN 前缀即 rc=0 且 ok=true)。
三选一取 (c) 回落 shutil.which("codex"):
- (a) CODEX_BIN 进 FORWARD_ENV_ALLOWLIST:要执行器与 chv-cell
两边接线、还得在客机环境里定一个单元内路径,改动面大,且
只修执行器驱动的调用,直接跑 host.py 的 health 修不到。
- (b) _guest_host_command 显式加 --codex-bin:把客机镜像路径
硬编码进执行器,同样只修执行器驱动的调用。
- (c) 单点修 host.py:health、Server、automations 全部调用方
直接受益;PATH 里找得到即返回绝对路径,找不到仍返回裸
"codex"(行为与旧代码一致,零回归面);不硬编码任何路径。
新测试 tests/test_host.py::DefaultCodexBinTest(4 项):模拟
单元内环境(PATH 含 codex、cwd 不含 codex、无 CODEX_BIN)
断言返回绝对路径、CODEX_BIN 优先、处处无 codex 时仍返回裸
"codex"、以及该解析下的 run_health_check ok=true。
2026-11-07 12:06:20 +00:00
host
c4661b64db
part 4 文档:P2 差距表补记三缺陷修复
...
RETEST3 三个 cell 新缺陷的修复方向与实现位置记入 §6:
起步门 + init pid 轮询、volatile 空根只读绑(/app、CA、
单元专属 resolv.conf/hosts;不绑 nsswitch.conf 的原因)、
唯一身份分配 + broker 多 cell 对照、执行器记 body。
2026-11-07 10:30:45 +00:00
host
f20cbc79cd
part 4 附带:vm.boot/vm.create 500 记响应体
...
_boot_vm 只留 status 导致间歇 500 根因无法定位(两轮已提,
未改)。_api_call 的两个调用点现在都把响应体(截断到 500
字符单行)放进 ChvFailure 消息:vm_create_failed 与
vm_boot_failed 均含 status 与 body。body 是 VMM 的报错文本,
不含秘密;超长截断并标明。
新测试:test_wake_vm_boot_failed_records_body、
test_wake_vm_create_failed_records_body、
test_wake_vm_boot_failed_body_truncated。
2026-11-07 10:30:45 +00:00
host
7a227323f2
part 4 缺陷 3:并发 cell 撞毁——唯一身份 + run_cell 接线
...
RETEST3 缺陷 3:固定 ve-chv-cell 名 + 固定 10.200.0.1/24,
第二个 cell 在 nspawn 建 veth 时即 File exists/Address
already assigned。
- CellNet + allocate_cell_net():每次 run_cell 在 flock 锁下
(/run/chv/.cell-alloc.lock,30 秒超时)分配唯一身份:
machine chv-cell-<xx>(11 字符)、宿主 ve-chv-cell-<xx>
(14 字符,接口名 15 字符上限内)、10.200.<xx>.0/24;
扫描活接口 + 地址 + machinectl 在册名,避让注销滞后的下标。
- 配网命令表(host/cell/cleanup)与 build_nspawn_argv 接受
net/cell_net 参数;None 时仍用旧常量(argv 子命令与旧测试)。
- run_cell 重写:分配身份 -> 生成专属文件 -> 起步门 payload
-> 等 veth(20 秒)-> 宿主配网 -> 轮询 init pid(10 秒)
-> 写 pid 文件 -> 单元内配网 -> 开门 -> 等退出码;
nspawn 已死返回其退出码;finally 清 NAT/pid/专属文件。
共享网络模式跳过门与身份(无配网可等)。
- broker:pid ns 对照改多 cell 版(peer_allowed_multi +
_read_cell_pids:cell-<machine>.pid glob + 兼容旧 cell.pid;
对端 ns 与任一活单元同 ns 即放行;残留 pid 文件只跳过,
全部读不到才拒绝,不降级)。
新测试:CellAllocTest、CellPart4NetworkTest、
CellPart4ArgvTest(cell_net 两法)、BrokerMultiTest。
2026-11-07 10:30:30 +00:00
host
2be69af92c
part 4 缺陷 2:volatile 空根缺 /app 与 /etc 关键文件
...
RETEST3 缺陷 2:--volatile=yes 下单元根是基本空的 tmpfs,
/app、/etc/resolv.conf、/etc/hosts、/etc/ssl/certs 全无,
执行器单元路径一律 ENOENT、DNS/TLS 不可用。
- build_nspawn_argv:固定只读绑 --bind-ro=/app 与
--bind-ro=/etc/ssl/certs;新增 extra_ro_binds 参数
(单元专属 resolv.conf/hosts 由 run_cell 传进来)。
- prepare_cell_files():按客机有效 DNS 生成单元专属
resolv.conf/hosts(/run/chv/resolv.conf.<machine>、
hosts.<machine>,0644——单元 root 映射为客机 uid 1000,
0600 的 root 文件单元内读不到;DNS/hosts 不含秘密)。
客机 resolv.conf 可能是 systemd-resolved stub
(127.0.0.53),单元内无 resolved,直接绑 stub 即 DNS
全灭,故过滤 stub 后备选 /run/systemd/resolve/resolv.conf,
两处都没有即大声失败。nsswitch.conf 故意不绑(客机版
可能含 resolve 模块;glibc 默认 files+dns 正是单元需要的)。
新测试:CellFilesTest、CellPart4ArgvTest(绑定两法)。
run_cell 接线在缺陷 3 的重写里做。
2026-11-07 10:29:31 +00:00
host
fc33eed262
part 4 缺陷 1:cell 启动竞态——起步门 + init pid 轮询
...
RETEST3 缺陷 1:run_cell 里配网与 payload 零同步,快 payload
(run -- true)在配网完成前退出即撞墙,11 次只成 6 次。
本提交先落 helper(接线在缺陷 3 的 run_cell 重写里做):
- gate_wrapper_command():payload 包一层 sh 起步门,等
/run/chv/.cell-gate-<machine> 出现再 exec(绝对路径
/usr/bin/sh:volatile 单元根里 /bin 未必有)。
- find_cell_init_pid() 改带超时轮询(timeout 默认 0.0 = 单次,
旧调用行为不变;缺目录不再直接回 None;proc_alive 回调让
nspawn 已死时立刻回,不空等)。
新测试:CellGateTest、CellInitPidPollTest(5 个)。
2026-11-07 10:29:13 +00:00
host
179a86d655
fix(chv-muse-r11fix): browser 快照改 Page.aria_snapshot()(复测新发现 2)
...
Playwright 1.64.1 的 Page 根本没有 accessibility 属性(那是
Puppeteer 的 API),open/snapshot 在真实库上必报
'Page' object has no attribute 'accessibility'。原生快照是
Page.aria_snapshot()(返回 ARIA 快照字符串),a11y 字段仍叫
a11y,值改为字符串;截断改字符串版 truncate_aria(200 节点
行/64KB)。FakePage 同步改真形状(旧 fake 自带 .accessibility
与真实库分叉,是与 sync_playwright bug 同款模式)。
wheel 1.64.1 实测:sync_api/_generated.py 无 def accessibility,
Page 与 Locator 均有 aria_snapshot() -> str。
2026-11-07 07:02:37 +00:00
host
581e850eb7
fix(chv-muse-r11fix): cell 只遮 /usr 下路径(复测新发现 1)
...
--volatile=yes 下容器根是基本空的 tmpfs(只挂进只读 /usr),
nspawn 按容器根解析 --inaccessible 路径,/etc/chv 与
/home/chv/.git-credentials 在容器根里根本不存在,解析失败即
Failed to resolve 而起不来;两条 /usr 旗可解析,保留。
凭证文件按构造即不可达(容器根里无 /home、无 /etc/chv),
遮蔽不再是必须项,安全属性不变。
探针证据:celldiag2/3/4——去 inaccessible 后完整 argv 0.4s/rc=0,
单元内 $HOME/.cache 可写,单元内 ls /etc/chv 本来就不存在。
2026-11-07 07:02:37 +00:00
host
04287f6053
fix(chv-muse-r11fix): chv-browser 补 sync_playwright 调用括号 + 接受 broker 的 browser op(复测新发现)
...
复测(RETEST.md §browser-defect、§broker-proto):
1. _load_playwright 返回裸 sync_playwright 函数(未调用),
_ensure_browser 对它调 __enter__ 即 AttributeError,open
永远失败。改返回 sync_playwright()(调用后的上下文管理器),
与单测假工厂的形状一致。回归测试用 stub 的 playwright 模块
钉住“返回调用结果、不是函数本身”。
2. broker 按设计原样转发 {op: browser, …},chv-browser 白名单
却不认 browser。在 chv-browser 的 handle_request 里归一化:
内层 op 在 action 里;无 action 但带 url 时默认 open(驱动
只发 url);action 同样受 FORBIDDEN_OPS 约束。broker 保持
原样转发不动(其 docstring 与单测均以此为契约)。
附:本提交含 test_chv_muse_p2.py 里 CellArgvTest 的配套更新
(c1d00b3 的 --volatile=yes 断言,同文件无法拆分提交)。
2026-11-07 05:24:42 +00:00
host
c1d00b3620
fix(chv-muse-r11fix): cell 改 --volatile=yes(复测纠正缺陷 2)
...
复测(RETEST.md §cell):--ephemeral 在客内 ext4 根盘(2.4G、
已用 1.8G、可用 593M)上做整盘快照拷贝,空间不够即 ENOSPC,
全部 cell 调用失败(每次约 10.5s veth 超时后 rc=1)。改
--volatile=yes:根为基本空的 tmpfs、/usr 只读挂进,单元内除
bind 出去的目录外一律可写、用完即弃——与 --ephemeral 的设计
意图一致,但不拷盘、不占空间(systemd-nspawn 手册口径)。
--volatile=state 不行:整树只读、仅 /var 为 tmpfs,codex 写
$HOME/.cache 等非 bind 路径会失败。探针已证实 yes/state 均可
启动(0.4s,rc=0),取 yes 保可写性;真机 codex 入 cell 由
第二轮复测验证。测试:CellArgvTest 断言新值、--ephemeral
不再出现。
2026-11-07 05:24:30 +00:00
host
4a7ca25334
fix(chv-muse-r11fix): browser.sock 移进 chv-browser 自有目录(缺陷 4)+ vsock 自动启动
...
缺陷 4:/run/chv 是 0755 root root,chv-browser 在 bind 时
EACCES 而无限 crash loop(restart 21)。browser.sock 从
/run/chv/browser.sock 移到 /run/chv-browser/browser.sock
(broker 与 browser 两端常量同改);build.sh 建目录 + tmpfiles
登记(0755 chv-browser 所有)。不用组可写 /run/chv——那会给
chv-browser 对 broker.sock/cell.pid 的 unlink 能力。
vsock 自动启动:此前 build.sh 只拷 vsock_notify.py、不建服务,
vsock 通道从未自动启动。按 vsock_notify.py 的 docstring 补
vsock-notify.service(ExecStart=/usr/local/bin/vsock-notify %H,
Restart=no,After/WantedBy=multi-user.target)并 enable;
printf 格式串里 %H 写 %%H。测试:干跑针 /run/chv-browser;
vsock 在场时干跑含服务与 enable 语句。
2026-11-07 04:01:24 +00:00
host
f093558c0d
fix(chv-muse-r11fix): authd 层 5 去掉 store helper,chv-sync 回落改 fail-closed
...
round-11 真机测试证实:镜像 /etc/gitconfig 的 [credential]
helper = store 把 authd 释放的长效 token 写进了客内
/home/chv/.git-credentials(0600)。改动:build.sh 不再设
store helper;chv-sync boot 在 authd socket/helper 缺失时直接
die,不再把 token 写进 .git-credentials(旧落盘回落废止);
authd helper 是唯一凭证 helper,且自身绝不落盘。旧镜像上 boot
现在会直接失败,须用含 authd 的新镜像。测试:无 authd 时 boot
失败且 .git-credentials 不产生、干跑不再含 store helper;P3
差距表 §3.5 更新为已关闭。
2026-11-07 04:00:04 +00:00
host
9f593d62ef
fix(chv-muse-r11fix): authd 层 3 socket 用 group 权限、层 4 裸 .git 当 pull
...
层 3:AuthdServer 不再 0700/0600 一刀切。socket 共享组取显式
socket_group 或第一个非 root 放行 uid 的主组(build_server 透
传;生产默认 allowed_uids=(0,1000) 派生 chv 主组),目录 0750
+ socket 0660 + chgrp;解析不出(uid 无 passwd 条目)回落
root-only,绝不放 0666(探针 fixprobe8 用的 0666 不上生产)。
层 4:_operation_for_path 加裸 .git → GET/pull;Sentinel
gitea 规则加 (GET, suffix, .git),POST 裸 .git 仍拒。语义已定:
裸 .git 一律当 pull(只读默认),push 只走显式 git-receive-pack。
测试:Sentinel 允许 GET/拒绝 POST 裸 .git、helper 端到端裸路径
取凭证、组 gid 派生与回落、显式组落地 0750/0660。
2026-11-07 03:58:45 +00:00
host
2d12179b9a
fix(chv-muse-r11fix): authd 层 1 叶子树补 errors.py + stub __init__、层 2 seed 补三键
...
层 1:真实的 cloud/chv/__init__.py import executor/orphans,拷进
authd 最小叶子树(/usr/local/lib/chv-authd)会让 chv-authd 在
import 时 ModuleNotFoundError 而 crash loop——先是 errors.py
缺失,补上后又在 executor 上失败(探针 fixprobe3)。新增
chv-guest/authd_init_stub.py(仅导出 ChvFailure),build.sh 拷
errors.py + stub 作叶子树的 __init__.py,不再拷真实包 __init__;
P3_LIBS_PRESENT 条件加 errors.py;EXTRA_CONTENTS 加 errors.py 与
__init__.py;两 lockfile 脚本的 DECLARED_SOURCES 同款登记。
层 2:_seed_env_entries 把 guest-env 里的
GITEA_URL/GITEA_USER/SYNC_REPO 抄进 authd-seed(build_server
要求四键齐全,只 GITEA_TOKEN 即 ValueError);没有不补、不编
默认值。测试:seed 三键落盘/缺键不补、干跑夹具含新文件、lockfile
合成清单含新两项。
2026-11-07 03:56:24 +00:00
host
b41fb67026
fix(chv-muse-r11fix): 执行器以 sudo 调 chv-cell(缺陷 1)
...
chv-cell 须 root(nspawn + 配网),执行器经 SSH 以 chv 身份调,
此前无 sudo 即 rc=2。改 _guest_host_command 在单元开时前缀 sudo
(探针 p2.log 的手动调用即 sudo chv-cell run;chv 的 NOPASSWD
sudo 来自 seed users 块)。关时原命令不变。
2026-11-07 03:52:34 +00:00
host
e02828c590
fix(chv-muse-r11fix): nspawn 255 拒裸 --no-new-privileges 与 --directory=/(缺陷 2)
...
systemd 255 把裸 --no-new-privileges 当作带必填参数的选项,吞掉
下一个参数后报错(p2.log 实测);--directory=/ 也被拒,须
--ephemeral 或 --volatile。改 --no-new-privileges=yes,
--directory=/ 后加 --ephemeral:根快照 + overlay,单元内除 bind
出去的目录外一律可写、用完即弃,与 P2 共享客机 rootfs 设计一致;
--volatile 会把根置只读,codex 写 $HOME 下非 bind 路径会失败。
测试:CellArgvTest 断言新值、裸值不再出现。
2026-11-07 03:52:34 +00:00
host
a6f9597333
round-12: §20 records 717efc4 merge + final suite numbers
...
Docs only (no code/test change): §20 now records the merge of
round-11 head 717efc4 (V-9 fixes) as 5d5041b with its conflict
resolution, and the final full-suite result on 5d5041b : 2474 tests,
OK (skipped=9). ruff/mypy state noted.
2026-11-07 01:13:05 +00:00
host
d324d87529
fix(chv-muse-round11): lockfile DECLARED_SOURCES 补 P3/vsock 六项
...
717efc4 镜像真机实测:BUILDINFO.contents 含 chv-authd 三件套、
cloud/chv/authd.py、cloud/chv/sentinel.py、vsock_notify,但两
脚本 DECLARED_SOURCES 没有它们——generate 记 6 项 unresolved,
verify 与 check 双双失败(contents 未覆盖)。V-9 的 912edef
没暴露:它的 contents 里根本没有这 6 项。
与 9f929b1 的 P2 三件套同款修法:六项皆仓库内脚本,版本随
repo_commit。合成 BUILDINFO 清单扩到与 717efc4 真实 contents
一致(另补 systemd-container 进 dpkg 假值),反向对照已验:
只撤修复时 LockfileTest 4 测里 2 测失败。
附带教训:经 ssh->wsl.exe 的命令内层退出码一律被吞成 0
(python3 -c 'sys.exit(1)' 回显 RC=0),此前三项验证只看
RC 会把失败判成通过;此后一律以输出文本为准绳(须见
'lockfile 校验通过' 行且无 unresolved 警告)。
2026-11-07 01:08:28 +00:00
host
5d5041bb7c
round-12: merge round-11 head 717efc4 (V-9 real-machine fixes)
...
Round-11 moved on Gitea after round-12 branched (29d3a5a -> 717efc4 ):
V-9 guest-env fixes must be in any image built from this branch, or
the round-12 image would ship the known defects V-9 found (guest-env
never created when owner=chv:chv; wake reporting ready ~30s before
the runcmd chown lands). Contents, all from 717efc4 :
- build.sh: runcmd chowns /etc/chv/guest-env to chv:chv after
'start chv-authd', before 'chv-sync boot'
- check/generate_lockfile.py: DECLARED_SOURCES gains P2 trio
(chv-cell/broker/browser -> repo_commit)
- executor._wait_guest_env_usable: with secrets delivered, wait for
guest-env readable by the SSH user before reporting ready; timeout
stops the VM and raises guest_env_not_ready; called from _boot_vm
- hostkeys.py: V-9 root-cause comment (owner always root:root)
- test_chv_gitea_sync.py: 5 new tests
Conflict: build.sh runcmd line only. Resolved as union: 717efc4's
runcmd line (with chown) kept; HEAD's P4 trio + P7 chv-memory
copy-in lines (absent on the 717efc4 side) kept. executor.py
merged cleanly.
2026-11-07 01:05:51 +00:00
host
414e245752
round-12: ruff hygiene on migration code (import sort, narrow store except)
...
- test_chv_muse_round12.py: drop unused socket/time imports, drop
unnecessary sys.path.insert (P3 pattern needs none), sort method-local
imports (activity/capabilities, approval_card/channel/sentinel)
- audit_trail.py: single-line method-local imports (I001)
- swarm.py / presentation.py / browser_tasks.py: store-path fail-safe
except narrowed from bare Exception to (sqlite3.Error, OSError)
(DB/file failures only); transport spawn/ping/close handlers in
browser_tasks.py deliberately stay bare Exception (arbitrary
transport errors must map to failed/False/close_error)
- NOT fixed (pre-existing style, left as-is): UP031 % formatting
(used throughout the codebase incl. the copied lines), BLE001/
TRY004 in untouched code, F401 atomic_write + RUF059 swarm
(P7/P8 pre-existing)
2026-11-07 00:57:05 +00:00
host
717efc4688
feat(chv-muse-round11): 移植 V-9 真机修复(9f929b1/912edef/9fb0f4b)
...
- lockfile 两脚本 DECLARED_SOURCES 加 P2 三件套 chv-cell/broker/
browser -> repo_commit(9f929b1)。
- build.sh 99-chv-sync.cfg runcmd 在 chv-sync boot 之前加 chown
行:guest-env 由 write_files 以 root:root 写(建用户之前),
须在 final 阶段改归 chv(912edef;本分支 runcmd 多一行
start chv-authd,chown 插在它之后、boot 之前)。
- executor._wait_guest_env_usable:密钥已投递时等客内 guest-env
对 SSH 用户可读再报 ready,超时关 VM 抛 guest_env_not_ready
(9fb0f4b;runcmd chown 比 SSH 就绪晚约 30 秒)。
- hostkeys.py:本分支 _guest_env_entry 本来就写死 owner
root:root(P3 重构时已无 ssh_user 分支),912edef 的
hostkeys 改动无内容可移,只补 V-9 根因注释防回退。
- 测试(5 个新测试,8 个运行):owner 恒 root:root、build.sh
chown 位置、chv 用户下 wake 后 owner 仍 root、等到可读、
永不可读抛 guest_env_not_ready。
全量 cloud 套件 2019 OK(skipped=8)。
2026-11-07 00:48:25 +00:00
host
da8d0c29fd
round-12: fix integration fallout (P9 gate x P1, P7 check x P2/P4 fixtures)
...
- P1 resident tests: P9's inference gate is a precondition of
_run_with_vm, so _RealExecCase.make_executor now configures a
default inference origin (CHV_INFERENCE_ORIGIN=https://xgapi.lol
+ CHV_INFERENCE_ALLOW_HOSTS=xgapi.lol) and a public fake resolver
(same setup as P9's GateTest). No assertion changed; the gate's
fail-closed behavior on missing origin stays pinned by P9's own
ask test. 9 resident tests fixed (7 errors + 2 failures).
- P2/P4 dry-run fixtures: P7's build.sh hard check requires
chv-memory.py in the repo; add it to both fixtures' copy lists.
2 failures fixed.
- No production code changed in this commit (test setup only).
2026-11-07 00:43:50 +00:00
host
d4cef29cdb
round-12: migrate P8 registries + P12 audit to AppStateStore
...
- app_state.py: host_state_db_path() (host-level DB, distinct from
per-VM state_db_path); kv_get/kv_put/kv_delete on meta (namespaced
keys; kv_put skips the no-secrets guard by design — registry docs
hold user prompts, documented); audit_trail table (P12 record
shape + hash chain, seq explicit); counts()/backup() gain
audit_trail.
- swarm.py / presentation.py / browser_tasks.py: JSON-file backends
replaced by KV rows (p8-swarm / p8-ledger / p8-browser-tasks);
legacy JSON imported once on first load (renamed .migrated);
corrupt row / unreadable store returns empty (fail-safe, same
semantics as before; next successful save self-heals).
- audit_trail.py: StoreAuditTrail (same record shape, hash chain,
filters, export as JSONL version, backed by audit_trail table);
migrate_jsonl_to_store() moves a chain verbatim (broken chain
refused, divergent seq refused, re-run idempotent). JSONL class
kept for reading old files.
- P12 dict contracts now run against real P3/P5 code
(ApprovalQueue.record -> build_approval_card ->
card_matches_channel; CapabilityIssuer.issue -> describe ->
PermissionRegistry.record_grant).
- P6->P3 local protocol test: real PrivsepClient + real worker
server + real git status; worker git argv carries the real P3
helper + useHttpPath; no token in argv/env/audit. runuser + HTTP
pull stay real-machine-only (see gap docs).
- Gap docs updated: P8 migration done, guest-side browser follow-up
explicitly left for the real-machine track (no task_id in the
browser protocol yet; lifecycle needs a real VM to verify);
P6 wiring + P12 migration marked done; production-readiness.md
gains §20 (round-12 integration).
- Tests: new cloud/tests/test_chv_muse_round12.py, 24/24 OK;
test_chv_muse_p8.py ledger corrupt test rewritten for the KV
backend (+ legacy-import test). P7+P8: 95+1 tests OK.
2026-11-07 00:36:25 +00:00
host
466cf7eae7
merge(chv-muse-round12): 合入 P12 审计轨迹与活动视图 ( 9759be4)
2026-11-07 00:10:34 +00:00
host
77743e734d
merge(chv-muse-round12): 合入 P11 用量计量与配额 ( 60c371d)
...
- 冲突仅一处:docs/chv-production-readiness.md §15 撞号——
P11 节顺延为 §19(§15 P2 / §16 P4 / §17 P6 / §18 P7
保持不动),节内无自引 §15,无内容改动。
- P11 未决冲突原样保留(见 docs/chv-muse-p11-gap.md §5):
档位门只做准入、USD 路径不动,等待用户裁决,不悄悄统一。
- 测试:test_usage_quota 22/22 OK。
2026-11-07 00:10:32 +00:00
host
b55b49b358
feat(chv): 对齐 Muse P10 支付安全——凭证隔离 + 结账检测 + 每次购买人工审批 + 一次性卡号
...
- 支付凭证隔离:PaymentCredentialVault(只活内存、白名单
stripe-link/shop-pay、只存不透明 id + 掩码标签、原始卡号
PAN 拒绝入库、按次释放绑定商家/金额/货币、单次 + TTL)
- 结账页检测:detect_checkout(URL + 无障碍树信号,确定性
规则、不读原始 DOM、与 P4 detect_form_risk 同输入形状)
- 每次购买人工审批:PaymentGate 经 P5 对话外通道发审批,
payload 含确切购买详情;完成时先验签、再验详情摘要
(篡改即拒且审批保持待处理)、最后单次消费答复
- 一次性卡号:OneTimeCard 绑定商家/金额/货币/有效期,单次
兑现;SimulatedWalletBackend 沙箱钱包(假 PAN 只在后端
私有内存、charge 只记账不联网、取消即 void)
- 限额:SpendLimits 三档 minor units 比对,限额不可用时
不编造上限(limits_checked=False)
- 审计:PaymentAudit 只留允许字段,秘密字段名丢弃 + redacted
- 审批通道最小扩展:ApprovalRequest 增加可选 details 字段,
不传时 payload 与 P5 完全一致
- 真实支付与扣款不做:全部沙箱验证,真实钱包集成待用户
另行批准;新测试 79 项,全量 cloud 套件 2037 OK
round-12 集成说明:本提交为 acf98f8 的 cherry-pick(只含 P10
自有 diff,基线 25bcd35 已含的 P3/P5 内容未重复合入;
approval_channel.py 仅加可选 details 字段)。
2026-11-07 00:09:55 +00:00
host
90c42f6e1d
Merge feat-chv-muse-p9: inference/telemetry restricted channel
...
- executor.py: P9 _inference_gate inserted before P1 dispatcher
_run_with_vm; gate call is the first statement, so deny/ask
fail-closed before any resident resume or cold wake. P9's own
_run_with_vm (old-body variant) dropped: its body is byte-identical
to P1 _run_cold (verbatim move), kept once in _run_cold.
- sentinel.py: P9 superset version wins (P5 base + inference entries
POST /v1/responses, GET /v1/models + comments).
- inference_channel.py / telemetry.py / host.py: P9 as-is.
- Tests: P9 51 + closeup/gaps/optimize/cloud_hypervisor/fix 272 OK.
- mypy on changed files: P9's 5 cross-track errors gone (P5
capabilities.py now in tree); remaining 4 are 06c3e17 baseline
legacy (marker_tools.py:142, executor.py:1573/1578), untouched.
2026-11-07 00:09:26 +00:00
host
240949e444
merge(chv-muse-round12): 合入 P8 后台工作 ( 8d4771b)
2026-11-07 00:03:00 +00:00
host
320cd36921
merge(chv-muse-round12): 合入 P7 状态与记忆分离 ( 29fa0c8)
...
冲突按并集解:build.sh 保留 P2+P3+P4 检查/拷入 + P7 的
chv-memory 检查/拷入(P7 的重复 runcmd 行删掉——同一文件
写两次会盖掉 authd 启动行);buildinfo.py 加 chv-memory 一项;
production-readiness.md P7 一节顺延为 §18。P7 测试 46 项全过。
2026-11-07 00:02:54 +00:00
host
b0b9f5ed9d
merge(chv-muse-round12): 合入 P6 privsep worker + 确定性安全检查层 ( 81e4eaf)
...
唯一冲突是文档 §15 撞号:P6 一节顺延为 §17,基线说明更新
(P3 已在树里,接线走真实代码)。chv-sync.sh 自动合入正确:
P6 的 worker 路径与 P3 的 authd 路径(useHttpPath)都在。
P6 测试 43 项全过(skipped=1 是 root 下 uid 否定测试)。
2026-11-07 00:02:22 +00:00
host
d1c9a8e647
merge(chv-muse-round12): 合入 P5 Sentinel 纵深 ( 25bcd35)
2026-11-07 00:01:39 +00:00
host
c24cc0ba92
merge(chv-muse-round12): 合入 P4 浏览器完全对齐 ( 1c8fc3f)
...
冲突按并集解:build.sh 保留 P3 authd 检查/拷入/runcmd(含
start chv-authd)+ P4 三件套检查/拷入(P4 的重复 runcmd 行
删掉——同一文件写两次会盖掉 authd 启动行)+ P4 的
cdp-broker.service/tmpfiles(含 ask-queue)+ P3 叶子模块条件
拷入;buildinfo.py 两边内容项并集;chv-browser.py 取 P4 重构
版(broker 客户端);production-readiness.md P4 的 §15 顺延为
§16。P2 的 BrowserTest 改走假 CDP broker(断言不变),两路
干跑夹具补齐并集文件集。
2026-11-07 00:01:35 +00:00
host
c06ba50983
feat-chv-muse-p9: 推理与遥测受限通道(Sentinel 预审 + 遥测最小化 + 训练退出开关)
...
- 受限推理通道:cloud/chv/inference_channel.py(origin 解析、
allowlist、上限、Sentinel 预审),执行器 _run_with_vm 起 VM 前
必过 _inference_gate(allow 才继续,deny/ask 审计 + fail-closed,
任务级 extra_env 合并进预审);host.py 第二道防线(_server_command
的 origin 结构校验 + Server.request 超时/重试走 env)。
origin 规则:https 公网网关(只 443);http 只接受本地中继
(字面环回/私网 IP,如 http://172.17.0.1:28084,端口保留 ,
无 DNS、无重绑定,allowlist 与单次能力照常);未知 provider
标签走默认网关(与 _server_command 一致)。
- sentinel.py:从 P5(25bcd35)取的超集版本 + 推理连接器条目
(POST /v1/responses、GET /v1/models;scheme/端口只 https/443,
本地中继不走 evaluate,不把 http 加进表)。
- 遥测最小化:cloud/chv/telemetry.py(字段白名单、确定性采样、
落盘失败不影响任务、token 未回传记 null)+ 训练退出开关
(默认开,本项目决定;关后轨迹不再产生;损坏 fail-closed;变更审计)。
- 访问边界:docs/chv-access-boundary.md(运营访问口径 + 审计钩子,
不冒充技术不可访问;Confidential VM 明确未做)。
- 测试:cloud/tests/test_chv_muse_p9.py 51 组全过;5 个旧文件
的 make_exec 配假 origin + 假解析器(新 fail-closed 门要求的
测试配置);全量 cloud 套件 1918 OK(skipped=8)。
详见 docs/chv-muse-p9-gap.md(含自定清单与真机待验证清单)。
2026-11-06 23:03:06 +00:00
host
8d4771bce3
feat(chv): align Muse P8 background work (crons/swarm/presentation/per-task browser)
...
- crons: pause/resume, exponential-backoff retry (cap 1h), retry claim
single-winner reusing quota+task build, run_cron_tick cap 5/project
- swarm: per-agent task id + isolated workspace (resolve_inside gate),
tool register + invocation audit (no execution in swarm layer)
- presentation: worth-presenting rules (needs_input/failed/new
content only) + notification ledger dedup 1h per (task, reason)
- browser_tasks: one BrowserTransport instance per browser task,
single-use (reuse after destroy refused), shots dir per instance
- automations: paused status + retry columns (max_retries,
retry_backoff_seconds, consecutive_failures, next_retry_at)
- gap table docs/chv-muse-p8-gap.md; self-defined values listed there
(not Meta official): tick cap 5, swarm max 32/default 8, retry
base 60s cap 3600s, ledger window 3600s, snapshot trunc 200/64KB
- tests: 49 new in cloud/tests/test_chv_muse_p8.py (incl. negatives:
cron unauthorized trigger, cross-workspace access, no-content
silence, dedup); full cloud suite 1916 OK (skipped=8)
2026-11-06 22:42:31 +00:00
host
60c371d9d5
feat(chv): 对齐 Muse P11 用量计量与配额执行——四项计量 + 三档档位门 + 哈希链账本
...
- cloud/usage.py(新):TIER_LIMITS 三档提案(Free $0/Paid $19/Heavy $99,
提案非定价,payload 带 proposal 标注)、TierStore(无档位行不受档位门
约束)、UsageLedger(追加写哈希链,篡改可发现)、UsageMeter(token 读
cost_records、消息读账本、并发/存储注入实测)、QuotaGate(纯准入判定,
402,不碰在跑任务)、80% 提醒每维度每窗口一次
- cloud/server.py:_reject_if_over_quota 内加档位门(同一漏斗,双人门
自动覆盖;查询异常 fail-closed 503)、GET /users/me/usage、
GET/POST /admin/tiers、存储实测复用 _task_worktree_for_files
- docs/chv-muse-p11-gap.md:差距表(先写表再动手)+ 诚实边界(USD 路径
30 秒轮询掐断与“不掐断”语义不一致是已知待决;并发即拒与设计文档
排队不同;cloud 任务存储量不到;Heavy 消息/天提案未给,本轨定不限)
- 测试 22/22,全量 1889 OK(skipped=8);mypy 在 usage.py 上干净,
server.py 5 错均为基线旧错(marker_tools/sub2api/_row_get,与本轨无关)
- 真机验证排队在 round-11 与 P4~P9 之后;不接真实计费
2026-11-06 22:42:30 +00:00
host
29fa0c8813
feat(chv): 对齐 Muse P7——状态与记忆分离
...
- 每 VM 一个 SQLite 状态库(cloud/chv/app_state.py):
state_dir/<vm>/app-state.sqlite(0600,WAL),表 tasks/goals/
sessions/audit(只追加)/meta;写操作过无凭证守卫(键名 +
值模式);备份用 sqlite3 在线备份 + manifest(sha256),恢复
先验 manifest、先留 pre-restore 副本;DDL 用 SQLite 与
Postgres 共通受限子集,换 Postgres = 换连接工厂。
- 记忆文件接线(cloud/chv/memory_files.py):宿主镜像读/列/
写/追加(路径穿越守卫、写审计);MemorySystemClient 调真实
记忆系统 CLI(search/get/explain/forget-plan/forget-confirm/
backup/restore/export),不重造引擎;forget = plan → confirm
→ 本地清行 → search 验证查不到;pull_memory_home 经 SSH +
tar 拉取客机记忆家目录。
- 客内脚本 chv-guest/chv-memory.py(纯标准库,list/read/
append/forget/export),家目录 /home/chv/memory(workspace
之外,不同步到 Gitea);build.sh 拷入 + buildinfo 登记。
- 新测试 cloud/tests/test_chv_muse_p7.py 46 项全过(含真 CLI
write/search/forget/backup/restore 实测、假 ssh 拉取、否定
测试);全量 cloud 套件 1913 项 OK(skipped=8)。
- 存储选型:SQLite 不是 Postgres(见差距表 §4;轻量 VM 跑
Postgres server 太重,宿主共享 Postgres 破坏每用户 VM
隔离);忘记是尽力删除 + 验证,不是密码学擦除。
- 真机待验证(未做,等测试机空闲):见
docs/chv-muse-p7-gap.md §6 清单
2026-11-06 22:39:04 +00:00
host
9759be47bb
feat(chv): 对齐 Muse P12——审计轨迹与活动视图
...
统一审计记录模型(时间/主体/动作/对象/结果/原因/关联任务/
关联审批)+ 追加写 JSONL + SHA-256 哈希链(改写/删除/调序可
被 verify 发现)+ 字段级白名单清洗(密钥/token 值/对话原文
绝不进审计);事件分类覆盖任务派发、VM 生命周期、同步、审批、
支付、配额、记忆、后台、推理/遥测;from_legacy_row 承接现有
audit_log 行;导出选 JSON。
活动视图后端:计划登记(已做 vs 计划做,流转受控)+ 已批准
权限登记(接 P5 describe 形状)+ activity_summary 纯函数;
结构化审批卡数据(风险分级 + 接受/拒绝明确动作 + 五档授权
选项,永久档须显式 opt-in)+ card_matches_channel 校验卡与
P5 通道载荷一致。
只做后端 + 数据接口,前端视图留接口;P3/P5 不在本基线,
接线走 dict 契约,集成由 round-11 合并;审计持久化先落独立
JSONL,待 P7 状态库就绪后迁移。真机验证排队在 round-11 之后。
新测试 43/43,全量 cloud 套件 1910 OK(skipped=8);
mypy 在改动文件上干净。
2026-11-06 22:38:19 +00:00
host
1c8fc3f7c8
对齐 Muse P4:浏览器完全对齐(CDP broker 单元外 + a11y-tree-only + 确定性分类器)
...
- chv-guest/chv-cdp-broker.py(新):单元外 CDP broker,用户 chv-browser,
独家 chromium.launch(headless=True, args=LAUNCH_ARGS);启动参数白名单
无 --remote-debugging-port、无 devtools;导航前 URL 校验 + 拦截名单;
快照恒带 untrusted_input 与 injection_flags;高风险表单在页时 open
即 ask 入队;观测到导航 POST 自动暂停;命中拦截规则的下载取消 + 暂停
+ ask;全部回包与错误经 sanitize_error + response_leaks 检查。
- chv-guest/chv-browser.py(P2 版重构):改为 broker 客户端,不再直连
Playwright(本文件无 playwright import),保留 URL 校验 + 快照截断
作为第二层防线;暂停状态与 broker 同步。
- chv-guest/chv_browser_guard.py(新):纯 stdlib 共享规则——validate_url、
拦截名单加载/匹配、快照截断、错误消毒(去 HTML、截断 200 字符、凭据形
key=value 与 sk- 形 token 打码)、注入启发式(中英文各 6 条)、表单风险
扫描、下载扫描(可执行扩展名)、文件型 ask 队列(pending/allowed/denied,
与 P3 ApprovalQueue 同语义)、启动参数与回包泄露检查、脚本注入面
禁止清单(FORBIDDEN_PAGE_ATTRS/FORBIDDEN_OPS)。
- chv-guest/browser-blocklist.txt(新):静态拦截名单;首版只有 RFC 2606
.test 自测条目,生产条目由运维构建时填入,无在线更新。
- chv-guest/build.sh/buildinfo.py:P2 三脚本 + P4 三文件纳入镜像与
buildinfo;新增 chv-cdp-broker.service 与 /run/chv/ask-queue tmpfiles。
- docs/chv-muse-p4-gap.md(新):现状 vs Muse 官方要求差距表、改动、
诚实边界、P2 合入约定、真机待验证清单(round 12)。
- docs/chv-production-readiness.md:补 §15(P4 一节;编号合入时若与
P2 的 §15 撞,顺延)。
- cloud/tests/test_chv_muse_p4.py(新,36 项):guard 单元、AST 钉住
禁止属性、假 Playwright broker 测试、假 broker agent 测试、真 Unix
socket 联调、buildinfo/build 干跑断言;含否定测试(evaluate 被拒、
DOM 外泄被拒、DevTools 不可达、私有地址被拒、高风险表单被拦、
注入文本被标注)。
测试:P4 新测试 36/36;全量 cloud 套件 1903 项,两次连续全过
(skipped=8)。附记:第一次全量跑出 1 个失败但输出未保留、后两次
均未复现,疑为时序抖动,未追认。
真机验证未做:排队等 round-11/第三棒释放 100.65.51.33,清单见 gap
表 §5。本地提交,未推未合未部署。
2026-11-06 22:36:56 +00:00
host
81e4eaf4db
feat(chv): 对齐 Muse P6 privsep worker + 确定性安全检查层
...
- cloud/chv/privsep.py(新):Gitea worker 注册表(凭证白名单只含
GITEA_TOKEN)+ 类型化请求/响应(request_id 绑定、64KB 上限)+
Unix socket 客户端(超时/崩溃 -> 类型化失败 WorkerRefusal)+
客户端白名单校验
- cloud/chv/safety.py(新):UntrustedData 来源标记 +
InjectionScanner 确定性规则(block/flag/allow,中英)+
redact_secrets + AuditLogger(只记指纹,不记值)+
audit_inference_request/response
- chv-guest/chv-gitea-worker.py + .service(新):systemd 沙箱化
worker(SO_PEERCRED 只放 root,仓限 ~/workspace,git 只配 authd
helper,绝不持 token;输出先扫描再返回)
- chv-guest/chv-sync-worker-client.py(新):agent 侧薄 CLI
- chv-guest/chv-sync.sh:pull/push/status 有 socket 时走 worker,
否则旧路径 + stderr 警告(过渡兼容)
- cloud/chv/executor.py:_run_guest 前后加推理边界审计钩子
(best-effort)
- docs/chv-muse-p6-gap.md(新):差距表 + 覆盖边界 + 真机待验证清单
- docs/chv-production-readiness.md:§15
- cloud/tests/test_chv_muse_p6.py(新):43 项
测试:新测试 43/43;全量 cloud 套件 1910 OK(skipped=9);mypy
在新增文件上干净(剩余 4 处为基线旧错 executor.py:1396/1401、
marker_tools.py:142,未动)。
真机验证:未做,排队在 round-11 之后,清单见
docs/chv-muse-p6-gap.md §4。
2026-11-06 22:31:54 +00:00
host
25bcd355f8
feat(chv): 对齐 Muse P5 纵深——eBPF 污点传播 + 五档严格能力 + 对话外审批 + 默认策略
...
- taint.py:污点追踪器(登记/污点不可逆/子进程继承/审计)
- ebpf_taint.py:eBPF 程序源码 + 加载器(能力探测 + 降级);
本机实测加载被 seccomp 挡(bpf() EPERM),报 blocked 不冒充
- capabilities.py:五档严格能力(一次/会话/任务/时限/永久,
三元组绑定 + 精确匹配 + 撤销;permanent 默认不签发)
- policy.py:默认策略规则表 + 谨慎度三档(写操作与敏感路径
永远不自动放行,规则变化审计)
- approval_channel.py:对话外审批通道(nonce + 15 分钟过期 +
HMAC,答复一次有效,对话伪造无效)
- sentinel.py 接线:evaluate() 可选接 taint/policy/tier/scope,
不传时行为与 P3 一致;自动放行步骤 + 档位签发回落单次;
Capability 基类属性放宽为 Optional(None = 不限)
- 新测试 61 项;全量 cloud 套件 1958 项 OK(skipped=8)
真机待验证(未做,排队在 round-11 之后):见
docs/chv-muse-p5-gap.md §4
2026-11-06 22:25:55 +00:00
host
ee456e6625
merge(feat-chv-muse-p3): P5 起点——authd 替身凭证 + Sentinel 最小实现
2026-11-06 22:06:23 +00:00
host
73176e135c
feat(chv-muse-round11): 执行器接 nspawn 单元(P2 差距表 §4)
...
客内 host.py 调用改为 chv-cell run -- python3 /app/host.py
--state /home/chv/.codex/host-state.json --codex-home
/home/chv/.codex --sandbox danger-full-access …,其余原参数
原样保留。--sandbox 放全局参数最后(argparse 后胜出),
单元内恒为 danger-full-access,调用方 read-only 不得盖回
bwrap;非单元路径(本地/Docker/冷启动回落)不动。
开关 CHV_CELL_ENABLED:只认 0/1,默认 1 开;非法值
ValueError(_to_switch 同款口径)。关时走原命令,给
lite10 及更早无单元的旧镜像留逃生口。
测试:新 test_chv_muse_round11_cell.py 7 项(开/关 argv、
原参数保留、sandbox 只在单元路径、非法值报错、SSH 层
接线);test_host_command_options_identical_across_executors
显式关单元测三执行器参数全等,断言本身未动。
全量 cloud 套件 2011 OK(skipped=8)。
2026-11-06 21:58:01 +00:00
host
304707b372
merge(chv-muse-round11): 合入 P3 authd 替身凭证 + Sentinel 出口审批 ( a90cf78)
...
冲突解决(3 处,均为并集保留,双方改动无一丢弃):
- cloud/chv/executor.py _copy_config_fields:P1 的 balloon/
vsock/vsock_cid 与 P3 的 sentinel_allow_hosts 合并进同一元组
- cloud/tests/test_chv_arch_maint_fe.py EXPECTED_FIELDS:P1 三字段
+ P3 sentinel_allow_hosts;len 断言 41/39 → 42(并集)
- cloud/chv/config.py 自动合入:P3 sentinel_allow_hosts(网络
片段内)+ P1 _balloon_vsock_fragment 均保留;仅更新
build_chv_config docstring 注明字段集含 P3 字段
2026-11-06 21:36:56 +00:00
host
3209f59cd6
merge(chv-muse-round11): 合入 P2 nspawn 单元 + broker + 浏览器子代理 ( c61484a)
2026-11-06 21:35:53 +00:00
host
55f6d7ad6c
merge(chv-muse-round11): 合入 P1 常驻 VM + 气球 + vsock ( 78098c5)
2026-11-06 21:35:51 +00:00
host
78098c5594
feat(chv-muse-p1): 常驻 VM + WarmPool 扶正 + 气球 + vsock,对齐 Muse
...
每用户一台常驻 VM(暂停态,resume 到 SSH 5 秒内为待验证目标),
池空/失败回落冷启动;CHV 配置加 virtio-balloon + free-page-reporting
与 vsock notify 最小实现(SSH 仍是命令通道与就绪判定)。
新模块 resident_pool.py / vsock.py + 客内 vsock_notify.py;
_config 增加 CHV_RESIDENT_IDLE_MINUTES / CHV_BALLOON / CHV_VSOCK;
worker_adapter 接常驻孤儿清理 facade;ADR-17 差距表见
docs/chv-muse-p1-gap.md。
恢复收尾(分离后回归,见 gap.md §4):VmDeathTest 死亡模拟改杀
实际跑命令的 VM;两处冷路径旧测试显式关常驻;_balloon_vsock_payload
与 listen_notify 拆到 50 行内;resident_pool.py:208 mypy 修掉。
executor.py out 未注解与 marker_tools.py:142 是基线旧错,未动。
测试:全量 cloud 套件 1934 OK(skipped=8);mypy 在改动文件上
干净(仅基线旧错 4 处)。真机验证待第三棒让出 WSL 测试机。
2026-11-06 21:31:48 +00:00
host
a90cf78d84
feat(chv): 对齐 Muse P3 收尾——authd 替身凭证 + Sentinel 出口审批
...
- 新测试 cloud/tests/test_chv_muse_p3.py 30 项:替身过期、真 token
泄露面、SSRF 挡截、deny/ask 路径、authd-seed 拆分、wake 预审、
客内 authd 守护进程、git credential helper 端到端(真 git fill)
- 8 个旧测试按新 authd 行为改写(未删测试、未放宽断言):
GITEA_TOKEN 改走 authd-seed,build_ssh_command 不再 source 进
codex 环境;wake 测试补 Sentinel 白名单 + 假解析器
- 7 处超 50 行函数拆到 50 行内(不改行为);补 authd/sentinel
公共 API 注解,mypy 在改动文件上干净
- 真问题修复:git 默认不把 path 发给 helper,chv-sync boot 加
credential.useHttpPath=true,否则 authd 路径每次都拒绝
- 全量 cloud 套件 1897 项 OK(skipped=8)
真机待验证(未做,等第三棒让出 WSL 测试机):见
docs/chv-muse-p3-gap.md §3.6 清单
2026-11-06 21:21:55 +00:00
host
c61484aa68
feat(chv-guest): 对齐 Muse P2——nspawn 单元 + broker + 浏览器子代理
...
- chv-cell:systemd-nspawn 单命令单元,--private-users=1000:65536
(单元 root → 客机 chv),丢 8 项能力(含 SYS_PTRACE/NET_ADMIN),
syscall 过滤扣 io_uring,遮蔽 /etc/chv 与 playwright,
--network-veth(10.200.0.0/24 + NAT),白名单环境透传
- chv-broker:Unix socket + SO_PEERCRED(uid 范围 + pid ns 对照),
白名单 ping/sync/browser;sync 只调 chv-sync(runuser -u chv)
- chv-browser:单元外独立进程,只暴露 open/snapshot/screenshot/
close/ping,返回无障碍树快照(截断);evaluate/content 拒绝
- build.sh:装 systemd-container/iproute2/iptables,拷入三脚本,
建 chv-browser 用户与两个 systemd 单元;vsock_notify 条件拷入
- buildinfo:内容项加 P2 四项,支持可选 extra_contents
- 测试:cloud/tests/test_chv_muse_p2.py 40 项全过;broker/browser
真实 socket 回路冒烟通过(root 连 broker 被拒)
- 差距表:docs/chv-muse-p2-gap.md;真机验证待测试机空闲(round 11)
本地做,不推、不合、不部署
2026-11-06 20:53:15 +00:00
host
06c3e172fe
fix(chv): restore 路径补 H7 net 校验+登记,seed 暂存文件走 atomic_file
...
restore_vm 此前既不校验 net 冲突、也不登记 net.json:
已登记 VM 的 tap/mac/ip 会被恢复出的 VM 静默复用,且
恢复出的 VM 自身不登记、后来的 wake 也看不到它,两边
都漏判。现与 wake 同款:_validate_restore 在起 VMM 前
校验冲突(net_tap_conflict + vm_failed 审计),
_restore_boot 在 restore 成功后登记 net.json,登记失败
审计 net_registry_write_failed + 拒绝恢复(P2-19 语义,
stop_vm 清半恢复 VM)。
hostkeys.write_seed/_apply_seed_extras 的 meta-data、
user-data、network-config 改走 atomic_file(mkstemp 0600
→ 写 → fsync → rename):user-data 含 host 私钥明文,
直接写 + 事后 chmod 会在 chmod 前以 umask 权限短暂可读;
半截文件本身到不了 ISO(唯一消费者 genisoimage 只在
write_seed 返回后跑),原子写同时堵住权限窗口与半截残留。
回归测试 6 个:restore 冲突拒起/恢复后登记/登记失败
拒起/无 net_json 不登记;seed 走原子写(0600、无 tmp
残留)/写失败不留半截文件。CHV 全套件 395 测试通过。
2026-11-06 19:32:41 +00:00
host
f448ecb74b
docs(chv): L4/M6 取舍定案 + 部署核对清单
...
- L4:保持警告不改硬拒(CHV_NET 是手动直接启动命令透传值,
与 API 的 CHV_NET_JSON 是两条路径;硬拒会断手动运维,
误配代价只是 API 模式忽略 CHV_NET);写清兼容影响与
将来改硬拒的前置条件;部署核对只设 CHV_NET_JSON
- M6:确认声明 + 审计就是本项机制,不假装已校验;部署核对
加人工项(部署记录写明已核对租户数 = 1 与项目名一致,
并复核 disk_reuse_experiment_allowed 审计)
- §11.4 加环境变量核对与残留尾巴审计抽查项
(net_registry_write_failed / dirty_marker_write_failed /
vm_net_registry_delete_failed 任一出现即先修宿主再启用)
2026-11-06 18:41:56 +00:00
host
2ad29eeb1f
feat(chv-guest): M4 Chromium 单独钉死 + /app 收紧为最小集
...
- Chromium 钉死:CHROMIUM_HEADLESS_SHELL_REV(纯数字修订号)
设即钉死,buildinfo.py 校验读回的 ms-playwright 缓存目录名
须恰好是该修订号,否则构建失败;generate/check 的 --verify
也复核;未设时只记录、构建输出明说未钉死,BUILDINFO 记 null
- /app 最小集:build.sh 不再把整个 $REPO_DIR/cloud/ 拷进客机,
只拷 host.py(只用标准库,不依赖 cloud/);REPO_DIR 预检
不再要求 cloud/ 存在
- generate_lockfile.py 只读 BUILDINFO.versions 一事已在 to10 轨
改写,本棒以合成 BUILDINFO 干跑复核(假版本 9.9.9 进 lockfile,
宿主 git 1:2.43.0 未混入)并补钉死复核;真实 lockfile 产出
仍待 V-9 真机构建,不编造版本号
2026-11-06 18:41:56 +00:00
host
c39715659e
fix(chv): P2-20/P2-19/P2-17/P2-18 残留收尾 + NO_PROXY 合并
...
- P2-20:_guest_env_delivered 加专用锁,读写只走
_delivered_secrets/_mark/_clear 三个入口,并发 hammer 测试钉死
- P2-19:_record_net_entries 失败发 net_registry_write_failed
独立审计并返回 False;_boot_vm 见 False 即拒起(wake 随后清半醒 VM)
- P2-17:net.json 删失败发 vm_net_registry_delete_failed 审计;
_write_dirty_marker 失败发 dirty_marker_write_failed 审计并返回
False,stop 不抛的契约不变
- P2-18:新增 cloud/chv/atomic_file.py(mkstemp 随机名 + 文件
fsync + rename + 目录 fsync),net.json/known_hosts/
snapshots.json/pool registry/脏标记/spill 全部走它,固定 .tmp 清零
- H1 附带:NO_PROXY 实测确有覆盖 bug(env 重复赋值以后者为准,
调用方 NO_PROXY 被 egress 的 localhost 值静默覆盖),改为合并
单条发出;egress 已设时调用方代理变量(含小写)一律不发
- 测试:新增 cloud/tests/test_chv_residual.py(23 项),旧 closeup
两处钉死旧语义的测试按新语义更新
2026-11-06 18:41:50 +00:00
host
ba5df980bf
fix(chv): known_hosts 22 端口写裸 host 行,修 provisioned 钉死失效
...
OpenSSH 默认端口只查裸 host 名、非默认端口只查
'[host]:port':known_hosts_line 对 22 端口也写
'[192.168.10.10]:22',ssh 永远匹配不上,报 Host key
verification failed、wake fail-closed 关 VM。keyscan
TOFU 输出裸行,lite9 没暴露。非 22 端口仍用括号形式。
2026-11-06 17:59:53 +00:00
host
4f3a176771
fix(chv): CHV 54 VmConfig 形态——payload.kernel/cmdline 纯字符串 + 磁盘显式 image_type Raw
...
真机 CHV 54.0.0 实测:旧顶层 kernel:{path}/cmdline:{args}
create 时 204 照放、vm.boot 400 'No bootitem provided';
补 payload 后又报 'Image type required for disk'(raw 盘
无魔数、探测失败),磁盘须显式 image_type,枚举原名
Raw(JSON 写小写 raw 报 unknown variant)。
2026-11-06 17:59:53 +00:00
host
5b6514d019
fix(chv): api_client 接受 204 无 Content-Length 响应
...
WSL 真机实测(CHV 54.0.0):vm.create 成功回 204 No Content,
且不带 Content-Length、无体;严格校验(P1-6)把合法成功当
失败拒掉,wake_vm 卡在 vm.create。204/304 按 HTTP 语义体长
恒为 0,不要求长度、不读体(keep-alive 下读会等到超时);
其它状态仍严格(无长度/截断/chunked 均拒绝)。
测试:test_chv_cover100 新增 3 项(204 成功、200 无长度仍拒、
_parse_status)
2026-11-06 17:43:54 +00:00
host
d7cc482ed5
feat(chv-guest): seed 附加项供客机用户与静态网络(wake 路径前置)
...
wake_vm 在 WSL 台架上跑通需要客机身份与网络:镜像本身不建
用户、tap 无 DHCP,缺 users 块的 VM 登不进去、缺 network-config
的 VM 拿不到静态 IP。最小补法(复用 write_seed 机制):
- hostkeys.write_seed 新增 user_data_extra(原样追加进
user-data,供 users: 块)与 network_config(写 seed
network-config 文件,0600);附加项含 runcmd: 即 ValueError
- config _seed_fragment:CHV_SEED_USER_DATA_EXTRA_FILE /
CHV_SEED_NETWORK_CONFIG_FILE(只存路径)
- executor._seed_extras 在 wake 起 VMM 前读入,缺失即
ChvFailure seed_extra_missing;provision_host_key 透传
- README §7 残留更新:guest-env 集成已做
- 测试:test_chv_gitea_sync 新增 5 项(写盘/禁 runcmd/
配置映射/wake 带附加项/缺失 fail-closed)
2026-11-06 16:58:27 +00:00
host
e7f699c62b
feat(chv-guest): Gitea 同步变量经 seed 进 guest-env(执行器集成)
...
- 新增 cloud/chv/gitea_sync.py:6 键白名单,三源合并
(宿主 CHV_GITEA_* < 任务 gitea_sync < extra_env),
必填 4 键缺失即 fail-closed,空即不同步
- ssh_transport:GITEA_TOKEN 进密钥集(argv 拒绝),其余
5 键进 guest-env 集(split_guest_env)
- hostkeys.write_seed:guest_env 与 secret_env 合并写同一
条目,仍无 runcmd、0600
- config:_gitea_fragment 产 gitea_sync_env(函数内 import,
叶子模块顶层只许标准库)
- executor.wake_vm:起 VMM 前合并+校验(gitea_sync_incomplete),
guest-env 随 seed 投递;provision_host_key 透传 guest_env
- worker:_run_attempt 仅对 CHV 执行器把同步变量并进 gateway_env
- 测试:cloud/tests/test_chv_gitea_sync.py 20 项
- 边界:tasks 表无 JSON 列,DB 往返丢任务 gitea_sync;
生产主来源是宿主 CHV_GITEA_* 环境变量
2026-11-06 16:55:32 +00:00
host
67ca0b86cd
fix(chv-guest): seed user-data 不再自带 runcmd,防顶掉镜像钩子
...
sync-test 首轮实测:seed 的 runcmd 整体替换了镜像
/etc/cloud/cloud.cfg.d/99-chv-sync.cfg 的 runcmd(cloud-init
不跨配置类型合并,merge_how 救不了 conf.d),chv-sync
boot 钩子静默不跑、启动 clone 没跑。
- hostkeys.build_seed_user_data 不再发 runcmd;chmod 600
已由 write_files 0600 保证;sshd 重启搬到镜像自己的
runcmd(cloud-final,sshd 首次启动之后)。
- build.sh:99-chv-sync.cfg 的 runcmd 增加 restart ssh
一行(在 chv-sync boot 之前)。
- README §5 同步硬性要求;回归测试 2 项(无 runcmd、
带 secret 仍单 write_files 列表无 runcmd)。
- 针对性 147 项全过(test_chv_to10/gaps/secfix/fix/
arch95plus)。
本地提交,未推未部署。
2026-11-06 16:35:14 +00:00
host
cbd5ab7c0b
fix(chv-guest): 首启缺 key 时才生成 host key(B-23)
...
Minimal 底座 cloud.cfg 不含 ssh 模块,build.sh 又写
ssh_genkeytypes: [] 彻底关掉首启生成:客机无 host key、
sshd -t 失败、ssh.service 连败 5 次,SSH 全程不通(真机
冒烟 131s 未通,console 已到 login、ping 通、tap 正常)。
修正:99-chv-hostkey.cfg 改写首启 bootcmd,只在缺
ed25519 key 时 ssh-keygen -A;ssh_deletekeys: false 保留,
绝不重生成已预置的 per-VM key(bootcmd 跑在 seed
write_files 之前,预置 key 随后覆盖生成值)。README §5
同步修正;新增 BuildScriptTest 回归断言。
2026-11-06 12:05:43 +00:00
host
dcb0824f78
fix(chv-guest): 浏览器装系统路径(B-22)
...
Round 7 构建本身成功,但 BUILDINFO.versions.chromium 为空:
virt-customize 的客机 shell 里 HOME=/,Playwright 默认缓存
~/.cache/ms-playwright 落到根目录 /.cache(实测浏览器在
/.cache/ms-playwright/chromium_headless_shell-1248),而
build.sh 读的是 /root/.cache/ms-playwright(不存在),ls 读回
空文件;buildinfo.py 当时不校验 chromium 非空,静默放过,
事后 check_lockfile / generate --verify 兜底报未覆盖(exit 1)。
改:安装与读回都走 PLAYWRIGHT_BROWSERS_PATH=
/usr/local/share/ms-playwright(agent 运行时也须设同一变量,
否则 chv 用户在家目录找不到浏览器);buildinfo.py 加
playwright_browsers_path 字段,并校验 playwright=1 时
versions.chromium 非空;README 同步。
2026-11-06 10:55:02 +00:00
host
4c8e4eac7b
fix(chv-guest): apt 用 --no-install-recommends(B-21)
...
Round 6 真机构建在 Playwright 步 ENOSPC 失败:--install 默认装
Recommends,python3-pip 连带拉入 python3-dev → gcc/g++/
build-essential 全套,根分区 2.4G 用到 2.2G(95M 空闲),
headless-shell 下到 70% 写满。改走 --run-command apt-get
install --no-install-recommends,必需项显式列出(fontconfig、
openssh-client),两轮 apt 后 apt-get clean + 清 lists 收尾。
buildinfo contents 与 README 同步加 openssh-client/fontconfig。
2026-11-06 10:29:59 +00:00
host
5206dfbc43
fix(chv-guest): gt 用绝对路径调用(B-20)
...
Round 5 真机构建在 gt 安装步失败:install.sh 已装好
/usr/local/bin/gt,但 virt-customize 的客机 sh 里 PATH 不含
/usr/local/bin,同一 --run-command 链里的 gt version 报
command not found,整个 virt-customize 退出非 0。
改两处为 /usr/local/bin/gt version(安装断言 + 版本读回文件)。
install.sh 自身的 SHA256 校验与二进制下载均已通过,不是下载问题。
2026-11-06 10:09:02 +00:00
host
4d09518338
feat(chv-guest): 轻量镜像 + Gitea 双向同步(停全量版,改 Ubuntu Minimal)
...
- build.sh 改轻量:Ubuntu Minimal 底座、apt 精简(git/ssh/cloud-init/
python3/pip/curl/ca-certificates/xz-utils/fonts-wqy-microhei)、
Playwright + chromium-headless-shell、去 B-16 +12G 扩盘;
加 git + gt 1.0.0(官方 install.sh + SHA256 校验,GITEA_CLI_VERSION
钉 1.0.0)与 chv-sync 启动钩子(cloud-init runcmd)
- B-19(新发现):dpkg freeze 的 ${Package} 会被客机 shell 展开
成空,284 行全空白;加反斜杠转义,探针实测已出真实版本
- buildinfo.py:轻量 contents、chromium-headless-shell、gt_version
- generate/check_lockfile.py:gt/chv-sync 声明来源、headless-shell 映射
- chv-sync.sh(新):boot/pull/push/status,分叉/脏树失败关闭,
凭证走 seed 盘 guest-env,不进镜像
- README §1/§2/§3/§4 改轻量口径,新增 §7 Gitea 双向同步
- tests:ChvSyncTest 6 项(本地 bare 仓当远端);针对性测试 144 项全过
2026-11-06 09:47:54 +00:00
host
9e60d5dfaa
fix(chv-guest): B-18 virt-get-kernel -o 是目录不是文件
...
- 第三轮真机构建:virt-customize 全程通过(Playwright 步已过),
随后 virt-get-kernel -a disk.raw -o $OUT/vmlinux 失败;手动
查 --help 确认 -o 是 output directory——旧写法会在 OUT 里
建出 vmlinux 目录,后面的 test -s 文件校验必然失败,即使
下载成功构建也会失败。
- 修复:-o 改为 $OUT,下载 vmlinuz-<ver> 与 initrd.img-<ver>
后把 vmlinuz-* 移为 vmlinux 文件;initrd.img-* 留在 OUT 里
作配套产物(与任务产物清单一致)。
- 同轮里 virt-get-kernel 首跑另报过一次 "file receive
cancelled by daemon",同一盘手动重跑即成功(瞬时故障),
此处失败重跑一次,与 B-05/B-06 重试口径一致。
2026-11-06 09:01:20 +00:00
host
b5e75f156d
fix(chv-guest): B-17 Playwright 安装加 --break-system-packages
...
- 第二轮真机构建实测:单次 virt-customize 在 playwright 步
失败,pip3 install --no-cache-dir playwright 在 Ubuntu 24.04
上报 PEP 668 externally-managed-environment 而拒绝安装;
随后 python3 -m playwright 报 No module named playwright。
此前 PLAYWRIGHT 默认 0,该步从未在默认构建里跑过,缺口
被默认开启暴露出来。
- 修复:playwright 的 pip 安装与第一处 pip 安装同款口径
(--break-system-packages,失败回落无 flag 再试),且只有
pip 成功才跑 python3 -m playwright install --with-deps
chromium(括号分组 + &&,失败即停,不再以 ; 带病续跑)。
- 第二轮中间证据:B-10 步已过(sshd -t 完成、99-chv.conf 与
cloud-init hostkey 配置已写入、客机 /etc/ssh 无残留 host
key;dpkg/pip freeze 已写 876/92 行)。
2026-11-06 08:34:14 +00:00
host
368bccd16e
fix(chv-guest): B-16 真机构建扩根分区(云镜像根分区仅 2.4G 会写满)
...
- 首轮真机构建实测:单次 virt-customize 在 playwright
--with-deps 装 g++/make 时报 No space left on device,
根分区 /dev/sda1 仅 2.4G、已用 97%。
- 修复:qemu-img resize +12G 后 sgdisk 只扩 1 号分区
(起始扇区实测取,不写死;14/15/16 不动),再 guestfish
resize2fs;实测根分区 2.4G→14G、可用 12G、编号仍为 sda1。
- 不用 virt-resize:实测它重写分区表、把根分区从 1 号重编号
为 4 号,而执行器默认 cmdline 是 root=/dev/vda1,重编号后
无法启动。工具检查清单加 sgdisk、guestfish。
2026-11-06 07:59:29 +00:00
host
3b41f864e8
test(chv-guest): 构建脚本测试夹具跟进 B-09 新契约
...
- 假 codex 二进制须报出版本号(codex --version 核对)
- 假仓库改为真 git 仓库,REPO_COMMIT 取其实测短 hash
(旧 test123 非 hex,B-03 格式校验本应拒绝)
- 干跑行补 BUILDINFO.json 字样(断言依赖)
另:79ba56b(并行轨)已把 Playwright 改默认开启、单次
virt-customize、补 fonts-noto-cjk,本提交只补测试与干跑
文案,不动构建逻辑
2026-11-06 15:34:06 +08:00
host
79ba56bd51
feat(chv-guest): Playwright 默认开启、单次 virt-customize、补 fonts-noto-cjk
...
- virt-customize 3 次调用合并为 1 次(VC_ARGS 数组按序执行;
PLAYWRIGHT=0 时仍可显式关掉,freeze 步骤保留兜底)。
- PLAYWRIGHT 默认 0→1:浏览器常驻复用;最终 freeze 在
Playwright 安装之后(B-08),BUILDINFO.versions.pip 含
playwright,chromium 目录名照常记录。
- apt 清单加 fonts-noto-cjk(浏览器 CJK 渲染字体,不是 LaTeX;
xelatex 仍不装)。
- 针对性测试:to10+gaps+secfix 94 项,91 过;3 项失败为
7f18c2d 已有 fixture 陈旧(REPO_COMMIT=test123 非 hex),
与本次改动无关,改前改后一致。
2026-11-06 07:25:15 +00:00
host
7f18c2d13b
fix(chv-guest): 客机镜像构建缺口补齐(B-02/B-03/B-04/B-05/B-06/B-07/B-08/B-09/B-10/B-13/B-15)
...
- B-10(实测):virt-customize chroot 里 sshd -t 必败,双因:
无 host key(exit 1)+ 缺 /run/sshd(exit 255);修为
mkdir -p /run/sshd + ssh-keygen -A 临时生成,断言通过后
立删临时 key,镜像仍不带 host key(已在 WSL 真机预演验证)
- B-08:Playwright 装在第二次定制,须重写 pip freeze 否则
BUILDINFO 里无 playwright;Chromium 以 ms-playwright 缓存
目录名记录进 guest-versions-chromium.txt
- B-09:codex --version 须含 CODEX_VERSION;REPO_COMMIT 须
等于 HEAD 短 hash;工作树脏即拒绝构建
- B-02/B-13:BUILDINFO 生成抽成 buildinfo.py(可单元测试),
补 disk.raw/vmlinux sha256+大小、ubuntu 镜像 sha、cmdline、
playwright 开关、image_sha256 字段
- generate_lockfile.py 改写:版本唯一来源改为
BUILDINFO.versions(客机读回),codex 三件套取
codex_version、/app/host.py 取 repo_commit、chromium 取
versions.chromium;不再查构建宿主 dpkg/pip(旧方法不成立)
- check_lockfile.py 补强:条目格式、contents 全覆盖、冻结
清单双向比对
- B-03/B-04 输入格式校验、B-05 curl 重试、B-06 哈希不符
删文件重下、B-07 磁盘预检、B-15 set -euo pipefail
- 同步改 test_chv_to10.py:generate 不再查宿主,改断言客机
版本来源 + 不回落宿主
2026-11-06 15:13:23 +08:00
host
8c8d62f70d
test(chv): 补齐 chv 模块剩余覆盖到 100%(生产与实验分开计分)
2026-11-01 07:00:21 +00:00
host
e718f0f326
test(chv): 修复 isWorkerAlive 边界测试抖动(精确边界改确定性字段测)
2026-11-01 00:44:12 +08:00
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
host
2f3ff8b3ec
feat-chv-to10:往 10 分方向提升(类型/lint 清零、worker 适配抽取、审计落盘、lockfile 生成脚本、前端四态与统一文案、就绪清单 §13)
2026-10-31 10:20:42 +00:00
host
df8c64bd64
feat(chv): 架构/可维护性/前端只读侧推进——生产实验分离、配置片段化、VM 只读展示
...
架构:WarmPool 从 cloud/chv/pool.py 移到 experimental_pool.py,
生产残留清理彻底分文件到 cloud/chv/orphans.py(facade 直接读
registry 文件清理,不构造池、不碰 prewarm/acquire/release);
cloud/chv 与 cloud/sandbox 不再导出 WarmPool,旧路径一律
ImportError(CHV 未合并、无生产用户,兼容保留已无保留理由);
worker 改走 orphans facade,不再持有 _warm_pool;#215 对齐从
接口形状推进到 REPLACEMENT_POINTS 替换清单(R1/R2 可机械替换、
R3 永不替换,#215 模块当前不存在由测试钉住)。
可维护性:build_chv_config 拆成 base/ssh/network/quota/disk/
timeout 六片段(组装只做 dict 合并,键冲突即报错;38 字段集
与取值不变,单项非法报错文案逐字一致);ADR-12 模块职责图
与禁 import 清单(AST 钉住);cloud/chv/ 公开 API 全量类型
标注、无 Any 逃逸,并修正三处旧标注错误;死代码扫一遍
(删实验池已无调用的 _quarantine 委托与未用 _LOGGER)。
前端(只读侧,不做控制按钮):chv.ts 新增纯逻辑谓词与文案
(执行器精确匹配、附件守卫、VM 状态文案、列表徽标);列表
行新增 VM 已报告死亡徽标;详情对全部 CHV 任务显示 VM 行
(已报告死亡/未报告死亡,不猜 live);WorkersSection 与成本
卡沿用已有数据,不新开池管理/成本页;服务端未新增第二个
生命周期字段(持久化事实只有三项,chv_vm_dead 已是完整派生),
只把派生抽成 _chv_vm_dead_from_row 并补 goal 回落形态测试。
2026-10-31 06:55:26 +00:00
host
42de20da68
feat(chv): 架构与代码质量 9.5+ 提升——长函数清零、WarmPool facade、#215 对齐、审计计数、只读 VM 字段、ADR-8~11
2026-10-31 06:20:12 +00:00
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
host
baf26beb78
feat(chv): 安全审计修复 High/Medium/Low(堆叠于 #239)
...
审计报告 ~/workspace/chv-security-audit/REPORT.md(No-Go,
Critical 0 / High 7 / Medium 8 / Low 5)代码层修复,mock
测试覆盖,真机动态验证一律未做、只列清单(见
docs/chv-production-readiness.md §11)。
High:
- H1 egress 代码门:代理地址校验、直连显式允许+审计、
每 VM 独立 tap/mac/ip 校验、net 字段白名单;宿主防火墙
列为部署清单,代码门+防火墙缺一不可。
- H2 网关 key 移出 argv:provisioned seed 盘客内文件
/etc/chv/guest-env(0600)投递,传输层密钥进 argv 直接
ValueError;keyscan 模式密钥投递 fail-closed。
- H3 任务盘删除:stop/recycle/cleanup 删 disk.raw(保留期
0)+ 残留盘 GC,删失败审计+脏标记。
- H4 默认值改 provisioned:keyscan 只作显式 opt-in。
- H5 seed.iso 生成即 0600;宿主私钥 seed 盘建好后即删;
崩溃残留扫描 cleanup_stale_secrets。
- H6 state_dir 默认出 /tmp(~/.local/share/.../chv-vms,
preflight 保 0700);api-socket 组/其它可写即 fail-fast。
- H7 tap 隔离校验:net.json 登记+stop 释放,共享即拒绝审计。
Medium:M1 shlex 远程转义;M2 清理失败即拒起(脏标记);
M3 配额默认 50GB + 快照数/总量/保留期上限;M4 SHA256 必填
+ BUILDINFO versions 实测记录(事前 lockfile 列清单);
M5 host key/ preflight/失败审计补齐;M6 reuse 须声明单租户
项目;M7 容量计数只认连通 socket;M8 sshd 加固进 build.sh
断言。Low:L1 链接不跟随;L2 路径白名单;L3 失败审计;
L4 双变量警告+字段白名单;L5 预热盘/任务盘对应关系定义。
旧测试:实验室默认值与生产默认值区分标注;行为已变的旧
测试按新语义更新(容量死 socket、快照白名单、磁盘路径
白名单、网关 argv、reuse 租户声明)。
测试:新 test_chv_secfix 39 项;旧 117 项 + 2 项新增断言 =
158 项;worker 相关 129 项;前端 vitest 9 项;cloud 全量
1588 项(skipped 4)。
2026-10-31 03:02:10 +00:00
host
003ea357f9
feat(console): CHV production-grade frontend — worker availability, attachment guard, queue hint, build:console fix, vitest
2026-10-31 02:35:38 +00:00
host
036323e620
feat(console): CHV executor option in dispatch/env selectors + experimental note in detail/list
...
- DispatchSection: add cloud-hypervisor option (labelled experimental,
default off); default stays docker; hint states a KVM-host CHV worker
must claim the task (otherwise it stays queued; attachments are
rejected by the backend at creation) and that the frontend only passes
the executor value through, never bypassing the backend allowlist.
- EnvSection: same option, because the backend env-create allowlist
(local/docker/cloud-hypervisor) does allow it; note states env
allowlist excludes cloud.
- TaskListSection: add cloud-hypervisor to the executor filter so CHV
tasks are findable; list rows already showed executor.
- TaskDetailPanel: pure display note for cloud-hypervisor tasks
(experimental, default off, no VM controls); detail already showed
executor from the task API.
- README: document the CHV console entry, experimental marking, and
verbatim backend-error display.
- Rebuilt cloud/console.html from src (tsc + vite single-file build);
no backend change: executor is already returned by _task_to_dict.
2026-10-31 02:25:21 +00:00
host
445376743d
feat: CHV 审核修复 P2(范围恢复为全做)
...
P2-1:preflight reuse/CPU/内存校验块小提取为
_preflight_config_checks(纯移动,深耦合处如实停)。
P2-2:build_vm_command 降级为私有 _build_vm_command;
Docker goal 内联解析顶部加正典分叉说明 + 同步检查清单。
P2-3:gaps grep 文本断言改成真实 Worker._run_attempt
行为断言。P2-4:README/build.sh 口径对齐(章节顺序、
BUILDINFO 名字列表、Node.js 不装写实)。P2-5:stop_vm
删除失败记审计。P2-6:CPU/内存校验统一进 preflight。
测试:原 84 + 新增 33 = 117 项,mock,无真 VM。
2026-10-31 02:01:03 +00:00
host
9771ed9e8c
feat: CHV 审核修复(P0+P1,堆叠于 #230)
...
P0:seed 磁盘 CIDATA ISO 挂进 VmConfig 第二块只读盘;
restore provisioned 下复用钉死 known_hosts、缺失 fail-fast
绝不 keyscan;preflight 拦截 CHV_DISK_MODE=reuse(显式
实验二次确认 + 审计放行);SSH 目标选客机 IP 方案(显式
host > net 静态 ip > 显式转发宣称回环,三者皆无 fail-fast)。
P1:网关 extra_env 经 SSH env 前缀注入、worker 守卫收窄到
Local/CHV;取消/清理/看门狗接 CHV 通用路径;WarmPool
acquire 内 resume;容量门持久化计数;磁盘配额总量+余量
与已存在磁盘校验重拷;API 按 Content-Length 验完整性;
快照 file:// 验落盘再 shutdown;execute 死端口归类
vm_not_running。
P2 全部排除未做(用户范围收窄令,留待以后一轨)。
测试:原 84 + 新增 29 = 113 项,mock,无真 VM。
2026-10-31 01:54:13 +00:00
host
22b83f118a
feat: CHV gap fill — worker breakpoint wiring, pool reconcile, per-VM host keys, egress validation, guest build script
...
Stack: #216 -> #221 -> this. Worker breakpoint branch now calls any
executor providing goal_resume_breakpoint_task (Local keeps its
original path, gateway tasks still loud-fail); WarmPool
reconcile_orphans is called on CHV worker startup and close with
audit-on-failure; per-VM SSH host keys are provisioned before VMM
start via cloud-init NoCloud seed (keyscan kept only as weak
fallback, CHV_HOST_KEY_MODE=provisioned|keyscan); CHV_NET_JSON is
validated in preflight and explicit direct egress is audited;
chv-guest/build.sh is now real steps with --dry-run and fails fast
without /dev/kvm. Tests: new test_chv_gaps.py (18), cloud full
1514 OK (skipped=4). No real VM verification: no KVM host.
2026-10-31 01:30:52 +00:00
host
fde7bf4c3e
feat: CHV 执行器优化(拆模块/去重复/SSH 钉死/池持久化/中途死亡分类)
...
- 拆模块:CHV 从 cloud/sandbox.py 巨类拆到 cloud/chv/(executor/
pool/config/api_client/ssh_transport/disk/errors),sandbox 只留
兼容 re-export,旧导入路径与新路径是同一对象
- 去重复:goal 解析、host 顶层参数、runner 超时抽成共享 helper,
Local 与 CHV 在矩阵输入下结论全等(Docker goal-resume 变体
有意保留内联版,见 PR 描述)
- 安全:SSH host key 按 VM 钉死(state_dir/<vm>/known_hosts,
ssh-keyscan 首次捕获 TOFU),废除 no + /dev/null;CHV_SSH_USER
空串与 CHV_SSH_PORT 越界直接拒绝,不静默 fallback
- execute 语义:只读已运行 VM,未运行报 vm_not_running,不为
status 起 VM
- 预热池:registry 落盘、重启载入只当孤儿、reconcile 清理、
损坏 quarantine;条目仍一次性,绝不复用脏 VM
- 长任务:VM 中途死亡判 interrupted(断点可续跑);中途心跳
经评估不做(无客内进度信号可采)
- #215 未合并:只列复用清单,不复制模块
测试:原 42 项 + 新 24 项全过;相关旧套件与 cloud 全量 1496 项
全过(skipped=4)。验证仍是 mock + 干跑 + 单元测试,未做真机、
压测、安全审计;堆叠于 #216 之上,base 为 feat-cloud-hypervisor。
2026-10-30 19:45:33 +00:00
host
c371bbdf1e
feat: Cloud Hypervisor 执行器生产级 v1(cloud-hypervisor)
...
单任务单 VM:API 唤醒(preflight→vmm.ping→vm.create→vm.boot→SSH 就绪)、
暂停/快照/休眠等价/关闭/回收、预热快照池、每任务磁盘 copy、容量与磁盘配额门、
受控 egress fail-closed、VM 事件审计与分类失败;worker/server/autoscaler 接线
(executor=cloud-hypervisor,任务内 LLM 不可自选);默认关闭,不进生产路由。
未做真实 VM 验证:生产主机与本 VM 均无 /dev/kvm、无嵌套虚拟化,验证为 mock +
干跑命令 + 单元测试;真 VM、快照恢复、压测、安全审计见
docs/chv-production-readiness.md。CI 账单故障仍是硬门禁,本提交只到 PR OPEN。
2026-10-30 18:54:16 +00:00
host
4428a721a6
feat: auto-resume platform-interrupted non-goal tasks
...
Deploy restarts kill running tasks: the worker marks them
interrupted (worker_shutdown on graceful exit, sweep on stale
reclaim), and auto_resume_interrupted used to accept goal tasks
only, so every non-goal task killed by a deploy stayed
interrupted forever unless a human retried it (the 2026-10-30
demo task died this way).
Now worker_shutdown/sweep interruptions are re-queued for
non-goal tasks too: the platform killed the task, so the
platform re-queues it. The re-queue is a fresh run, not a
breakpoint resume: goal_resume_pending is forced to 0 and any
stale resume_message is cleared, so the new run cannot be
hijacked by the goal-resume path or an old continue message;
files in the same worktree persist. All existing guards stay:
user pause, coordinator orphans, quota (still goal-only),
backoff, the 3-strike stall guard (non-goal tasks have no
checkpoints, so each platform re-queue counts as no-progress),
and the auto_resume_max cap. Other non-goal reasons (NULL,
quota, user cancel) still do not auto-resume.
2026-10-30 15:39:55 +08:00
host
2d644f901b
feat(console): automation panel edit and richer list
...
- AutomationPanel rows now show title, prompt content (160-char preview with expand/collapse), repo_url, last/next run, run_once badge and cancelled time.
- Active automations get an inline edit form (name/prompt/interval/repo) that PATCHes only changed fields via the existing automation_update endpoint; backend semantics unchanged (no last_run_at reset, cancelled stays terminal).
- Rebuilt cloud/console.html with tsc + vite (build green); automation python tests 18/18 OK.
2026-10-30 15:31:21 +08:00