diff --git a/cloud/chv/executor.py b/cloud/chv/executor.py index 48c75fa..3346196 100644 --- a/cloud/chv/executor.py +++ b/cloud/chv/executor.py @@ -250,8 +250,9 @@ class CloudHypervisorExecutor(Executor): 3-4294967295 内,0/1/2 为保留 CID) - CHV_CELL_ENABLED:nspawn 单元开关(默认 1 开;只认 0/1,非法值 ValueError)。开时客内 host.py 改走 - chv-cell run(P2 差距表 §4);关时走原命令,给 - lite10 及更早无单元的旧镜像留逃生口 + sudo chv-cell run(P2 差距表 §4;round-11 真机修复: + chv-cell 须 root,执行器以 chv 身份调,须 sudo); + 关时走原命令,给 lite10 及更早无单元的旧镜像留逃生口 前置校验(preflight,执行入口必调,缺一即 fail-fast): 收集全部缺失项一次报出具体缺哪一项,绝不笼统报错: @@ -1462,11 +1463,15 @@ class CloudHypervisorExecutor(Executor): 放在该路径(与 Docker 的 /app:ro 同款约定,只是载体 从容器换成 VM 镜像)。 round-11 集成补洞(P2 差距表 §4):单元开时(默认) - 命令改为 chv-cell run -- python3 /app/host.py --state + 命令改为 sudo chv-cell run -- python3 /app/host.py --state /home/chv/.codex/host-state.json --codex-home /home/chv/.codex … --sandbox danger-full-access [子命令 - ...]。--state/--codex-home 须显式给(见模块顶 _CELL_* - 注释);--sandbox 放全局参数最后(argparse 后胜出), + ...]。sudo 不可省:chv-cell 须 root(nspawn + 配网), + 执行器经 SSH 以 chv 身份调,chv 的 NOPASSWD sudo 来自 + seed users 块(见 test_chv_gitea_sync.py 的 users 夹具; + 探针 p2.log 的手动调用也是 sudo chv-cell run)。 + --state/--codex-home 须显式给(见模块顶 _CELL_* 注释); + --sandbox 放全局参数最后(argparse 后胜出), 确保单元内恒为 danger-full-access:单元即沙箱,调用 方传的 read-only(plan 任务)与 approval=full 自带的 值都不得把它盖回 bwrap。单元关时 @@ -1476,7 +1481,7 @@ class CloudHypervisorExecutor(Executor): cell = self._cell_enabled() cmd = ["python3", self.guest_host_py] if cell: - cmd = ["chv-cell", "run", "--"] + cmd + cmd = ["sudo", "chv-cell", "run", "--"] + cmd cmd += ["--state", _CELL_STATE_PATH, "--codex-home", _CELL_CODEX_HOME] cmd += _host_command_options( @@ -2598,7 +2603,7 @@ class CloudHypervisorExecutor(Executor): ValueError(_to_switch 的 CHV_BALLOON/CHV_VSOCK 同款 口径,绝不静默 fallback)。关时 _guest_host_command 走原命令,给 lite10 及更早无单元的旧镜像留逃生口; - 开时走 chv-cell run -- python3 /app/host.py …。读 + 开时走 sudo chv-cell run -- python3 /app/host.py …。读 self._env(与 _resident_enabled 同款惰性读法),不 经 config:开关只影响命令构造,不影响建池/起 VM。""" flag = _to_switch( diff --git a/cloud/tests/test_chv_muse_round11_cell.py b/cloud/tests/test_chv_muse_round11_cell.py index 9288242..fa04819 100644 --- a/cloud/tests/test_chv_muse_round11_cell.py +++ b/cloud/tests/test_chv_muse_round11_cell.py @@ -1,9 +1,10 @@ """round-11 集成补洞:执行器接 nspawn 单元(P2 差距表 §4)。 只测 _guest_host_command 的命令构造与 CHV_CELL_ENABLED 开关: -单元开(默认)时 host.py 调用改为 chv-cell run -- python3 +单元开(默认)时 host.py 调用改为 sudo chv-cell run -- python3 /app/host.py --state … --codex-home … --sandbox -danger-full-access …;单元关时走原命令;非法开关值即 +danger-full-access …(sudo 不可省:chv-cell 须 root,执行器以 +chv 身份调;round-11 真机修复);单元关时走原命令;非法开关值即 ValueError。只用 mock,不启动真实 VM、不连真实网络。 """ @@ -83,7 +84,7 @@ class CellCommandTest(CellCase): ex = self.make_exec() cmd = ex._guest_host_command("status", "--task", "t1") self.assertEqual(cmd, [ - "chv-cell", "run", "--", + "sudo", "chv-cell", "run", "--", "python3", "/app/host.py", "--state", "/home/chv/.codex/host-state.json", "--codex-home", "/home/chv/.codex", @@ -93,7 +94,7 @@ class CellCommandTest(CellCase): def test_cell_on_explicit_1(self): ex = self.make_exec(env_extra={"CHV_CELL_ENABLED": "1"}) cmd = ex._guest_host_command("status", "--task", "t1") - self.assertEqual(cmd[:3], ["chv-cell", "run", "--"]) + self.assertEqual(cmd[:4], ["sudo", "chv-cell", "run", "--"]) self.assertIn("--sandbox", cmd) self.assertEqual( cmd[cmd.index("--sandbox") + 1], "danger-full-access") @@ -120,7 +121,7 @@ class CellCommandTest(CellCase): model="m1", effort="low", approval="ask", model_provider="sub2api", sandbox="read-only") self.assertEqual(cmd, [ - "chv-cell", "run", "--", + "sudo", "chv-cell", "run", "--", "python3", "/app/host.py", "--state", "/home/chv/.codex/host-state.json", "--codex-home", "/home/chv/.codex", @@ -164,12 +165,14 @@ class CellCommandTest(CellCase): def test_cell_wiring_reaches_ssh_command(self): # 接线落到 SSH 层:build_ssh_command 的远端命令里 - # chv-cell 前缀在、python3 在其后。 + # sudo chv-cell 前缀在、python3 在其后。 ex = self.make_exec() inner = ex._guest_host_command("status", "--task", "t1") cmd = ex.build_ssh_command({"id": "t1"}, inner) + self.assertIn("sudo", cmd) self.assertIn("chv-cell", cmd) self.assertIn("danger-full-access", cmd) + self.assertLess(cmd.index("sudo"), cmd.index("chv-cell")) self.assertLess(cmd.index("chv-cell"), cmd.index("python3"))