Skip to content

fix(report): 为主编排回注补充 IPC 鉴权 - #779

Open
wzono wants to merge 4 commits into
deepcoldy:masterfrom
wzono:fix/report-daemon-ipc-auth
Open

fix(report): 为主编排回注补充 IPC 鉴权#779
wzono wants to merge 4 commits into
deepcoldy:masterfrom
wzono:fix/report-daemon-ipc-auth

Conversation

@wzono

@wzono wzono commented Aug 7, 2026

Copy link
Copy Markdown

改动

  • 同机 dispatch 的 botmux report 在可读取宿主密钥时继续使用 fetchDaemonIpc,为最终 /api/trigger 请求补齐 HMAC 鉴权。
  • 在 credential-only bwrap / macOS read isolation 场景新增窄口 /api/report-relay:隔离 CLI 只向当前 Bot daemon 提交轮换的会话 capability。
  • credential-only worker 在 Linux bwrap 与 macOS Seatbelt 上都为每个 session 发布独立 capability 目录:bwrap 以 tmpfs 屏蔽父目录后只读绑定当前子目录;Seatbelt 先 deny 父目录,再仅 allow 当前子目录并保持父目录不可写。兄弟会话凭据不可见,原子 rename 轮换仍能被长驻 CLI 观察到。
  • source daemon 校验当前会话、轮次和 dispatch root,从宿主 dispatch registry 派生目标 app/session,再用宿主 HMAC 向主编排 daemon 转发固定的 untrusted report envelope;调用方不能自选来源或目标身份。
  • relay 请求体限制为 256 KiB,并拒绝 receiver、过期 capability、跨轮次或跨 root 的请求。
  • 隔离 pane marker 升至 v11,旧的 bwrap/Seatbelt credential-only pane 会冷启动,避免 warm reattach 继续使用缺少新 mount/profile/env 的进程。

原因

Daemon 的 /api/trigger 在非 core-only 模式要求 X-Botmux-Cli-* 鉴权头。原实现直接请求 loopback HTTP,因缺少签名头被鉴权中间件以 401 missing_headers 拒绝。第一次修复改用 fetchDaemonIpc 后,credential-only bwrap 又会因为刻意屏蔽 .dashboard-secret 而无法签名;第二次只补读取端仍不完整,因为 worker 尚未发布 capability。最终方案由 worker 发布当前 session/turn 的私有轮换能力,最终 HMAC 签名始终留在可信 daemon 中。

影响面

  • 仅影响命中 dispatch 注册表、向同机主编排 daemon 回注的 report 路径,以及复用同一会话能力传输的隔离 CLI IPC。
  • issue in-review 与普通 Lark message report 路径保持不变。
  • 新增的未签名入口仅允许固定 relay route,业务 handler 内继续做 session capability 与服务端身份绑定校验。

验证

  • 相关 12 个测试文件:390/390 通过(覆盖 capability 发布/读取、private bwrap carve-out、reattach marker、session relay、IPC auth、dispatch 与 fs-policy)。
  • pnpm build:通过。
  • 真实 bwrap 验证:当前 session capability 在宿主原子轮换 v1→v2 后对长驻子进程可见,兄弟 session 目录不可见。
  • 全量单测检查中,platform-http-family.test.ts 有 2 例受当前宿主 localhost IPv6 解析环境限制;v3-distillation-runner.test.ts 的并发超时用例单独重跑 33/33 通过。

