尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

OmO senpi-task Curated Agents 修正的验证证据链:如何证明禁用、执行固定与只读隔离

OmO senpi-task Curated Agents 修正的验证证据链:如何证明禁用、执行固定与只读隔离 OmO senpi-task Curated Agents 修正的验证证据链如何证明禁用、执行固定与只读隔离【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent本文基于 .omo/evidence/omo-senpi-adapter/20260719-curated-agents/ 证据目录中的 why-enough.md 展开。该目录记录的是 2026-07-19 针对 OmO 的 senpi-task 适配器所做的 curated agents 收敛修正将内置只读子代理explore、librarian、plan-consultant、plan-reviewer的禁用、执行方式与工具能力固定为不可绕过的安全边界。文章将逐条还原这份证据总结的六大论证支柱并结合仓库源码curated-readonly-bash.ts、E2E 驱动脚本、内置 Agent 定义与回归测试说明每一条证据背后的实现与可复现的验证命令。读者读完后可以掌握一套如何为安全边界修正构造自洽、可回归、与 mtime 无关的证据链的工程方法论。背景一次针对 curated agents 的收敛修正在 OmO 的 senpi-task 适配器中内置子代理分为两组4 个curated只读Agent——explore、librarian、plan-consultant、plan-reviewer以及 3 个reviewer Agent——omo-senpi-code-reviewer、omo-senpi-gate-reviewer、omo-senpi-qa-executor。两者的集合互斥、工具面不同curated 组只允许只读工具reviewer 组在 curated allowlist 基础上追加write用于产出评审报告。这一事实由 builtin-agents.test.ts 以字面量断言固定CURATED_AGENT_NAMES恰好 4 个名字curated 组预期工具 allowlist 为read / find / grep / ls / bash / lsp_diagnostics / lsp_goto_definition / lsp_find_references / lsp_symbolslibrarian额外允许x_search而explore显式拒绝x_search所有内置定义mode subagent且executionMode in-process。这次修正要回答的核心问题是如何证明上述边界真实生效、不可被配置覆盖、不会随构建产物陈旧而悄悄回退证据目录中的 why-enough.md 正是对这一问题的结论性回答它把证据组织成六个支柱本文依次展开。支柱一禁用Disablement在 planner 层与 advertised-roster 层双重证明Disablement is proved at planner level with and without explicit model, and at the advertised-roster level.修正后的 planner 对被禁用的 curated 同名类别必须返回unknown_target而不是静默解析出一个不带 persona/工具策略的计划。关键观察记录在 observed.md修正前disabled 且显式指定 model的场景最初会返回一个已解析的计划但缺失 persona/tool policy——这正是被拒绝的边界行为修正后新 planner 分支返回unknown_targetTDD 过程可复现禁用同名类别用例初始为 RED10 pass / 1 fail修正后 GREEN11 pass / 0 fail。unknown_target不是一个拍脑袋的返回值它在 E2E 中同时被验证。看 curated 场景的父步骤脚本 curated-agents-e2e-scenarios.mjs父 Agent 依次发起subagent_type: explore正常路径与subagent_type: nonexistent用于prove the unknown target error的负路径。而分析器 curated-agents-e2e-analysis.mjs 对应设置了unknown_target_agents、unknown_target_categories检查项。advertised-roster level则指对外公布的内置 Agent 名录本身即使某 curated 名字从 roster 中移除也不应残留任何可解析的策略。对应的单元断言在 interaction-policy.test.tsgiven a retired curated idwhen looked upthen no policy is returned。也就是说禁用同时覆盖通过名称解析与通过策略查询两条入口且无论调用方是否显式传入模型都成立。支柱二执行固定Execution Pinning在 config overlay 之后与真实 in-process 子路径证明Execution pinning is proved after config overlay and by the real in-process child path.curated Agent 的executionMode必须被固定在in-process即使配置覆盖config overlay试图将其改为其他进程模式也不行。证据来自两处overlay 之后的钉死observed.md 记录了修正前配置的 Explore 进程覆盖会抵达 RPC 路径修正后引擎在 overlay 之后钉死 curated 名字的进程模式同时保持自定义 Agent 的进程模式不变——即钉死只作用于 curated 集合不误伤自定义扩展。真实子进程路径单元层面builtin-agents.test.ts 对每个内置定义断言executionMode in-processE2E 层面隔离证明 isolation-proof.md 表明调用方提供的SENPI_CODING_AGENT_DIR处于 unset 状态由 E2E 驱动把新建沙箱注入子进程——执行路径是真实的进程内子 Agent 路径而非 mock 桩。这一点的重要性在于只读策略必须附着在实际会执行的那条路径上。如果证据只覆盖规划阶段而执行阶段仍可能走 RPC 或其他进程 runner那么 persona/工具策略可以被绕过。将in-process钉死到内置定义并用executionMode字面量断言等于把安全边界的载体固定在了受控的进程内执行器上。支柱三只读行为由 schema、shell-free 调用、allowlist 与双重检查强制Read-only behavior is enforced by an unambiguous schema, direct executable invocation without a shell, positive command/flag allowlists, unit mutation cases, and live filesystem absence checks.这是整个证据链中源码密度最高的一层落地在 curated-readonly-bash.ts。该文件实现了 curated 会话专用的bash工具——本质是一个结构化的只读远程研究 broker取代普通 bash。3.1 无歧义的参数 schema工具参数用 TypeBox 描述curated-readonly-bash.tsprogram只能是字面量curl或gh之一不存在第三选项args是字符串数组minItems: 1、maxItems: 64即参数向量而非 shell 字符串——语法上就排除了 shell 拼接timeout_seconds可选范围 1120。schema 的无歧义体现在可执行目标被收窄为两个白名单程序且参数以数组传递任何;、、管道、重定向等 shell 语法都根本没有承载的字段。3.2 无 shell 的直接调用执行层使用execFile而非exec/spawn加 shellcurated-readonly-bash.tsexecFile(command.program, command.args, { cwd, encoding: utf8, maxBuffer: 512 * 1024, timeout: timeoutSeconds * 1_000, signal, windowsHide: true, env: { ...process.env, GH_PAGER: cat, GH_PROMPT_DISABLED: 1, GIT_PAGER: cat, PAGER: cat }, }, ...)execFile直接以 argv 方式执行可执行文件不经过 shell 解释因此不存在命令注入面。环境变量中还钉死了GH_PAGER、GIT_PAGER、PAGER为cat、禁用GH_PROMPT_DISABLED避免交互式分页或提示阻塞只读请求。此外curl路径会在规划阶段自动注入--disablecurated-readonly-bash.ts关闭 curl 的配置文件读取防止用户级 curlrc 引入意外行为。3.3 正向命令/标志 allowlistplanCuratedReadonlyCommand只放行两类调用curlisReadonlyCurl要求恰好一个https://URL其余参数必须命中布尔标志集合-f/-I/-L/--compressed/-s/...或带值标志集合--connect-timeout/--max-time/--retry/...或单独允许curl --versioncurated-readonly-bash.ts 与 L146-L161ghisReadonlyGitHub放行search code|commits|issues|prs|repos、repo view、issue/pr view、release view|list、api endpoint排除graphql与以-开头的端点每个子命令再叠加各自的布尔/带值标志 allowlistcurated-readonly-bash.ts 与 L163-L180。任何写操作标志如curl --output、gh api -X POST都不在 allowlist 内会抛出CuratedReadonlyCommandError。这是正向 allowlist而非黑名单默认拒绝一切未列明的参数。3.4 单元 mutation 用例与 live filesystem absence 检查只读行为有两层验证单元层curated-readonly-bash.test.ts 除验证 allowlist 拒绝外还专门覆盖输出边界——超过行数/字节上限时保留响应头部并追加[truncated: ...]提示错误诊断头部也被限制在预算内curated-readonly-bash.test.ts。E2E 层curated 场景脚本在沙箱内预置qa-probe.ts内容为export const probe: string 42\n然后让子 Agent 依次尝试只读调用与非法写入curated-agents-e2e-scenarios.mjsbashcurl --version合法只读应成功bashcurl --output forbidden-via-bash.txt https://example.invalid写操作应被拒edit修改qa-probe.ts应被拒write创建forbidden.txt应被拒。随后分析器在真实文件系统上断言副作用不存在curated-agents-e2e-analysis.mjsprobe_unchangedprobe 文件字节与预期完全一致direct_forbidden_file_absentforbidden.txt不存在bash_forbidden_file_absentforbidden-via-bash.txt不存在。再叠加工具事件层检查bash_read_succeeded只读调用有成功事件与bash_mutation_rejected写调用出现失败事件curated-agents-e2e-analysis.mjs。这组检查是live的不依赖 mock 返回值而是直接检查沙箱目录里是否真的出现了本不该出现的文件、本不该变化的内容。支柱四内容级 Bundle 新鲜度替代 mtime 与手维护源列表Bundle freshness is content-based across Buns transitive graph; the regression suite names the primary senpi-task broker input and rejects stale source/body markers irrespective of mtimes.生成 bundlebuild-extension.mjs是 curated broker 真正随扩展分发的形态因此源码改了、产物还是旧的这类陈旧问题必须被当作安全边界的一部分。修正后的构建校验见 what-tested.md不再比较 mtime也不再维护手写的 source-root 列表构建过程把完整 Bun metafile 输入图的内容 digest 稳定的相对输入路径 构建设置 构建脚本嵌入产物--check模式重新生成依赖图并比较该 source digest同时独立校验已入库的 body digest。也就是说新鲜度判定完全基于内容只要传递闭包内任何一个输入文件的内容发生变化digest 就会变化与文件 mtime 是否被触碰无关。回归测试bun test packages/omo-senpi/plugin/scripts/build-extension.test.mjs进一步固定了三件事主依赖图必须包含packages/senpi-task/src/runners/in-process/curated-readonly-bash.ts——这是命名主 senpi-task broker 输入旧的产物 mtime 必须通过证明不依赖时间戳body 篡改或 source marker 陈旧必须失败。observed.md 记录了 TDD 过程最初的 mtime 检查器在全部新增的内容新鲜度用例上失败最终 5 个构建测试覆盖mtime 无关性、body 篡改、陈旧 source marker、空白归一化、senpi-task 传递包含五个维度。最后node packages/omo-senpi/plugin/scripts/build-extension.mjs --check退出码 0且生成 bundle 通过 700,000 字节的包体积预算。支柱五独立字面量的 Drift GuardsDrift guards are independent literals: full fallback tables and a complete expected analyzer check object.回退链与期望行为不能由与实现共享的同一份数据推导出来——否则实现改错时测试也会跟着错形成共谋。修正的做法是把两处关键期望以独立字面量固化完整回退表fallback-chains.ts是 curated Agent 的模型回退链来源注释明确两个 curated agent 在此携带其规范 idplan-consultant、plan-reviewer其回归测试 fallback-chains.test.ts 断言该表只携带 4 个 curated agent 名字防止回退表悄悄被污染完整期望 analyzer 检查对象E2E 分析器 curated-agents-e2e-analysis.mjs 以EXPECTED_EXPLORE_TOOL_ALLOW数组独立列出 explore 的完整工具面与实现方的 allowlist 字面量互相独立、互相校验。observed.md 记录了 mutation 观察篡改镜像回退表、记录解析器或根导出都会使对应回归测试在恢复前失败——这正是 drift guard 存在的意义任何一侧实现或期望单独漂移都会暴露。支柱六最终 Gate 全绿The final typecheck, package, adapter, generated-bundle, documentation, and real-harness gates all pass.最终 gate 的完整命令清单与结果记录在 what-tested.md 与 observed.mdGate命令结果作用域类型检查tsgo --noEmit -p packages/senpi-task/tsconfig.json/tsgo --noEmit -p packages/omo-senpi/tsconfig.json均退出 0核心测试bun test packages/senpi-task packages/omo-senpi1,014 pass / 0 fail2 snapshots3,422 expectationssenpi 专项bun run test:senpi259 pass / 0 fail1 snapshot813 expectations文档链接审计bun test packages/omo-opencode/src/shared/markdown-link-audit.test.ts16 pass / 0 fail构建校验器测试bun test packages/omo-senpi/plugin/scripts/build-extension.test.mjs5 pass / 0 fail生成 bundle 校验node packages/omo-senpi/plugin/scripts/build-extension.mjs --check退出 0通过 700,000 字节预算curated 真实 harnessCURATED_AGENTS_E2E_OUT_DIR... node packages/omo-senpi/scripts/qa/curated-agents-e2e.mjs18 项检查 PASSbaseline 真实 harnessTASK_E2E_OUT_DIR... node packages/omo-senpi/scripts/qa/task-e2e.mjs12 项检查 PASS0 泄漏 PID6.1 真实 harness 的隔离证明curated 与 baseline 两次 E2E 都具备严格的因果隔离isolation-proof.md每个场景使用独立 sandbox token如omo-senpi-qa-lPaFsIagent/project/task-state 目录全部位于 worktree 的.omo/tmp下realSenpiChangedPaths为空no_leaked_pids为 PASS快照期间若有并发主机会话写入路径会进入concurrentRealSenpiChangedPaths单独分类不携带任何 sandbox token——因此整目录 digest 被如实标记为 changed但因果归属判断仍然严格任何非会话路径或携带活跃 sandbox token 的会话路径都会被判定为 QA 归属并使驱动失败。verdict.json 给出了 baseline 的 12 项检查结果spawn_background、unconditional_wake、followup_revive、task_output_full、task_output_block、jsonl_sequence、extension_suppression、batch_fanout_two_children、sync_inline_no_notification、negative_category_error、real_senpi_untouched、no_leaked_pids与 0 泄漏 PID。curated 驱动的 18 项检查则额外覆盖本修正的核心面record_tool_allow、record_model_source、explore_persona_prompt、probe_unchanged、direct_forbidden_file_absent、bash_forbidden_file_absent、bash_read_succeeded、bash_mutation_rejected、unknown_target_*等。证据的边界这套证据不证明什么omitted.md 与 what-tested.md 明确划定了证据边界这本身就是严谨性的一部分未改动OpenCode、Codex、主 checkout 或其他无关包代码未引入进程 runner 的 persona/工具策略重构或宽泛的团队注册表未发起真实外部模型请求未复制用户凭据、认证头、原始环境变量或完整会话转录安全的 live broker 探测只使用了curl --version未保留含密钥的日志、用户配置、环境 dump 或转录正文.omo/**、临时 QA 沙箱、依赖与生成的测试缓存均不参与提交——证据目录本身是未入库的工作产物。换句话说这套证据证明的是被拒绝的边界全部有覆盖、且覆盖在真实执行路径上而不是声称对任意外部系统做过端到端调用。边界越清晰证据的充分性判定就越可复现。结语为什么这些证据足够回到 why-enough.md 的原始表述六条支柱合在一起回答足够禁用在 planner 层有无显式模型两条路径与 advertised-roster 层都被证明负路径返回unknown_target执行固定在 config overlay 之后与真实 in-process 子路径被证明executionMode与mode有字面量断言只读由无歧义 schema、无 shell 的execFile、正向命令/标志 allowlist、单元 mutation 用例与 live 文件系统 absence 检查四层叠加强制bundle 新鲜度基于 Bun 传递依赖图的内容 digest回归套件指名主 broker 输入拒绝陈旧 source/body marker 且与 mtime 无关drift guards是独立字面量——完整回退表与完整期望 analyzer 检查对象杜绝实现与测试共谋最终 gate全绿typecheck、package、adapter、generated-bundle、documentation、real-harness 全部通过且隔离证明排除了外部会话的干扰。这套方法论的关键启示在于安全边界的证据不能停留在功能正确而要回答边界是否不可绕过、配置是否不可覆盖、产物是否可能陈旧、期望是否与实现独立。当一条证据链同时覆盖这四个维度并配上可复现的 TDD mutation 记录与真实 harness 隔离证明时才能像这份文档一样用一页纸的篇幅让人信服地说出——why this is enough。【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表