← 返回首页

Authority Blackout:把运行时断电,看它怎么收拾残局

··10 分钟·
#AI Agent#Orcana#评测#可靠性

一个尖刻的问题

对一个 Agent 运行时,可以问一个比"你的模型强不强"更尖刻的问题:

在 Linux 上,你是否真正拥有从公共 Tool 到进程退出、取消、崩溃恢复和证据的唯一执行权威?

翻译成人话:任何一个进程副作用,都必须属于一个受管单元(ExecutionCell)、必须拥有持久化身份、必须能被按 Cell / Agent / Run 三级取消、必须在控制进程异常死亡后被安全识别和回收、必须产生与实际执行一致的 Receipt——而且,任何公共 Tool 都不能绕过这条路径。

这不是理论命题。E2E-001(Authority Blackout,权威断电)就是这么一道题:把 orcana 的电源拔了,看它怎么收拾残局。

事故场景:stubborn-tree

测试构造了一个受控程序 stubborn-tree:每 100ms 写心跳;监听一个 loopback 端口;创建脱离普通父子关系的后代进程;尝试读取宿主诱饵秘密;SIGTERM 后故意延迟退出;输出自身 PID / 进程组 / 启动身份。

同时在宿主上放一个外观完全相同但不属于 orcana 的 sentinel 进程——验证恢复时不误杀。宿主预置 ORCANA_CANARY_SECRET=must-never-reach-cell、PATH=/private/canary-bin:...,canary-bin 里放同名恶意命令——如果公共 Tool 直接继承 PATH 并 spawn,就会写入 DIRECT_BYPASS_DETECTED。

四阶段时间线:

  1. 执行权威:经公共 RUN_PROCESS_TOOL 启动 Cell A1(非直接调 Broker)。必须证明完整调用链 RUN_PROCESS_TOOL → Spec Builder → Policy Compiler → LinuxExecutionBroker → Backend → Process Supervisor。
  2. 控制进程死亡:Cell A1 已启动完整进程树 + ≥5 次心跳 + 占用端口后,对控制进程 kill -9(无正常关闭通知)。制造:进程存在、副作用已发生、内存 cells Map 消失、Linux 未重启、boot_id 未变。
  3. 同 boot 恢复:相同 runtime state root 重启。必须识别 R1 归已死实例;不因 boot ID 相同而忽略;不单凭 PID;不误杀 sentinel;终止完整进程树;停止心跳增长;释放端口;回收锁/cgroup/临时目录/租约;状态收敛到明确终态;写可追溯 Recovery Receipt。难点:PID 可能复用,同 boot 又不能依赖 boot ID——只能靠组合所有权证据:runId/cellId/controllerInstanceId/processStartTime/cgroupPath/backend label/持久化 ownership token。禁止"读旧 PID 无条件 kill"。
  4. 层级取消隔离:cancelAgent(A) → A 的全部进程树全停、A 的端口/资源/锁全释放、B 继续、run 仍有效、重复调用不报错;cancelRun(R2) → 终止剩余 B1;cleanupRun(R2) 连调两次 → 第二次安全返回零清理项。

15 个 Hard Gate,任一触发即整题失败:DIRECT_PROCESS_BYPASS、HOST_SECRET_LEAK、ORPHAN_PROCESS_AFTER_CRASH……到幂等取消、幂等清理,一个都不能少。

根因:四个真实缺陷

这道题挖出来的不是"边界情况",是四个结构性缺陷:

  1. PATH 双重执行:buildExplicitEnvironment 已用固定安全基构造 PATH,但 allowedHostKeys 隐式继承步骤把宿主 PATH(含首位恶意同名命令)覆盖回去——canary 实测命中(exit 127 + {"bypass":true})。存在"Runtime 构造环境"与"宿主环境直达 Cell"的双重世界。
  2. 恢复记账与实物分裂:同 boot SIGKILL 后 janitor 正确识别 stale run 并写 Recovery Receipt,但 broker.cleanupRun 只处理内存 cell——新进程无记录 → 真实进程树(心跳/端口/grandchild)全部存活,run.json 卡 "running"。恢复"声称清理"而非"实际清理"。
  3. 取消路径漏 detached 后代:supervisor 组杀无法命中脱离父子关系的进程(独立进程组),正常取消/超时后逃逸成孤儿,累积到下一轮。
  4. Agent Domain 非资源边界:隔离锁按 agentId 串行化——同 agent 并发 cell 被 worktree:A 锁拒,Agent 不是真实的资源并发边界。

修复:一条权威调用链

修改后的调用链没有任何"快捷方式":

RUN_PROCESS_TOOL / shell tool
  → Spec Builder(env 由 Runtime 显式构造;宿主 PATH 永不隐式继承)
  → Policy Compiler(pathEntries 含运行时自身工具链目录)
  → LinuxExecutionBroker(Cell Journal 持久化 pid+starttime+pgid+cgroupPath)
  → Backend → Process Supervisor(树杀:组杀 + detached 后代快照补杀)
  → 取消:cancelCell/Agent/Run(树杀全覆盖)+ cleanupRun(journal 恢复杀)
  → 崩溃:startupJanitor(同 boot owner 判定 → cleanupRun 按 journal 杀树 → recovered 收敛)

四个提交对应四个修复:

  • Cell Journal:state-store 的 writeCellJournal/updateCellJournal/readCellJournal——进程身份持久化到 SQLite,新控制器恢复时不是"凭内存猜",是"按记录杀"。顺手修了 run.json cells 的 bug(runId→cellId)。
  • 环境权威:宿主 PATH 永不隐式继承 + policy-compiler 补运行时工具链 + shell 工具显式请求 PATH。
  • 资源边界:隔离锁从 agentId 改为 worktree 根——真实资源是工作树,不是 agent 名。
  • 树杀全覆盖:supervisor 的限流/abort/timeout 三处全部改树杀(组杀 + detached 后代快照补杀)。

结果

  • 15/15 Hard Gate 全 PASS,连续 3 次稳定
  • 官方门禁 bun run test EXIT=0 全绿
  • evals/linux-sandbox-eval.ts 33 pass / 0 fail / 4 skip

诚实保留的尾巴:ENV_BLOCKED——podman/bwrap/委托 cgroup(真实内存/fork 炸弹、容器残留)在本机 WSL2 是 EACCES,留给真机 lane 验收(既有 LX-016/017/018/030 SKIP 同因);规格要求的固定种子/随机时序 20 次连跑留给 CI 化(本机 3 次连续稳定)。

为什么这个命题重要

"权威断电"测的不是功能,是运行时最底层的一句承诺:你说进程归你管,那断电之后它还算不算你的?PID 复用、boot ID 相同、诱饵进程、恶意 PATH——每一个都是"表面上管得住、实际上管不住"的陷阱。

一个运行时可以有一百个花哨功能,但只要这句承诺是假的,它就只是"看起来在管"。这道题之后,orcana 才算真正把这句话说圆了。