@wzono
wzono requested a review from deepcoldy as a code owner August 7, 2026 06:51

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f7e7320290

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli.ts Outdated
let response: Response;
try {
response = await fetch(`http://127.0.0.1:${daemon.ipcPort}/api/trigger`, {
response = await fetchDaemonIpc(daemon.ipcPort, '/api/trigger', {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Route credential-isolated reports through a trusted relay

On Linux hosts with device credential isolation enabled but the per-bot file sandbox disabled, the credential-only bwrap wrapper deliberately masks .dashboard-secret while leaving the dispatch registry and daemon descriptors readable. This branch is therefore reachable, but fetchDaemonIpc calls loadDaemonIpcSecret() before sending anything and throws, so every registry-backed botmux report still fails instead of reaching the orchestrator. Use a daemon-side relay or a session-scoped capability path rather than requiring the agent process to read the host HMAC secret.

AGENTS.md reference: AGENTS.md:L54-L58

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。credential-isolated CLI 不再读取 host HMAC:它改为携带当前轮换的 session capability 请求 source daemon 的 /api/report-relay。该 handler 会绑定 live session / turn / dispatch root,从宿主 registry 派生目标身份,并由 daemon 使用 HMAC 转发固定的 untrusted report envelope;调用方提交的 source/target 字段不会被信任。补充的授权与 wiring 回归覆盖了缺失、错误、过期 capability,跨 root/turn、身份夹带、receiver 拒绝和 256 KiB body limit;相关 323/323 测试及 pnpm build 均通过。修复提交:37b64f8a。

@wzono

wzono commented Aug 7, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37b64f8a1f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli.ts
Comment on lines +8983 to +8987
const originClaim = readManagedOriginCapability(
resolveDataDir(),
sid,
relayDir,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Publish a capability for credential-only isolation

When device credential isolation is enabled but the full file sandbox is disabled, this fallback still cannot authenticate: BOTMUX_SEND_RELAY is unset, while the worker creates neither a Linux relay-outbox capability nor a read-isolation/origin-*.json file for credential-only bwrap, so originClaim is null and /api/report-relay rejects the request with origin_unproven. Fresh evidence after the prior thread is that the new client now reads this capability, but the credential-only worker path was not updated to publish it; therefore the scenario this commit intends to fix still breaks every registry-backed report. Publish a child-readable rotating capability for the credential-only path or provide another session-scoped transport.

AGENTS.md reference: AGENTS.md:L54-L58

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已补齐 capability 生产端。credential-only worker 现在为每个 session 创建私有轮换目录,bwrap 先用 tmpfs 屏蔽整个 read-isolation 父目录,再只读绑定当前 session 子目录;因此 sibling capability 不可见,同时目录 bind 能观察 atomic rename 后的新 token。worker 在 fresh spawn 与 safe reattach 都会发布当前 session/turn capability,并通过 BOTMUX_ORIGIN_CAPABILITY_DIR 指向该目录;pane marker 升至 v10,使缺少新 mount/env 的旧 pane 强制冷启动。真实 bwrap 验证覆盖了 token v1→v2 轮换可见与 sibling 隐藏,相关 389/389 测试及 pnpm build 通过。修复提交:0f656a86。

@wzono

wzono commented Aug 7, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f656a86ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/worker.ts Outdated
}
if (!willReattachPersistent && credentialOnlyBwrap) {
let credentialOnlyCapabilityDir: string | undefined;
if (credentialOnlyBwrap) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Provision the relay capability for credential-only Seatbelt

On macOS when device credential isolation is active but the full file sandbox is disabled, the credential-only Seatbelt profile masks the host HMAC secret, but this new capability publication is guarded exclusively by credentialOnlyBwrap. The existing macOS capability setup is inside if (sandboxRequested), so this combination has neither the secret nor its own published claim; botmux report consequently submits no originCapability and /api/report-relay rejects every registry-backed report with origin_unproven. Add an equivalent current-session capability transport and carve-out to the credential-only Seatbelt path.

AGENTS.md reference: AGENTS.md:L54-L56

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已补齐 macOS credential-only Seatbelt。worker 现在对 Seatbelt 与 bwrap 共用同一套 per-session capability 发布与 BOTMUX_ORIGIN_CAPABILITY_DIR 注入;Seatbelt profile 先 deny 整个 read-isolation 父目录,只授予父目录 metadata traversal 和当前 session 子目录 read,并在后序规则继续 deny 父目录 write,因此 sibling capability 不可读、当前轮换文件可读且不可写。pane marker 升至 v11,缺少新 profile/env 的 v10 Seatbelt pane 会冷启动。TDD 用例先复现缺失路径,相关 390/390 测试及 pnpm build 通过。修复提交:88169d58。

@wzono

wzono commented Aug 7, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88169d58f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +91 to +98
const rawEntry = input.registry[dispatchRoot];
const entry = rawEntry && typeof rawEntry === 'object' && !Array.isArray(rawEntry)
? rawEntry as Record<string, unknown>
: undefined;
const targetLarkAppId = typeof entry?.orchAppId === 'string' ? entry.orchAppId.trim() : '';
const targetSessionId = typeof entry?.orchSessionId === 'string'
? entry.orchSessionId.trim()
: '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Protect relay targets from a writable dispatch registry

When device credential isolation is enabled without the full file sandbox, both credential-only wrappers still permit writes to orchestrate-dispatch.json (bwrap binds / read-write, while the Seatbelt profile only protects credential/profile paths). An isolated CLI can therefore copy any other live orchAppId/orchSessionId tuple from the readable registry into its own capability-bound dispatch-root entry, then call this relay; these lines treat that caller-modified entry as trusted and send an HMAC-authenticated trigger into the victim session. Bind the target to host-owned immutable provenance, authenticate registry entries, or make this registry host-write-only before using it as an authorization source.

AGENTS.md reference: AGENTS.md:L54-L58

Useful? React with 👍 / 👎.

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