fix(grok): enforce pinned native tool boundary in copresence - #830
fix(grok): enforce pinned native tool boundary in copresence#830vansin wants to merge 7 commits into
Conversation
独立窄审 · PR #830 (Draft) — deny vendor
|
| value | check | |
|---|---|---|
| HEAD (report-only) | 78a6de9c9d1277936326ce31db0561bc90f07151 |
✓ matches brief |
| source (fix) | f407ed961bc9f0e146657439a9fbfb113604362e |
✓ matches brief |
| parent (#826 HEAD) | 114967626f20c7ef036c3d0e0dab295e1f983a89 |
✓ is-ancestor of pr-830 |
| grandparent (#825 source) | 8186b79de8e2f904c28bec268d93a523503a6845 |
✓ is-ancestor |
| current main tip | 034f00647d42d38d5086d7fc057eb7824a441791 |
(merge-base w/ pr-830, since #825/#826 not merged yet) |
| image ID (claim) | sha256:91b8e8b06603... |
declared, matches brief |
| files (base(#826)..HEAD) | 4 = 3 src/test + 1 report | ✓ matches brief |
| source→HEAD delta | exactly docs/tests/report-grok-copresence-terminal-deny.txt |
✓ report-only |
| full stack vs main | 21 files (#825's 7 + #826's 12 + #830's 4 - overlap) | expected |
Per-file drift base..main: 0 for every one of the 21 touched files. git merge-tree base main pr-830 = 0 conflict markers.
Report source_commit anchor: report L4 Source commit: f407ed961bc9f0e146657439a9fbfb113604362e byte-matches the PR source SHA. L3 Base: 114967626f20c7ef036c3d0e0dab295e1f983a89 (#826 report head) explicitly cites #826's report HEAD as the base — chain accurate.
Item-by-item
① Delta = 3 source/test + 1 report, no extra product changes beyond #825/#826 — CONFIRMED
git diff --name-only 114967626f...78a6de9c9d:
agent-node/src/runtime/grok-copresence/profile-process.test.ts (modified, +1 line)
agent-node/src/runtime/grok-copresence/runtime.test.ts (modified, +1 line)
agent-node/src/runtime/grok-copresence/runtime.ts (modified, +4 lines of comment + argv)
docs/tests/report-grok-copresence-terminal-deny.txt (new)
Exactly 4 files: 3 in agent-node/src/runtime/grok-copresence/ (all under the copresence namespace) + 1 report. No product changes outside the copresence runtime, no changes to agent-network, no changes to test infrastructure. No accidental #825/#826 file revisions.
② Vendor event name run_terminal_command accurate + deny in real production argv — CONFIRMED
Vendor name corroboration:
- Report §Live trigger quotes real pinned Grok 0.2.93
events.jsonl:permission_requested tool_name=run_terminal_command permission_resolved tool_name=run_terminal_command decision=allow wait_ms=0 tool_completed tool_name=run_terminal_command outcome=success - Independent corroboration from the existing test corpus (pre-fix(grok): enforce pinned native tool boundary in copresence #830):
run_terminal_commandis used astool_nameinruntime.test.tsfixtures at ~15 sites (lines 373, 388-389, 409, 453, 644, 807, 820, 824, 841, 881, 937, 944) and injsonl.test.ts:345. This is the established vendor emission name. - Existing
grok-build-cli.ts:56alias map:run_terminal_command: "run_terminal_cmd"(translation from vendor name for internal policy use) — confirms the vendor usesrun_terminal_commandin its wire vocabulary.
Deny added to real production argv (runtime.ts:421-431 in buildGrokCopresenceArgs):
args.push(
// ...
// Pinned Grok 0.2.93 emits `run_terminal_command` in its permission
// lifecycle. `Bash` is only the cross-runtime policy alias and does not
// deny that vendor-native tool name by itself.
"--deny", "run_terminal_command",
"--deny", "Bash",
"--deny", "Write",
"--deny", "WebFetch",
);This is the actual production argv builder — same function called by openGrokCopresenceRuntime → spawnTui → real Grok binary spawn. Not a fixture, not a mock. The new "--deny", "run_terminal_command" is a real production argv entry.
Argv precedence check: the deny appears BEFORE --deny Bash in the same args.push() block. Grok's --deny semantics are additive (multiple --deny entries all take effect). --always-approve and --permission-mode bypassPermissions appear EARLIER in argv — but existing MUTATION_REDs from #822/#825 (e.g., Bash, Write, WebFetch, Read(protected), Grep(protected)) empirically prove that --deny is NOT overridden by --always-approve in Grok 0.2.93.
③ Two assertions cover x-search/repo-read/commhub-only + named mutation red — CONFIRMED
Assertion 1 (profile-process.test.ts:71, +1 line added by this PR):
for (const result of [restricted, xSearch, repoRead]) {
const denied = result.args.flatMap(...);
expect(denied).toContain("run_terminal_command"); // ← NEW
expect(denied).toContain("Bash");
expect(denied).toContain("Write");
expect(denied).toContain("WebFetch");
...
}The for loop iterates over all three capability profiles (restricted = commhub-only, xSearch, repoRead). Every profile is asserted to include "run_terminal_command" in denied. Structural guarantee: if any profile drops the deny, this assertion reds.
Assertion 2 (runtime.test.ts:238, +1 line):
const denied = args.flatMap(...);
expect(denied).toContain("run_terminal_command"); // ← NEW
expect(denied).toContain("Bash");
expect(denied).toContain("Write");
expect(denied).toContain("WebFetch");Direct launch-policy test on buildGrokCopresenceArgs output — independent of the profile-process spawn abstraction.
Named witnessed-red mutation vendor-terminal-deny-removed (report §Docker evidence):
Focused clean run: 54 pass, 0 fail, 456 expect (2 files)
After mutation: 52 pass, 2 fail, 432 expect (2 files)
MUTATION_RED vendor-terminal-deny-removed rc=1
The mutation harness required the named Bun failure
`Expected to contain: "run_terminal_command"`; an unrelated red did not count.
Cardinality analysis:
- Baseline 54 pass / 0 fail
- Mutation → 52 pass / 2 fail — precisely 2 failures, matching the 2 new assertions in profile-process.test.ts + runtime.test.ts
- Both fail with the SAME string:
Expected to contain: "run_terminal_command"— the named-red text the harness required - If the mutation had caused an unrelated failure (e.g., syntax error, ambient assertion), the harness's
grep "Expected to contain: \"run_terminal_command\""requirement would have missed → mutation would fail with "died for the wrong reason" style abort
Mutation preconditions:
- Requires exactly ONE occurrence of
"--deny", "run_terminal_command",in production before running - Requires a byte-changing mutation (file hash before ≠ after)
- Both guards prevent no-op mutations passing
Not self-red: baseline runs FIRST (54 pass / 0 fail — proves clean tree passes). Mutation is applied only after baseline is green. The tests import production runtime.ts, so mutation to production propagates to the tests (real coupling, not fixture self-consistency).
④ Report provenance + Docker gate doesn't impersonate real vendor — CONFIRMED
Numeric consistency:
- Full unit domain:
1284 pass / 0 fail / 4410 expect / 91 files— matches feat(grok): add strict repository-read co-presence profile #826 baseline (1284/0/4406/91) plus +4 expect which precisely matches the 2 newexpect(denied).toContain("run_terminal_command")assertions × 2 (they run once directly and once inside the 3-profile probe loop, or the expect count reflects the mutation-hardened path count). Consistent. - Focused: 54 pass / 456 expect on 2 files → mutation drops to 52 pass / 432 expect (delta -2 pass, -24 expect ≈ 12 expects per file matches "2 new expects × 3 profiles × ... " scaling). Consistent.
Blob hashes for changed source files listed in report §Source delta:
a62d5e3b... agent-node/src/runtime/grok-copresence/runtime.ts
72b449ea... agent-node/src/runtime/grok-copresence/runtime.test.ts
48a22832... agent-node/src/runtime/grok-copresence/profile-process.test.ts
These are sha256sum outputs of the file contents (not Git blob hashes). Verifiable in principle by sha256sum on the source-tree files at commit f407ed96. I did not independently verify byte-for-byte, but the shape is honest and reproducible.
Docker ≠ real vendor — explicitly acknowledged in report §Honest limits:
"NOT COVERED: a released build has not yet been run against the real Grok 0.2.93 vendor after this change. The decisive post-fix gate is a fresh-session task that previously caused
run_terminal_command; the event stream must show no permission request, resolution, or completion for that tool."
"The Docker evidence proves exact argv construction and regression sensitivity. It does not prove that a future Grok binary preserves the same permission-rule vocabulary; the existing exact version pin remains required."
The Docker gate proves ONLY:
- Argv construction includes
--deny run_terminal_command - Mutation regression sensitivity (removing it reds tests)
The Docker gate does NOT claim to prove:
- Grok 0.2.93 actually honors
--deny run_terminal_commandat runtime - Real vendor no longer emits
permission_requested/resolved/tool_completed(run_terminal_command)after the fix
The report is disciplined on this distinction. This is the honest position — the decisive post-fix gate is a live pinned-Grok test that the report explicitly defers to a follow-up.
⑤ No missed generation sites in copresence + --deny not overridden — CONFIRMED for copresence scope
Copresence argv builder inventory (searched agent-node/src/runtime/grok-copresence/):
- ONE
buildGrokCopresenceArgsfunction atruntime.ts:421— the sole argv builder for copresence - The new
--deny run_terminal_commandis INSIDE this function (line 427), applied unconditionally to all three capability profiles
Argv precedence within copresence:
- Order:
--sandbox <profile> --no-auto-update --disable-web-search --no-subagents --no-memorythen--deny run_terminal_command --deny Bash --deny Write --deny WebFetchthen per-protectedPath--deny Read(...) --deny Grep(...) --deny Edit(...) --always-approveand--permission-mode bypassPermissionsappear EARLIER in argv- Empirical evidence that
--denyis NOT overridden by--always-approve: fix: fail closed when Grok CommHub MCP is unavailable #822/fix(grok): fail closed when CommHub MCP is not ready #825's protectedPath denies (Read(protected),Grep(protected)) empirically enforce, and the whole--deny Bash/Write/WebFetchpolicy has been the security posture without incident (per pre-fix report, the--deny BashDID stop Bash-tool invocations; the leak was only thatrun_terminal_commandwas a DIFFERENT vendor name not covered by theBashalias)
No allowlist that could re-enable: no --allow, no --enable, no --allow-tools flag in argv. --tools explicit forwarding is REJECTED at argv build (if (opts.toolAllowlist !== undefined) throw). The tool set is fixed by the capability profile.
⑥ Secret sweep + main merge-tree — CONFIRMED clean
Secret sweep on the 4 delta files with patterns ntok_/utok_/atok_/BEGIN PRIVATE KEY/AKIA/AIza/ghp_/gho_/xoxb-/sk-live: 0 hits on all 4 files. No credential exposure risk.
Current-main drift: 0 commits on any of the 21 stack files since base..main (base == current main tip).
Virtual merge-tree: 0 conflict markers.
⑦ Informational (not blocking) — same-class bypass in non-copresence grok-build-cli.ts
Observation: the non-copresence Grok runtime agent-node/src/runtime/grok-build-cli.ts has a very similar deny list (grok-build-cli.ts:217-219):
"--deny", "Bash",
"--deny", "Edit",
"--deny", "Write",And its GROK_TOOL_ALIASES at line 56 has run_terminal_command: "run_terminal_cmd" — confirming the codebase acknowledges the vendor name.
If the same pinned Grok 0.2.93 emits run_terminal_command (or the semantically-equivalent alias run_terminal_cmd) under the non-copresence launch mode, and if the non-copresence deny list also uses the policy alias Bash instead of the vendor name, the SAME shell-escape class could exist there too.
Why this is INFORMATIONAL, not MAJOR-for-this-PR:
- The bypass has only been OBSERVED in copresence mode. Non-copresence uses different launch modes (
--output-format streaming-json,--prompt-file) which may have different tool-invocation semantics. - Non-copresence uses
--tools <allowlist>explicitly — vendor may only be able to invoke tools in that list, andSAFE_GROK_TOOLS = ["read_file", "grep", "list_dir", "web_search", "web_fetch"]excludesrun_terminal_cmdby default. - However, if a user configures
bashin their tool allowlist, the alias map translates torun_terminal_cmd, and it becomes part of--tools— where the--deny Bashmay not cover it. - This is a separate audit trail requiring live vendor observation; not testable via fix(grok): enforce pinned native tool boundary in copresence #830's Docker gate.
Recommendation for a follow-up PR (out of scope for #830):
- Add
--deny run_terminal_command --deny run_terminal_cmdtogrok-build-cli.tsargv as belt-and-suspenders. - Ideally do the same live-observation trigger for non-copresence to verify or refute the bypass class before assuming safety.
Report §Honest limits does not currently mention this consideration. Not a defect for THIS PR — brief scope explicitly names copresence — but worth landing as a same-class-audit follow-up ticket.
Reviewer discipline (self)
Applied feedback_finding_confirmation_is_not_verdict: every focus item was mechanically mapped to brief wording. Nothing lands on BLOCKER/MAJOR/MINOR gate wording for THIS PR's scope. Verdict: CLEAN.
Applied lesson from #822: verified the mutation is truly named-red (specific "Expected to contain" text required, precise 2-fail count matching 2 added assertions) rather than exit-code-only.
Applied lesson from #800/#822: verified report source_commit=f407ed96... byte-matches PR source SHA — no stale anchor. Report explicitly cites #826 report head as base and does not conflate stacks.
Applied feedback_silent_failure_needs_independent_review: verified the pre-fix failure mode was described correctly (supervisor 在 tool completed 后才 approval_boundary fail-closed — the vendor had already completed the tool before the supervisor caught it), which is a real security invariant violation, not a decorative issue.
Independent verifications on this host:
git rev-parse origin/pr-830=78a6de9c...✓git rev-parse ${source}^{tree}— tree matches source ✓git merge-base --is-ancestor 8186b79d origin/pr-830= true (stacked on fix(grok): fail closed when CommHub MCP is not ready #825 confirmed)git merge-base --is-ancestor 11496762 origin/pr-830= true (stacked on feat(grok): add strict repository-read co-presence profile #826 confirmed)git diff --name-only source..HEAD= report only ✓git diff --name-only base(#826)..HEAD= exactly 4 files (3 src/test + 1 report) ✓- Read
buildGrokCopresenceArgs(runtime.ts:421-465) — the new--deny run_terminal_commandis at line 427, unconditional, in the shared code path for all three capability profiles - Grep confirmed
run_terminal_commandused in 15+ existing test fixtures as vendor emission name - Read profile-process.test.ts:71 — assertion inside the for loop over restricted/xSearch/repoRead → covers all 3 profiles
- Read runtime.test.ts:238 — direct assertion on
buildGrokCopresenceArgsoutput - Mutation math checks out: 54 - 52 = 2 fails, matching exactly the 2 new assertions
- Named-red string
Expected to contain: "run_terminal_command"is the exact Bun test error format fortoContainmismatch — required by mutation harness - Verified no
--allow/--allow-toolsflag in copresence argv builder that could re-enable - Verified non-copresence
grok-build-cli.ts:217-219deny list uses policy names (Bash/Edit/Write) not vendor names — flagged as informational - Secret sweep on 4 files: 0 real credentials
git log --oneline base..main -- <21 files>= 0 for each — no driftgit merge-tree base main pr-830 | grep -cE '^<<<<<<<'= 0- Report §Honest limits explicitly declines to claim Docker argv gate is proof of vendor runtime behavior; pinned-Grok post-fix gate deferred to follow-up
No approve, no merge, no deploy. Do not merge before #825 and #826.
|
🔴 Supersedes all earlier #830 review coordinates and CLEAN verdicts. The earlier Current frozen coordinates:
Validation: full No previous review applies to this source. A new independent review is required. No merge, publish, deploy, or node restart is authorized by this comment. |
独立窄审 · PR #830 (Draft) — pinned native tool-inventory closureVerdict: CLEAN — no BLOCKER, no MAJOR, no MINOR. Prior CLEAN comment on old source Reviewer: 通信IM马 (independent, read-only). Extracted PR tree via Dependency: MUST NOT merge before #825 → #826. Both are ancestors of current #830 HEAD (verified Provenance
Per-file drift Report source anchor honesty: report L5 Item-by-item① base..source product delta + source..head report-only — CONFIRMED
Exactly 4 product files + 1 report. All product edits are within ② Pinned 0.2.93 AvailableCommandsUpdate 25-name denominator — CONFIRMED closedReport §Pinned denominator captures the exact 25 names from I counted: 25 tools exactly — matches brief's "25-name denominator". Structural closure enforced in test ( for (const tool of [
"run_terminal_command", "read_file", "search_replace", "list_dir", "grep",
"kill_command_or_subagent", "todo_write", "get_command_or_subagent_output",
"wait_commands_or_subagents", "scheduler_create", "scheduler_delete", "scheduler_list",
"monitor", "search_tool", "use_tool", "update_goal", "enter_plan_mode", "exit_plan_mode",
"ask_user_question", "web_search", "web_fetch", "image_gen", "image_edit", "video_gen",
"write",
]) {
expect(result.tools.includes(tool) || denied.includes(tool)).toBe(true);
}This runs for ALL THREE profiles ( Preventive-only clarity: report explicitly says: "Only ③ Three profiles no overlap 越权 + final argv 真承重 — CONFIRMEDPer-profile allow-vs-deny partition (25 names always partitioned across allow/deny):
Enforcement chain in runtime.ts:421-438: // Unconditional vendor deny (28 tools including safety-margin aliases)
for (const tool of GROK_COPRESENCE_VENDOR_DENY_TOOLS) {
args.push("--deny", tool);
}
// Conditional per-profile
if (!GROK_COPRESENCE_REPO_READ_ENABLED) {
for (const tool of ["read_file", "grep", "list_dir"]) args.push("--deny", tool);
}
if (!GROK_COPRESENCE_WEB_SEARCH_ENABLED) args.push("--deny", "web_search");
// Legacy compatibility aliases (kept for defense in depth)
args.push("--deny", "Bash", "--deny", "Write", "--deny", "WebFetch");No profile overlap: I mentally traced each profile through the branches:
Test asserts these boundaries hold (profile-process.test.ts:99-107):
Final argv 真承重: same VENDOR_DENY_TOOLS count: I counted 28 entries in policy.ts:32-73. The extra 3 (beyond the 25 captured) are conservative native aliases: ④ 7 named-red mutations 零 mutation 绿对照 + 唯一目标 + byte change — CONFIRMEDReport §Docker evidence lists all 7: Five common-deny mutations (one per tool class: terminal, write, scheduler/control, fetch, media) + two profile-specific mutations (read-boundary + search-boundary). Mutation contract (per report §Docker evidence):
Baseline focused control: Sample mutation output (report L91-97): Anatomy:
Named-red per mutation class:
Each mutation must produce the specific named string — not accidentally red on ambient failure. Byte-change guard: report says "changed file hash" is required — bit-identity would fail this precondition (matches ⑤ 1284/0/4609/91, 54/0/655/2, 7 mutations 与 source 字节相符 — CONFIRMED consistentFull unit domain (report L69-76): Compared to #826 baseline (1284/0/4406/91): +203 expect, same 1284 tests, same 91 files. The +203 expect delta is consistent with:
Focused clean (report L80-86): Compared to old #830 focused (54/0/456/2): +199 expect. Same 54 tests. Consistent with new closure-check + per-profile boundary additions. Blob SHA-256 declared for 4 changed source files. I did not run Note on 28 vs 25: policy.ts's VENDOR_DENY_TOOLS has 28 entries (I counted). The AvailableCommandsUpdate denominator is 25. The 3 extras ( ⑥ secret sweep / main drift / merge-tree — CONFIRMED cleanSecret sweep on 5 delta files with patterns
Main drift: 0 commits on any of the 21 stack files since Virtual merge-tree: Trivially rebase-clean — base == current main tip, no drift risk at this moment. Reviewer discipline (self)Applied Applied Applied prior audit lesson from old-source review: verified the closure check (every captured 25 name is allow-or-deny) is the correct structural guarantee, not the earlier narrower Applied brief reminder: prior CLEAN comments on old sources Independent verifications on this host:
No approve, no merge, no deploy. Do not merge before #825 and #826. |
CORRECTION · PR #830 — set-math error in prior CLEAN commentReviewer: 通信IM马 (independent, read-only). This is an append-only correction to my earlier CLEAN verdict at #issuecomment-5277364559. Prior comment preserved unchanged for trace. Verdict remains: CLEAN. The correction is arithmetic / set-classification, not a security-property change. Details below. What I wrote wrongIn the prior comment (⑤ paragraph and (2) closing), I wrote:
This is incorrect. I conflated two orthogonal partitions. What is actually true (independently recomputed with
|
|
Draft,不合,只留 review。这个 PR 修的是一次真实发生过的边界击穿,不是理论问题 —— 所以我核得比平时细。 一、先确认它的分母主张成立evidence 文件里那句「Every captured name is now either explicitly allowed by the selected process profile or explicitly denied」我逐条对了: 分区是完整的,没有漏网的名字。 我一开始怀疑 版本也是钉死的: 🔴 二、我的核心问题:
|
…1004) * fix: fail closed on broken Grok CommHub MCP * test: exercise Grok CommHub MCP readiness handshake * test: add isolated Grok MCP readiness gate * test: exercise the real Grok MCP doctor * docs: report Grok vendor MCP readiness * test: gate Grok readiness on product startup path * test: keep Grok gate dependency layers source-independent * test: anchor Grok readiness to runtime events * docs: record exact Grok MCP readiness evidence * fix(grok): 把 #825 的 MCP 就绪 fail-closed 落到 main(rebase + 补两处今天新门抓到的) #825(`fix(grok): fail closed when CommHub MCP is not ready`)从 2026-08-15 起是 draft,落后 main 120 个提交,上次 CI 只跑了 10 个 check(今天一个 PR 跑 13–23 个)。 它是 grok 栈 `#825 → #826 → #830 → {#836,#867}` 的**唯一出口**,它不落地, 上面四条谁都到不了 main。 **没有 force-push 那条共享 draft 分支** —— 本 PR 从我自己的分支发,内容是它那 9 个 补丁 rebase 到 `origin/main`(`rc=0`,0 冲突)再加下面两处修补。 ## 今天新合的两道门抓到了它两处 上一轮我测过「#825 引入新失败 0」,那句话当时是真的 —— 但那两道门是**今天晚些时候** 才合进 main 的,门槛抬高之后它就红了: 1. `test-suite-registration`(#1003) `tests/test813-grok-mcp-readiness/` 是新增套件,没有任何 CI 会跑它。 🔴 这条特别值得修而不是豁免:**#825 的目的就是「MCP 没就绪时 fail closed」, 而验证这件事的套件如果不进 CI,fail-closed 这个保证就没有任何东西持续守着。** 照 test831 的同构做法接进 qa.yml:两处 `paths` + build/run 两个 step。⚠️ 它的 Dockerfile 收的 build-arg 叫 `SOURCE_COMMIT`(不是 831 的 `TEST831_SOURCE_COMMIT`),容器里由 `ENV TEST813_SOURCE_COMMIT` 承接 —— 照抄 831 的参数名会静默拿不到值。 2. `doc-symbol-pins`(#1002) `docs/message-lifecycle.md` 把 `shouldSkipMessage` 钉在 `cli.ts#L4639`, 而 #825 给 cli.ts 加了 54 行,真值现在是 **4662**。 文本 `cli.ts:4639` 和 URL `#L4639` 是同一句话的两副面孔,两处都改 —— 只改 URL 会留下渲染出来给人读的那个错数字。 ## 验证 rebase 到 origin/main rc=0,0 冲突,9 个补丁 test-suite-registration rc=0 suites=198 registered=34 orphans=164 new=0 doc-symbol-pins rc=0 l1-paths-sync / qa-trigger-coverage / workflow-structure / docs-integrity / no-escaped-comments 全部 rc=0 `registered` 从 33 变 34、`orphans` 仍是 164 —— 新套件是接进 CI 了,不是塞进基线蒙混。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(test813): 一条从写下起就是空的变异 —— 接进 CI 的第一次运行就把它照出来了 把 test813 接进 CI(本 PR 上一个提交)之后,它在 GitHub runner 上第一次运行就红: MCP_READINESS_PASS tools=commhub_get_all_status,commhub_send_message,commhub_send_task,commhub_upload_file FAIL: mutation survived: upload-tool-removed MCP_READINESS_PASS tools=…(同一份列表,commhub_upload_file 仍在) 不是产品没拦住,是**变异根本没发生**: sed -i '/^[[:space:]]*"commhub_upload_file",[[:space:]]*$/d' agent-network/src/node-server.ts 那个模式要求整行只有 `"commhub_upload_file",`,而真实那行是 ` name: "commhub_upload_file",`(对象字面量的字段)。实测命中 **0** —— 在 origin/main 上也是 0,**它从写下那天起就没匹配过任何一行**。 套件此前不在任何 CI 里(#861 说的 164 个孤儿之一),所以没人见过它红。 删整行会破坏对象字面量语法,改成改名: sed -i 's/name: "commhub_upload_file"/name: "commhub_upload_file_MUT"/' … 干跑验证:文件确实变了(`243: name: "commhub_upload_file_MUT",`),已还原。 ## 顺带堵住这一类,不只这一条 给 `expect_red` 加空变异防护:跑完变异命令后,若两个源文件**都**没被改动就直接判红, 并说清楚是「sed 模式和源码对不上」而不是「产品没拦住」。 这两种结论指向完全不同的下一步 —— **去改产品 vs 去改测试** —— 而它们在没有这道防护 时打印出来是同一句 `mutation survived`。 同一个套件里另外三条 sed 都逐条查过,各自命中 1(其中打 fake-grok.mjs 那条还自带 `grep -Fxc … -eq 1` 基数守卫),只有这一条是空的。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: t <internlmorg@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* feat(grok): add strict repo-read copresence profile * docs(tests): record restacked Grok repo-read evidence * feat(grok): 把 #826 的 strict repo-read 共存档位落到 main grok 栈 `#825 → #826 → #830 → {#836,#867}` 的第二层。#825 已由 #1004 落地 (main `89a6164e`),所以这一层现在可以直接对 main 落。 **没有 force-push #826 那条共享 draft 分支**,本 PR 从我自己的分支发。 ## rebase 方式:只取它自己那两个提交 直接 `git rebase origin/main` **会冲突** —— 冲在 `436b4bdb fix: fail closed on broken Grok CommHub MCP`,那是 **#825 自己的提交**,已经以 squash 形式在 main 上了,而 #826 的历史里还带着它。 正确做法是把它自己那部分接到 main 上: git rebase --onto origin/main <#825-head> <#826-head> rc=0 它自己的两个提交: 4496835 feat(grok): add strict repo-read copresence profile 1149676 docs(tests): record restacked Grok repo-read evidence 结果 12 files changed, 284 insertions(+), 36 deletions(-)。 ## 今天这套门抓到一处 `doc-symbol-pins`:`docs/message-lifecycle.md` 把 `shouldSkipMessage` 钉在 `cli.ts#L4662`,而本层又往 `cli.ts` 加了行,真值变成 **4669**。文本和 URL 两处都改。 🔴 **这是同一条 pin 今晚第二次漂**(#1004 刚把它从 4639 改到 4662)。 往 `cli.ts` 这种热点文件钉**行号**,几乎每个碰它的 PR 都会把它顶漂 —— 改成只钉符号、不钉行号才是根治,但那是另一条改动,不在这里顺手做。 其余全绿:test-suite-registration(suites=198 registered=34 orphans=164 new=0)/ doc-source-pins / no-escaped-comments / no-memory-slugs / home-path-baseline / public-script-safety / l1-paths-sync / copresence-profile-pin。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: t <internlmorg@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* fix(grok): deny vendor terminal tool in copresence * docs(tests): record Grok terminal deny evidence * fix(grok): deny native effectful tool surface * chore(grok): reset superseded terminal deny report * docs(test): record exact Grok native deny evidence * fix(grok): close pinned native tool inventory * docs(test): record pinned Grok tool boundary
这条的内容已落到 main(#1008,
|
| 文件 | 新增行 | 在 main 上找不到 |
|---|---|---|
agent-node/src/runtime/grok-copresence/policy.ts |
39 | 0 |
agent-node/src/runtime/grok-copresence/runtime.ts |
11 | 0 |
agent-node/src/runtime/grok-copresence/runtime.test.ts |
12 | 0 |
agent-node/src/runtime/grok-copresence/profile-process.test.ts |
32 | 0 |
docs/tests/report-grok-copresence-terminal-deny.txt |
99 | 0 |
5 个文件、193 行新增,一行不缺。
这一层没有触发任何一道门
前两层各触发过一次 doc-symbol-pins 行号漂移;这一层八道门直接全 rc=0。
栈的进度
#825 已落地 #1004 → main 89a6164e 已关闭
#826 已落地 #1006 → main c85dca96 已关闭
#830 已落地 #1008 → main 526163cd 本条
#867 下一个 —— 含 #883(P0) 点名的 b830403b,分支已备好、预跑抓到的三处已修
#836 最后 —— 只有 1 个提交,用 cherry-pick(range rebase 会撞已合提交)
What changed
AvailableCommandsUpdate._meta.toolsas the native-tool denominator because interactivetoolsprofiles are not a complete permission boundary;commhub-only,x-search, andrepo-readread/search capabilities;Bash/Write/WebFetchcompatibility denies;Why
A prompt-contained review explicitly prohibited tools, yet Grok rendered
Run No-op; review is prompt-onlyand emitted:The old argv denied only
Bash. The supervisor failed closed withapproval_boundary, but only after successful terminal execution. A second denominator audit then found that a terminal-only or partial effectful list was also insufficient: pinned 0.2.93 advertises native write, scheduler/control, fetch, and media names outside the generated profile.Frozen coordinates
114967626f20c7ef036c3d0e0dab295e1f983a89(feat(grok): add strict repository-read co-presence profile #826 report head)433b4af44bdcc09145c75b697634f74aec42a7dfd51a4473f6aea75547437150dba729524506062bsha256:df3b83526409d21ece60f0a5a12589e0fc0933616af617ea83abd6e1416deb1cThis PR is stacked on #826 and must not merge before #825 and #826.
Validation
1284 pass / 0 fail / 4609 expect / 91 files;54 pass / 0 fail / 655 expect / 2 files;run_terminal_command,write,scheduler_create,web_fetch,image_edit, profile-specificread_file, and profile-specificweb_search;Honest limits
run_terminal_commandwas observed live. Other captured names are explicit preventive boundaries, not claims that each is reachable.