Muse
|
39c51b7bf2
|
feat(chv-hybrid-c): autoscaler 池目标数 + 回收同步门 + 审计事件目录
- autoscaler: desired_workers += pool_target(W=2 台/宿主,
pool_target_for_hosts);Autoscaler/CLI 支持 --pool-target /
--online-hosts;L1 其余语义(30s 轮、scale up fast/down slow、
fail-closed、veto、LIFO)原样复用,L2 不自动加主机
- executor: recycle_vm/recycle_persistent_vm 前加 Gitea 同步门
(chv-sync push 失败即 state/status=sync_failed、VM 不回收、
记 vm_recycle_sync_failed 审计);未配同步/VM 已死走旧路径
- 新增 cloud/chv/hybrid_events.py:9 个设计事件名一字不差,
全部必填 host_id、密钥字段名拒绝入目录
- orphans facade 已存在且复用 registry/orphan 语义,不动
experimental_pool(wired_to_dispatch 恒 False)
- 测试:cloud/tests/test_chv_hybrid_c.py 32 项;全量 4611 项
0 失败 0 错误 15 skipped
|
2026-11-08 21:24:46 +00:00 |
|
host
|
3cdfd0f79e
|
fix(ci): runner 补 py3-yaml/py3-pillow/procps
ci / test (push) Successful in 37m11s
CI run 198 红:cloud 套件 5 失败 + 12 错误,根因全是
runner 环境缺包(本地全绿):
- No module named 'yaml':test_chv_gaps /
test_chv_gitea_sync 模块导入失败 + test_chv_v3_fixes
GuestEnvV4Test 两例(4 错误)。
- No module named 'PIL':阶段 4 diff_shot 逐像素裁剪
走 Pillow,ComputeDiffTest 5 错误 + DiffShotTest
3 错误 + 4 失败(Counters/DiffShot/ForbiddenOps
皆为缺 PIL 后的下游失败)。
- busybox ps 不支持 --ppid:阶段 5 ExecdKillGroupTest
用 ps --ppid 找组内子 sleep,10 秒等不到而失败。
|
2026-11-08 11:13:15 +00:00 |
|
host
|
738982ce10
|
fix: rebase 合入修复(#215 已合并 + 执行器文案 + server 重导出)
ci / test (push) Failing after 30m37s
- cloud/server.py:重导出 handler_support._chv_vm_dead_from_row,
沿用 main 的 split 重导出约定(test_chv_arch_maint_fe 从
cloud.server 导入该名)。
- cloud/tests/test_coverage85_server2.py:执行器非法值文案期望
跟随分支行为(valid 列表已含 cloud-hypervisor,main 新增
的该用例原先按旧文案断言)。
- cloud/chv/compat215.py + test_chv_arch_maint_fe.py:#215
(facc2a2)已合入 main,四模块已存在,替换清单本身未动;
钉住项由“模块不存在”翻为“模块已存在”,tmpfs_isolated
扫描白名单加 canonical 定义 cloud/sandbox_policy.py。
R1/R2 替换本身未做(属合并后工作):语义已核对,
gates.resolve_inside 与本地版逐行一致,
sandbox_policy.tmpfs_isolated 对 cloud-hypervisor
同样返回 False,未触发 R2 的停手条件。
|
2026-11-08 10:22:51 +00:00 |
|
host
|
dba5620e29
|
fix(chv): execd codex 白名单补 SUB2API_/XCM_ 前缀,网关 key 得进单元
chv-cell 的 FORWARD_ENV_ALLOWLIST 早已接受 SUB2API_API_KEY /
SUB2API_BASE_URL / XCM_API_KEY,但 execd _codex_env 的前缀白名单
没有这两项,调用方传了也被丢弃,单元内 codex 永远拿不到网关
key(假值探针实证:三者全被丢弃,只有 OPENAI_* 能通过)。
host.py sub2api provider 直读进程 env,缺 key 即调不到模型。
补前缀 + 扩展 test_codex_env_allowlist;GITEA_TOKEN 仍被丢弃。
真实 turn 仍待安全测试 key(另见 KEY-PIPELINE 报告),本次
只修链路不断言 live。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
6466ea6024
|
feat(chv): 阶段 5 多会话并行——具名会话独立 context + storage-state 落盘 + execd 组杀
|
2026-11-08 09:45:00 +00:00 |
|
host
|
f723eb8a88
|
feat(chv): 阶段 4 截图三级管线——a11y 角色解析 + diff_shot 逐像素裁剪 + verify_shot 全屏校验
- snapshot 纯字符串解析 a11y 角色计数/interactive/字符数/hash
(不跑 JS、不取原始 DOM,禁 op 保持拒绝);status 带计数器
与 verify_share
- diff_shot:PNG 全帧 Pillow 逐像素比对(单通道阈值 10),
无变化 changed:false size 0;有变化 bbox 外扩 8px、钳制视口、
宽高下限 32px,再 clip 截 JPEG q70;Pillow 缺失如实报错并
指引回落 screenshot 全帧;open 不清基线(跨页局部差分靠它)
- verify_shot:全帧 JPEG q70,只用于检查点
- build.sh 与 playwright 同批 pip 装 pillow(只加 pillow);
buildinfo BASE_CONTENTS 登记 pillow(pip 名覆盖)
- 单测 cloud/tests/test_chv_opt_stage4.py:31 项(bbox 纯函数、
a11y 解析、计数器、Pillow 缺失回落、禁 op、lockfile 往返)
|
2026-11-08 09:45:00 +00:00 |
|
host
|
5dc75128f8
|
fix(chv): 数据盘挂载升格为 oneshot 服务,浏览器启动时重解析 profile
|
2026-11-08 09:45:00 +00:00 |
|
host
|
c7ffb1fe6f
|
fix(chv): 浏览器单元去掉成环的 After=cloud-final
cloud-final 自己 After=multi-user.target,与浏览器的
Before=multi-user.target(WantedBy 隐含)成环,systemd 启动时
直接删掉浏览器任务:构建 #9 驱动实证服务从未启动(NRestarts=0、
无日志,journal 明言 Job deleted to break ordering cycle),
构建 #8 同款问题一直被手动 restart 掩盖。改排在数据盘挂载单元
home-chv-workspace.mount 之后(真依赖);单测钉死不再出现
cloud-final。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
0100ffe207
|
fix(chv): 完整 Chromium 检测认 CFT 布局 chrome-linux64
Playwright 1.64.1 下的 chrome-linux64.zip 解压为 chrome-linux64/
chrome,旧检查只认 chrome-linux/chrome:数据盘上 403M 完整版
已装好(含 DEPENDENCIES_VALIDATED)仍报未安装、mount_full 误
回落(2026-11-08 构建 #8 驱动实证)。两种布局都认;驱动安装
步在仍未装好时重试一次(客机慢出口 CDN 30 秒超时是抖动)。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
9d986becaf
|
feat(chv): 完整 Chromium 改装数据盘
根盘只剩 ~600MB,playwright install chromium 装根盘 109 秒后
ENOSPC 失败(2026-11-08 构建 #8 驱动实证)。完整版改装数据盘
/home/chv/workspace/.chv-browsers(9.3G 空闲),仍不 bake 进
base、按需;full 引擎启动时直接传 executable_path(channel 与
executable_path 互斥,且驱动进程启动时才读 env,运行中改 env
无效);status 增 full_browsers_dir,mount 失败报错给数据盘
安装命令。驱动的安装步同步改数据盘并 chown 给 chv-browser。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
435664925e
|
fix(chv): cell 不再把 /run/chv 的组改回 root
chv-cell 每次跑 cell 都 _ensure_bind_source(BROKER_DIR, uid=0,
gid=0),把 /run/chv 的组改回 root,抹掉 tmpfiles 的 chv-browser
组;之后 chv-browser 重启时 os.remove(browser.sock) 报
Permission denied、无限 crash-loop(构建 #8 客机 62 次重启才
被发现,03:42 驱动两次跑 cell 正好在补丁后、重启前)。改:组
改取 chv-browser 的 gid(不存在回落 0);serve() 删 socket
失败时报错说清修法,不再只剩裸 traceback。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
0bfb00ab1b
|
fix(chv): 快照改走 page.aria_snapshot()
Playwright 1.64.1 已移除 page.accessibility,真实快照一路报
AttributeError(P2 假实现用的旧 API,单测一直没抓到;2026-11-08
构建 #8 驱动 live 抓到)。新版 aria_snapshot() 返回字符串,
超 64KB 截断;旧版 accessibility.snapshot()(dict)只作回落。
驱动的 a11y 断言接受 str 或 dict。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
7361b0654f
|
fix(chv): _load_playwright 须返回 sync_playwright() 实例
返回函数本身则无 __enter__,真实启动路径从未跑通过(P2 假实现
掩盖;2026-11-08 构建 #8 驱动 live 抓到)。回归测试钉死该契约。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
eb495892e1
|
fix(chv): 阶段 3 live 根因——浏览器 socket 与数据盘 profile 的两处权限
- /run/chv 0755 root:root 时 chv-browser 建 browser.sock 报
PermissionError、服务无限 crash-loop(P2 遗留,阶段 2 从未验
过 browser.sock):tmpfiles 改 0775 root:chv-browser。
- /home/chv 默认 0750,chv-browser 穿不过家目录,ismount 判假、
profile 静默回落本机盘:chv-data-mount 挂载成功后 chmod 0751
/home/chv(只放行穿过,不放行列表)。
- 驱动:等 cloud-init done + 四服务 active 再验浏览器。
- 回归 97 项全过(新增 2 项接线断言)。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
1188e4b000
|
feat(chv): 阶段 3 浏览器服务化——持久 profile + CDP + 多会话 + JPEG 截图 + 双浏览器
- chv-browser:launch_persistent_context,profile 固定数据盘
/home/chv/workspace/.chv-browser-profile(未挂载回落本机盘并明说);
CDP --remote-debugging-port 9222(op cdp 返回 webSocketDebuggerUrl);
多会话每会话一页;截图 JPEG q70、viewport 宽封顶 1280、diff_only
整帧相同跳过;mount_full/unmount_full 切 full/shell 引擎,full
未装或起不来回落 shell 并明说。
- chv-data-mount:挂载后预建 profile 目录(chv-browser:chv-browser 0700)。
- build.sh:chv-browser 单元 Restart=always、After cloud-final.service。
- chv-execd:codex 环境白名单加 CHV_BROWSER_ 前缀。
- 测试:新增 test_chv_opt_stage3.py(20 项);P2 假实现改为持久
上下文 + JPEG;stage2 的 Restart=always 计数 3→4。
- 全量回归 2032 过 skipped=8。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
6a65c94254
|
fix(chv): execd 单元 KillMode=process(构建 #6 驱动实证)
缺 KillMode 时 systemd 默认 control-group,kill -9 execd 主进程
后重启会 SIGTERM 整个 cgroup,sleep 任务同 pid 存活的要求被破、
新 execd 认领时 pid 已死记 unknown,驱动 kill 相断言失败。
KillMode=process 只信号主进程,任务在重启后同 pid 存活认领;
stop 仍干净停 daemon 本身。回归测试
BuildWiringTest.test_build_sh_execd_unit_keeps_tasks_on_restart。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
42adbd047f
|
fix(chv): 79-chv-cell.network 改回 root:root 644(构建 #5 驱动实证)
virt-customize --copy-in 保留构建宿主 uid/mode,79 文件在客机
落盘成 chv:chv 640,networkd 不认它、改配 80-container-ve.network、
刷掉 10.200.0.1,cell _iface_has_ip 复核失败、codex --help rc=1。
构建时显式 chown root:root + chmod 644 并断言属主与权限;
回归测试 BuildWiringTest.test_build_sh_fixes_cell_network_file_owner。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
1cbaf7c1d5
|
chv-cell: networkd 不管 ve + 单元内 DNS 修复
- systemd-networkd(/usr/lib 80-container-ve.network,匹配 ve-*)
会在 veth 建好后几秒内刷掉静态 10.200.0.1、改 DHCP/链路本地,
致单元网关不可达、TCP/UDP 全灭(FORWARD/NAT 计数器恒 0;
早先一次 curl 403 是刷掉前的窗口期偶发)。修法:镜像内置
/etc/systemd/network/79-chv-cell.network(Unmanaged=yes),
须排在 80 之前(99 会被 80 抢走,已实测);build.sh copy-in
+ 校验、BASE_CONTENTS 与两处 DECLARED_SOURCES 登记。
- run_cell 配网后复核 ve 上确有 10.200.0.1(_iface_has_ip),
不见即大声失败、不跑无网单元(第二道防线)。
- 单元内 DNS:/etc/resolv.conf 是 127.0.0.53 stub,单元独立
netns 里自己的 lo 上没有 resolver;把上游
/run/systemd/resolve/resolv.conf 绑到 /etc/resolv.conf
(解析 symlink 后挂真实目标)。live 验证:DNS-UDP-OK、
getaddrinfo 解析成功、curl https://gitea.tose.top 200。
- 单测:CellResolvTest + _iface_has_ip 真实 lo 断言 + 规约
dns_resolv_conf 字段;P2 + 阶段 2 共 74 项全过。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
4b5f2f124f
|
chv-cell: ns 内 setuid 修复 + 单元内 DNS(上游 resolv.conf 绑定)
- 中间进程不再先 setuid(1000) 再 unshare:真机对照实测那样
后续 unshare(CLONE_NEWNS) 得 EPERM;改为保持 root 外层身份
unshare(creator caps 在),孙进程在 ns 内 setgid/setuid(0)
切到内 0(映射到外层 chv 1000)。
- 单元内 DNS:客机 /etc/resolv.conf 是 127.0.0.53 stub,单元
独立 netns 里自己的 lo 上没有 resolver;把上游
/run/systemd/resolve/resolv.conf 绑到 /etc/resolv.conf
(解析 symlink 后挂真实目标),只在单元私有 mount ns 里。
- 单测:CellResolvTest(bind 参数/symlink 解析/缺失回落)
+ 规约 dns_resolv_conf 字段;P2 + 阶段 2 共 73 项全过。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
afbb7772c5
|
fix(chv): cell 映射改由父进程写,中间进程先 setuid(1000)
两个真机教训(2026-11-07):
- 子进程自己写不进 uid_map:unshare 后 euid 变 overflow,
连 /proc/self/uid_map 的 open 都 EPERM——改由父进程
(仍在初始 ns 的 root)经 /proc/<pid>/uid_map 写。
- 映射按外层 uid 翻译:中间进程外层是 root(0) 时
“0 1000 1” 盖不住它、新 ns 里仍是 overflow——中间进程
须先 setgroups/setgid/setuid(1000) 再 unshare(实测
chv 身份 unshare 在客机上可行,AppArmor 不挡)。
另:中间进程异常加 traceback(调试用);userns 单测改测
父写映射真实路径(映射行按 split 比,内核会多空格对齐)。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
a2a5624736
|
fix(chv): cell 后端由 nspawn 改为纯 stdlib userns 启动器
nspawn --directory=/ 在 systemd 255.4 上走不通(2026-11-07 真机
实测,修一个冒一个):裸 --no-new-privileges 被当成要值吞掉
下一个参数;--directory=/ 被根目录检查挡住;--volatile=state
又要 /run/host/os-release 挂载点与空 /dev(--tmpfs=/dev 不
生效)。cell 从未 live 跑通过(阶段 1 只测参数表纯函数)。
bwrap 作 chv 被 AppArmor userns 门挡住,newuidmap 客机未装。
新后端(同文件、同 CLI、同调用方):root 起进程,中间进程
unshare 用户 ns 并自己写 uid_map/gid_map(内 0 → 外 chv
1000),再进 mount/pid/net ns、挂 fresh /proc、/tmp tmpfs、
遮蔽敏感路径(目录盖 tmpfs、文件绑 /dev/null)、设
no_new_privileges + seccomp(禁 io_uring 三件套)+ 丢
capability,最后 exec payload;父进程配 veth/NAT、等退出码、
清 NAT。veth/NAT/nsenter 流程与旧版一致,seccomp BPF 与
capability 语义与 P2 设计一致。无新依赖、无 sysctl 改动。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
42b295fc71
|
fix(chv): 阶段 2 syncd 改走 systemd RuntimeDirectory=/run/chv-syncd
tmpfiles 行 d /run/chv/syncd 0755 chv chv 没用:tmpfiles-setup
跑在 cloud-init 建 chv 用户之前,属主解析失败整行被跳过,
客内 /run/chv/syncd 根本不存在(2026-11-07 真机实测:镜像
里有这行、目录没有,syncd 反复退出、restart counter 57)。
改走单元 RuntimeDirectory=chv-syncd(服务启动时由 systemd
按服务用户建目录,不依赖启动时序);状态写失败改为记日志
不杀进程;daemon 与驱动的 syncd 路径同步改到
/run/chv-syncd/。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
8013431f63
|
fix(chv): 阶段 2 syncd 写路径改到 chv 所有的 /run/chv/syncd/ 子目录
/run/chv 是 0755 root:root,chv 身份的 syncd 写不进状态文件
与 socket,_atomic_write 抛错致进程反复退出、systemctl 长期
activating(2026-11-07 真机实测)。socket 与状态文件改到
tmpfiles 预建的 /run/chv/syncd/(0755 chv:chv,与 chv-browser
的 shots 同款);daemon 的 sync 摘要读同一路径;驱动的
syncd socket 路径与 ls 检查同步更新;另修驱动 SSH poller
线程残留(daemon=True + wake 失败也 set 事件)。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
9d77ae55a7
|
feat(chv): 阶段 2 客机运行时三分 daemon/execd/syncd + restore 留 seed.iso + tap 退避
- 客机三分(chv-guest/chv-daemon.py、chv-execd.py、chv-syncd.py,
仅标准库;systemd Restart=always;build.sh 拷入 + 单元 + enable;
buildinfo/check/generate lockfile 登记):
daemon=心跳/资源上报/快照配合(prepare-snapshot 问 execd,
有运行中任务或联系不上即拒绝);execd=shell/文件读写/codex
托管(chv-cell 起 host.py,setsid 脱离,任务登记落盘,
重启按 pid 认领;SO_PEERCRED 只认 uid 0/1000;codex env
白名单);syncd=常驻循环只调 chv-sync pull/push,规则一条
不改(先 pull --ff-only 再 push,分叉即停、不 --force、
不 rebase;仓不存在记 needs-boot 不擅自 clone)。
host.py 仍是唯一任务/codex 引擎,broker/browser/cell 分工
不变,不另起第二套 agent。
- 阶段 1 遗留修复:restore_vm 失败路径 stop_vm(keep_disk=True),
seed.iso 与任务盘都留,重试有输入;vm.boot/restore 的 tap
触点遇 Resource busy 等 tap 空闲后重试一次(_wait_tap_idle
看 ip link state,_ch_remote 报错带 stderr 尾巴以便识别);
诊断不用 pgrep -x(15 字符上限)。
- 单测 cloud/tests/test_chv_opt_stage2.py 25 项;P2 干跑夹具
与 enable 行断言随构建接线更新。
- 全量 cloud/tests 2001 全过(skipped=8)。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
f809014bef
|
feat(chv): 阶段 1 数据盘与 tenant 标记同 overlay 解耦(copy 也供)
真机根因(2026-11-07,CHV v54 三变体实证):vm.boot 对任何
带 backing file 的 qcow2 都报 Maximum disk nesting depth
exceeded——overlay-only 与 overlay-rawbase 均 500,base 直接
启动(reuse)22.5 秒成功,数据盘与压缩均已排除。overlay 在
本 VMM 上不可用,持久 VM 须能在 copy 模式下跑。
- _provision_task_disk:copy 与 overlay 都供数据盘并写
tenant.json(只有 reuse 不供不写);_provision_data_disk_path
同理(reuse 才返回 None)。
- _cleanup_vm_task_disk:保护(持久登记/登记快照)不再只限
overlay 模式;无登记无快照的 copy 盘仍按旧语义删除。
- provision_data_disk:数据盘改 raw 稀疏盘(os.truncate,
零外部依赖)——copy 模式本来就不需要 qemu-img,数据盘
绝不能悄悄加上这个依赖;CHV 按后缀认 Raw。
- 测试:新增 copy 供数据盘+tenant 与 copy 持久盘 stop 保护;
VmConfig 三盘断言(任务+seed+数据)更新 arch95/fix 两处
旧“恰好两盘”契约与本轨 qcow2 类型断言。
回归:test_chv_*.py、test_cloud_hypervisor.py 42、test_chv_v3_fixes
38 全过(全量 cloud/tests 在跑)。
不推、不合、不部署;只本地分支。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
a5f836e9fd
|
feat(chv-guest): 阶段 1 数据盘独立持久(客内挂载)
- 新增 chv-guest/chv-data-mount.sh:按 LABEL=CHVDATA 找盘
(不依赖 /dev/vd? 固定名;seed ISO 与根盘排除),无 fs
即 mkfs.ext4 -L CHVDATA,挂到 /home/chv/workspace,幂等;
无数据盘即静默退出 0(copy 模式旧 VM 不报错)。
- build.sh:缺脚本即失败(与 chv-sync.sh 同款门);拷入
镜像 /usr/local/bin/chv-data-mount;99-chv-sync.cfg
runcmd 在 chv-sync boot 之前调它(工作区先挂好再 clone)。
- buildinfo.py BASE_CONTENTS 与两 lockfile DECLARED_SOURCES
登记 chv-data-mount(repo_commit,随 P2 三脚本先例)。
- tests:test_chv_opt_stage1.DataMountScriptTest(脚本内容、
构建接线、lockfile 登记);P2 干跑夹具补新文件。
回归:discover test_chv_*.py 与 test_cloud_hypervisor.py 全过。
不推、不合、不部署;只本地分支。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
7a6fae7993
|
feat(chv): 阶段 1 持久 VM、overlay 分层与预热快照
- disk.py:overlay 模式(qcow2 backing file 指只读 base,
建盘/复用/重建校验 + qemu-img fail-closed)、数据盘
data.qcow2 独立供给(不进快照/GC/stop)、配额增量口径
(overlay 本次增量 0)、快照登记 tenant 字段、每 VM
tenant.json、持久登记 persistent/<tenant>.json、快照
登记按 URL 查找。
- config.py:CHV_DISK_MODE 白名单加 overlay(默认仍 copy;
错误文案保留旧子串,防回归测试钉死)。
- executor.py:VmConfig image_type 按后缀(.qcow2→Qcow2,
其余 Raw)+ 数据盘第三块盘;overlay 供给写 tenant 标记;
snapshot_vm 登记带 tenant,_validate_restore 归属校验
(跨用户 snapshot_tenant_mismatch 拒绝 + 审计,legacy
未标记/未登记放行并警告);stop/GC 在 overlay 模式下
保护持久登记/快照认领的盘;持久 VM(prewarm/acquire/
suspend/dispatch_task_persistent/recycle_persistent_vm,
CHV_WARM_POOL_SIZE>=1 启用,=0 退化冷启旧语义),
resume 只认 vm.info=Paused + socket 活性 + 归属一致。
- tests:cloud/tests/test_chv_opt_stage1.py 26 项(overlay、
tenant、持久池、跨用户拒绝、两连任务、显式回收)。
回归:discover test_chv_*.py 与 test_cloud_hypervisor.py
全过(结构契约:函数 ≤50 行、公开 API 全注解、文案钉死)。
不推、不合、不部署;只本地分支。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
c904ae9358
|
carry-over: 在途 V-9 根因修复 + Muse P2 对齐原样带入(未改一行业务逻辑)
来源:feat-chv-muse-p2 @ c918d69 的 6 个未提交文件(+157/-29):
build.sh(GT 哈希轮换 + 99-chv-sync.cfg runcmd chown)、
check_lockfile.py / generate_lockfile.py(DECLARED_SOURCES 加
chv-cell/chv-broker/chv-browser)、executor.py(_wait_guest_env_usable)、
hostkeys.py(guest-env owner 恒 root:root)、test_chv_v3_fixes.py。
单测:python3 -m unittest cloud.tests.test_chv_v3_fixes 38/38 通过。
本提交只搬运,不含阶段 1 改动;阶段 1 另起提交。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
1836c5af32
|
fix(chv): V-7 复测缺陷复修 D1/D2 + F1 瞬时 reset 重试
D1:snapshot_vm 在配额预检后、ch-remote 前建好 file:// 目标
目录(新 helper _ensure_snapshot_dir;fresh URL 直接 snapshot
曾 rc=1 Destination is not a directory)。建目录只在 snapshot_vm
一处,hibernate 经此调用;配额拒绝仍先于任何文件改动。
D2:keep_disk=True 时 stop 保留 seed.iso(_remove_vm_seed_files
抽出;快照 config.json 的 disks 同时引用 disk.raw 与 seed.iso),
且 cleanup_stale_secrets 不清有登记快照的 VM 的 seed(与
gc_stale_disks 的盘保护同款逻辑);正常 stop 仍删两者。
F1:首条任务 SSH 撞 kex 阶段瞬时 reset(rc=255 + kex/reset 标记)
时重试恰好 1 次(_call_ssh_with_transient_retry,_run_guest 与
_run_guest_goal 共用;host key 拒绝/认证失败/远端失败不重试;
审计 vm_ssh_transient_retry)。§5“执行器内部不重试”的唯一例外,
结论写入 docs/chv-production-readiness.md §3/§5/§7。
测试:test_chv_v3_fixes 新增 12 项(D1×3、D2×4、F1×5);旧代码
上 12 项中 9 项失败(余 3 项为守卫既有行为)。全量 test_chv*
470 测试通过。
|
2026-11-08 09:45:00 +00:00 |
|
host
|
65504ae8cb
|
fix(chv): V-3/F1/F2 真机缺陷修复 + V-1/V-4 附带修复
V-3 快照/restore:
- snapshot 改传裸 URL(source_url= 是 restore 的键,服务端
Could not extract path from URL);快照产物是目录,校验
改为目录非空,登记计量/剪枝同步支持目录
- restore 起 VMM 前补 _restore_prepare:杀旧 VMM(登记的 +
未登记跨实例扫描)并清旧 socket,与 _wake_prepare 对等
- hibernate 评估结论:快照 config.json 引用原盘,旧 stop 删
盘致 restore 必失败;hibernate 的 stop 改 keep_disk=True,
GC 不删有登记快照的 VM 的盘,restore 前预检快照引用的盘
(snapshot_disk_missing fail-fast)
F1:re-wake 删旧盘——H5 删私钥致 re-wake 必然生成新 key 对,
旧盘复用时 cloud-init 不重应用新 seed,sshd 仍呈旧 key 而
known_hosts 钉新 key;wake 本就是冷启动,旧盘不是要保留的状态
F2:stop_vm 跨实例按 socket 进程扫描杀未登记 VMM
(/proc cmdline 精确 socket + VMM 二进制名 + 跳过自身/pid 1,
绝不误杀 ch-remote 与他人 VMM)
V-4:remote_command source 失败改 || exit 126 fail-fast;
guest-env 条目 owner 改归 SSH 用户(0600 不变),root 仍 root:root
V-1 附带:build.sh 预建 /app/work(1777 粘滞位 + stat 断言);
host.py default_codex_bin() 改 shutil.which,裸名不再让
health 报 ok:false
测试:新 test_chv_v3_fixes.py 23 项;旧快照测试按目录产物改写;
test_chv* 458 全过,全量 cloud 套件 1930 全过(skipped=8)
|
2026-11-08 09:45:00 +00:00 |
|
host
|
ef206cf554
|
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-08 09:44:59 +00:00 |
|
host
|
cef6353c85
|
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-08 09:44:59 +00:00 |
|
host
|
906f180277
|
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-08 09:44:59 +00:00 |
|
host
|
fb609acb50
|
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-08 09:44:59 +00:00 |
|
host
|
b3cd353a76
|
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-08 09:44:59 +00:00 |
|
host
|
c94cb05157
|
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-08 09:44:59 +00:00 |
|
host
|
82e4150e24
|
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-08 09:44:59 +00:00 |
|
host
|
e7fe0d65e1
|
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-08 09:44:59 +00:00 |
|
host
|
af64f31138
|
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-08 09:44:59 +00:00 |
|
host
|
540cbaf473
|
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-08 09:44:59 +00:00 |
|
host
|
706fe88f46
|
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-08 09:44:59 +00:00 |
|
host
|
e8cf356616
|
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-08 09:44:59 +00:00 |
|
host
|
39c76c2e43
|
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-08 09:44:59 +00:00 |
|
host
|
c94bb02881
|
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-08 09:44:59 +00:00 |
|
host
|
7900b4b7b4
|
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-08 09:44:59 +00:00 |
|
host
|
7674f7396b
|
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-08 09:44:59 +00:00 |
|
host
|
b83c5b2d8d
|
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-08 09:44:59 +00:00 |
|
host
|
e656f63e6d
|
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-08 09:44:59 +00:00 |
|
host
|
018bcda046
|
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-08 09:44:59 +00:00 |
|
host
|
3b5dd7a473
|
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-08 09:44:59 +00:00 |
|