Skip to content

fix(grok): audit the canonical CommHub MCP target - #836

Draft
vansin wants to merge 1 commit into
fix/grok-copresence-deny-terminal-toolfrom
agent/grok-copresence-canonical-mcp-target
Draft

fix(grok): audit the canonical CommHub MCP target#836
vansin wants to merge 1 commit into
fix/grok-copresence-deny-terminal-toolfrom
agent/grok-copresence-canonical-mcp-target

Conversation

@vansin

@vansin vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

What changed

  • pass the resolved canonical CommHub Bun command into the Grok co-presence ownership audit
  • require the doctor target to match that exact command instead of the historical bare bun spelling
  • add positive absolute-path and negative mismatch coverage

Why

#825 changed the generated MCP command from bare bun to a canonical absolute executable. The #830 pre-spawn ownership audit still compared the doctor target against bare bun, so the reviewed stack failed closed on the real host even though doctor reported a healthy four-tool CommHub server.

Scope and topology

Validation

  • focused Grok co-presence runtime tests passed in Docker
  • exact agent-node build completed in Docker
  • single-node live candidate: real Grok 0.2.93 TUI reached input-ready; doctor reported healthy_count=1, failing_count=0, and all four checks including 4 tools discovered
  • human TUI input returned TUI_HUMAN_OK
  • inbound CommHub task reached replied; TUI-originated send_task was accepted and acked

Live validation is deployment evidence for this exact source, not merge or release authorization. Rollback coordinates remain outside Git because they contain machine-local runtime state; the repo runbook records their required shape and non-secret recovery procedure.

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

我把这个 PR 与 #836合成体放进真门跑了一遍:绿

背景:这两个 PR 都改 agent-node/src/runtime/grok-copresence/*.tscli.ts,
内容不同却不冲突 —— git 会静默合出一个谁都没审过的版本(这一类我在 #856 里量到 45 处)。
所以"各自 CI 绿"并不覆盖合成体。

真合 + 跑 test725 这道门自己的容器(不是我另写的等价物):

临时 worktree ← origin/main ← #826 ← #836     两次 merge 均干净
合成体 SOURCE_COMMIT=fc221fc5f783d0a09e1fa427860f7c88a5825919

docker build --build-arg SOURCE_COMMIT=$SHA -f tests/test725-agent-node-unit-ci/Dockerfile .
docker run --rm <image>

  # test725 — complete agent-node unit domain
  source_commit=fc221fc5f783d0a09e1fa427860f7c88a5825919
  1284 pass   0 fail   Ran 1284 tests across 91 files. [115.18s]
  RESULT: PASS                                                     退出码 0

合成体在这道门上是绿的。 这不是对两个 PR 各自的评审意见,只回答一个问题:
它们合在一起会不会把 agent-node 单测域弄坏 —— 不会。

顺带一个值得知道的对照(已单独立为 #865)

同一棵合成体,在宿主机上跑 bun test src/42 条红;进 Docker 是 0 红
那 42 条全部落在 runtime.test.ts(39)与 grok-build-cli-home.test.ts(3)——
正是这两个 PR 改的文件。原因是环境,不是代码:

TMPDIR=/tmp(默认)  35 × grok-build-cli project is busy; concurrent turns are refused
                        ← 单测去抢本机真实 grok 节点正持有的 /tmp 全局锁
TMPDIR=干净空目录     40 × leader socket path is too long for a Unix socket

所以在本机跑这两个文件的单测,结果不可用;要判断这块有没有回归,只能走 Docker 门。
本条的绿就是这么取的。

(只读:worktree 已 git worktree remove,我建的镜像已 docker rmi;
未改任何 PR、未 approve、未 merge。)

@vansin

vansin commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

独立审 · #836(栈的叶子)—— CLEAN,建议随栈合并。一条 NIT

线9 这条栈里,#825(独立)、#826#830 三个都已有钉在当前 head 的 CLEAN 判定;
只有本 PR 从来没有被独立审过。补上。

先说结构,因为它影响怎么合:

git merge-base --is-ancestor:
  #826 ⊂ #830 ⊂ #836        ← 一条栈,#836 是叶子,已含前两个
  #825 独立(与三者互不为祖先),距 origin/main 9 个提交

所以线9 要落地的是两件东西:叶子 #836 与独立的 #825 —— 不是四个并行 PR。
(合叶子等于把 #826/#830 一起带进去,所以它们的 CLEAN 判定同样是前提。)

一、改动本体:3 个文件 25 增 2 删

agent-node/src/runtime/grok-copresence/runtime.ts       +3 -1
agent-node/src/runtime/grok-copresence/runtime.test.ts +18
agent-node/src/cli.ts                                   +6 -1

核心就一行:

-  || commhubRecord.target !== "bun"
+  || commhubRecord.target !== expectedCommhubTarget

判据是精确相等,不是前缀/形状匹配 —— 这点对(白名单类判据一旦退化成形状匹配就会放行近似值)。

🔴 二、我重点查的是调用侧:审计用的值和生成用的值是不是同一个

这类改动最容易出的问题是生成器和审计器各算一遍规范路径,然后悄悄漂开。实测不是:

cli.ts:3629   const commhubMcpCommand = resolveGrokCommhubMcpCommand(…)   ← 只算一次
cli.ts:3642         command: commhubMcpCommand,                           ← 用它生成 MCP 配置
cli.ts:3738         commhubMcpCommand,                                    ← 用同一个值做审计

同一个变量、单一来源。 所以无论 resolveGrokCommhubMcpCommand 在某台机器上解析出
绝对路径还是别的拼写,两侧永远一致 —— 这比"把绝对路径也加进允许列表"稳。

全仓非测试调用点只有 cli.ts:3735 这一处(git grep 全量列出),没有遗漏的旧调用方。

三、fail-closed 没有被削弱

assertGrokCopresenceApprovalOwnership 的前置分支我通读了:JSON 非法 / 缺 permissions /
sources / 来源不是绝对路径 / 来源逃出隔离 HOME —— 五处全部 throw,
本 PR 一处都没动,只在最后的目标比对上增加了参数。方向是收紧,不是放松。

四、测试正负都有

+ 规范绝对路径 /opt/runtime/bin/bun 作为期望值 → not.toThrow()
+ 传 "/different/bun"                          → toThrow("runtime-owned commhub")

五、门:我在本 PR 的确切 head 上跑过真容器

SOURCE_COMMIT=fc221fc5f783d0a09e1fa427860f7c88a5825919   (= 本 PR 当前 head)
docker build/run tests/test725-agent-node-unit-ci
  1284 pass  0 fail  Ran 1284 tests across 91 files [115.18s]
  RESULT: PASS                                        退出码 0

更正我自己:我先前把这次运行描述成「#826 × #836 合成体」的验证。
那是错的 —— #826#836 的祖先,两次 git merge 实际是 fast-forward,
得到的就是 #836 的 head。所以这个结果是对本 PR 单独的验证(它已含 826+830),
不是"两个并行 PR 合起来"的证据。结论不变,但证明的对象要说准。

🟡 NIT(不挡合并):expectedCommhubTarget = "bun" 这个默认值

参数带默认值 "bun",意味着任何忘记传的调用方都会静默退回旧比较——
而"旧比较"正是本 PR 要修的那个 bug(真实主机上目标是绝对路径,比 "bun" 必然不等 → 误报)。

现在只有一个非测试调用方且它传了值,所以当下不可达。但它是个安放好的绊子:
下次有人加第二个调用点、忘了传,症状是共存在那台机器上直接起不来,而代码看着没问题。

建议把它改成必填参数(TS 会在编译期指出漏传),或至少在默认值旁写一行注释说明
"这是历史兼容值,新调用方必须显式传"。纯防御性,不影响本 PR 的正确性。

结论

CLEAN。 建议按栈合并:#826 → #830 → #836(或直接合叶子 #836),
#825 独立,可单独走。四个都是 Draft —— 转正/合并的时机由 owner 决定,我不推动。

(只读:git diff / git grep / 临时 worktree(用完即 remove)/ Docker 真跑那道门自己的容器;
未改本 PR、未 approve、未 merge、未碰任何在跑节点。)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant