feat: replace tool permissions with session sandbox boundaries - #1581

Merged
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary
Jul 29, 2026
Merged

feat: replace tool permissions with session sandbox boundaries#1581
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace additional permissions, one-call sandbox escalation, and the live generic tool-approval path with one revisioned, session-scoped ExecutionBoundary authority.
  • Persist genesis boundaries, immutable expansion requests, and applied revisions in the SQLite session metadata store. Approval and boundary advancement commit atomically; stale, duplicate, and concurrently decided requests settle deterministically.
  • Keep the expansion schema no broader than the product needs today: exact/subtree filesystem read/write entries plus session network enablement. Tools report exact sandbox_boundary_required deltas or requires_bypass; Bash diagnostics never parse commands or invent authority.
  • Wire the boundary lifecycle end to end through core, storage, runtime, Runtime Host, session bundles, Desktop/shared UI, TUI, headless/Harbor, and non-interactive CLI. Desktop and TUI expose Auto/Bypass, boundary prompts take over the composer, and Bypass requires an explicit second confirmation.
  • Remove the superseded PermissionEngine matrix, grant ingress, generic permission prompts, and legacy live escalation executors in the same PR so no dual-authority intermediate state ships. Historical codecs and settled audit history remain readable; OS Permission Center behavior is unchanged.

Closes#1564

Verification

  • npm run build — passed across all workspaces.
  • npm run test:dist — passed the complete repository suite with the workspace runner in serial mode, including script contracts (176/176), storage (733 passed, 1 skipped), Runtime (2675 passed, 9 skipped), Runtime Host (212/212), and Desktop (2964/2964).
  • npm run format:check — passed, 1221 files checked.
  • npm run lint — passed, 2304 files checked.
  • npm run typecheck — passed across all workspaces.
  • node --test packages/runtime/dist/__tests__/macos-seatbelt-smoke.test.js packages/runtime/dist/__tests__/filesystem-worker-smoke.test.js — passed (9/9), including exact outside-path expansion and restricted network behavior.
  • npm run e2e -w @maka/desktop -- e2e/sandbox-boundary-takeover.spec.ts — passed (1/1), covering the visible Desktop composer takeover and approval journey.
  • The all-workspace parallel npm test command intermittently exhausted a Runtime Host test's local timing window under machine load. That package passed independently (212/212), and the complete serial repository run above passed; this PR does not broaden into unrelated test-harness timing changes.

Migration and breaking change

  • Legacy ask and execute sessions enter the managed workspace-write boundary; explore enters managed read-only; bypass remains bypass. First access durably records revision 0 without rewriting settled historical records.
  • Pending legacy permission interactions close with host_restarted during recovery because their live continuation authority cannot survive the upgrade.
  • Interactive surfaces now expose only Auto and Bypass. Removed permission modes and per-tool grant flags fail during CLI argument validation.
  • maka run defaults to Auto and cannot interactively expand a boundary, so it fails closed when expansion is requested. Only explicit --yolo creates or resumes a bypass session.
  • Headless/Harbor sessions explicitly use the external boundary; imports and exports preserve the authoritative boundary even though the SQLite database itself is not bundled.

Review focus

  • The SQLite transaction boundary around request settlement and boundary revision advancement, including cross-connection races.
  • The runtime continuation/publication barrier when a sandbox boundary or user question is pending, including durable denial when a turn closes.
  • The cross-surface fail-closed behavior for ordinary expansion requests versus requires_bypass.
  • The branch contains 105 small, reversible commits ordered from contracts and storage through runtime, surfaces, legacy-path removal, and regression coverage.

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 6f15924 to d481739CompareJuly 29, 2026 01:50
@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

Review outcome

Request changes.

I reviewed the final PR head d481739 against the accepted contract in #1564 and the guarantees stated in this PR body. The SQLite transition work, prompt settlement, --yolo protection, boundary persistence, and Linux sandbox tests are meaningful improvements, but several execution paths still violate the central invariants of this change.

The latest rebase and the final d481739 cleanup commit do not change the sandbox semantics described below.

Contract used for this review

The accepted #1564 contract requires:

  • one authoritative, session-scoped ExecutionBoundary;
  • managed execution to fail closed when enforcement is unavailable;
  • an exact, reachable expansion flow for process network and filesystem boundaries;
  • External execution only when an explicit external isolation owner exists;
  • Deep Research to remain internally managed and read-only;
  • child Agents to inherit the parent boundary;
  • non-interactive Auto to exit nonzero when an unavoidable boundary requirement cannot be resolved; and
  • session bundles to restore the authoritative boundary.

The alternative proposals to enable network by default, automatically fall through to Bypass, or treat user-provided paths as implicit authorization were explicitly rejected in the issue discussion. These findings are evaluated against the accepted issue body, not those alternatives.

Blocking findings

1. [P1] Managed filesystem tools fail open when the filesystem worker is unavailable

Desktop and CLI conditionally omit the filesystem worker when the platform cannot provide the built-in worker sandbox. buildBuiltinTools then falls back to createLocalWorkspaceExecutor, and Write/Edit/Read execute on the host instead of rejecting managed execution.

Relevant paths:

I reproduced this on the final head: a Write call under an explore/read-only boundary successfully created a file when no worker was supplied.

Managed execution must return an enforcement-unavailable failure before reaching the host executor. The host path should only be reachable for an explicit Bypass or harness-owned External boundary.

2. [P1] The first process-network expansion has no valid request path

Auto starts with restricted process network, but Bash has no declarative network requirement. A denied command returns only a likely sandbox-denial signal, without sandbox_boundary_required or a concrete network expansion:

Runtime guidance simultaneously states that the Agent must not infer an expansion and may request one only after a tool returns an exact expansion:

I reproduced an EPERM network denial with sandboxType: linux; the failure contained no required expansion. Commands such as npm install, git pull, and curl therefore cannot reach the session-level network approval flow required by #1564.

This needs a declarative, non-authorizing process-network requirement or an equally reliable backend signal that can produce the exact expansion without parsing command text.

3. [P1] An External session can resume in Desktop/TUI as Auto while Bash runs without a Maka sandbox

Imported session bundles can restore an External boundary. Bash treats both Bypass and External as instructions to skip the Maka sandbox:

Desktop maps every non-Bypass boundary to Auto, while TUI session switching continues to project the legacy permissionMode:

maka run correctly rejects this resume path, but ordinary Desktop and interactive TUI do not. The result is an Auto-labelled session executing host Bash without the external harness that supposedly owns isolation.

External sessions must be rejected by ordinary interactive surfaces unless an explicit external-isolation owner is injected. External must also never be presented as Auto.

Additional correctness gaps

4. [P2] Deep Research can request and receive write or network expansion

Deep Research starts with a managed read-only profile, but Desktop still includes the complete builtin surface and unconditionally exposes request_sandbox_boundary:

Storage applies an approved expansion to any managed profile, including read-only:

I reproduced approval of a network expansion on a Deep Research session. The resulting profile was still named read-only, but its network state was enabled.

The Deep Research surface should omit mutation tools and the boundary-request tool, and its internal read-only boundary must not be expandable into write or process-network authority.

5. [P2] Child boundary persistence is fixed, but filesystem execution does not fully inherit Bypass or External

The parent boundary is now persisted into the child correctly. However, the child header still uses the Agent definition’s legacy permission mode, and the filesystem worker only consumes managed boundaries:

For an inherited Bypass or External boundary, filesystem execution falls back to the child definition’s legacy profile. The same child can therefore run Bash according to the inherited boundary while Read/Write/Edit follow a different authority.

Boundary handling in the filesystem client should be exhaustive: managed, bypass, and external must each have explicit semantics, with no fallback to permissionMode.

6. [P2] Non-interactive Auto can still return exit code 0 after an unresolved boundary failure

maka run does not register the boundary-request tool. It marks the command as failed only after receiving a sandbox_boundary_request event:

A filesystem tool can instead return sandbox_boundary_required as an ordinary structured tool failure. If the model then produces a normal final answer explaining that it could not complete the task, the invocation remains completed and maka run returns 0.

An unresolved boundary requirement must become a terminal non-interactive invocation outcome, independently of whether a request event was published.

7. [P2] A session bundle does not read its header and boundary from one SQLite snapshot

The bundle exporter writes selected session metadata and the selected boundary through two independent exporter calls:

A concurrent Auto/Bypass transition between those reads can export a header from one revision and a boundary from another. Import then accepts both as the new genesis state.

Storage should provide one read transaction that returns an immutable portable { header, boundary } snapshot before either transfer file is written.

Implementation-quality concern

The Runtime public boundary contract still permits the authoritative reader to be absent:

All current first-party production call sites appear to provide the reader, so I am not treating this as a separate exploit. However, the public API still silently reconstructs authority from header.permissionMode, which preserves the dual-authority fallback that this PR claims to remove.

The boundary reader should be required. Interactive expansion support can be represented separately as an explicit enabled/disabled capability.

There are also several source-regex and collaborator-call tests that lock implementation shape rather than public behavior. I do not use those as the primary basis for this review, but they should be replaced with behavioral coverage while these paths are being corrected.

Validation

On final head d481739:

  • npm run build:test passed.
  • Linux sandbox smoke passed, 7/7.
  • Linux filesystem-worker smoke passed, 2/2.
  • SQLite session metadata tests passed, 30/30.
  • git diff --check a454b9a..d481739 passed.
  • GitHub typecheck, test, and e2e checks are green.

The green suite validates the supported sandbox path, but it does not cover the fail-open worker-unavailable path or the cross-surface inconsistencies above.

简体中文

审查结论

Request changes。

我基于 #1564 的已接受契约与本 PR body 声明的保证,对最终 head d481739 进行了审查。SQLite transition、Prompt settlement、--yolo 保护、boundary 持久化和 Linux sandbox 测试都是有价值的改进,但若干执行路径仍违反这次改动的核心不变量。

最新 rebase 与最终的 d481739 cleanup commit 没有改变下述 sandbox 语义。

本次审查采用的契约

已接受的 #1564 契约要求:

  • 每个 session 只有一个 authoritative、session-scoped ExecutionBoundary
  • enforcement 不可用时,managed execution 必须 fail closed;
  • process network 与 filesystem boundary 必须具有精确且可达的 expansion 流程;
  • External execution 只能在存在显式 external isolation owner 时使用;
  • Deep Research 必须保持内部 managed read-only;
  • 子 Agent 必须继承父 session boundary;
  • 非交互 Auto 遇到无法解决且不可避免的 boundary requirement 时必须非零退出;
  • session bundle 必须恢复 authoritative boundary。

Issue 讨论中关于默认启用 network、自动退化到 Bypass,以及把用户给出的路径视为隐式授权的替代提案已经被明确拒绝。以下 findings 以已接受的 issue body 为准,不采用这些替代提案。

阻塞问题

1. [P1] Filesystem worker 不可用时,managed filesystem tool 会 fail open

当平台无法提供内置 worker sandbox 时,Desktop 与 CLI 会有条件地省略 filesystem worker。buildBuiltinTools 随后退回 createLocalWorkspaceExecutor,导致 Write/Edit/Read 在 host 上执行,而不是拒绝 managed execution。

相关路径:

我在最终 head 上完成了复现:未提供 worker 时,explore/read-only boundary 下的 Write 成功创建了文件。

Managed execution 必须在进入 host executor 前返回 enforcement-unavailable failure。Host 路径只能由显式 Bypass 或 harness-owned External boundary 访问。

2. [P1] 首次 process-network expansion 没有合法的请求路径

Auto 默认限制 process network,但 Bash 没有声明 network requirement 的字段。命令被拒绝时只返回可能的 sandbox-denial signal,不包含 sandbox_boundary_required 或具体 network expansion:

Runtime guidance 同时要求 Agent 不得推断 expansion,且只有在工具返回精确 expansion 后才能请求:

我复现了带有 sandboxType: linuxEPERM network denial,但 failure 中没有 required expansion。因此 npm installgit pullcurl 等命令无法进入 #1564 要求的 session-level network approval 流程。

这里需要一个声明式且本身不授予权限的 process-network requirement,或同样可靠的 backend signal,以便在不解析 command text 的情况下生成精确 expansion。

3. [P1] External session 可以在 Desktop/TUI 中以 Auto 恢复,同时 Bash 不受 Maka sandbox 约束

导入的 session bundle 可以恢复 External boundary。Bash 将 Bypass 和 External 都视为跳过 Maka sandbox 的指令:

Desktop 把所有非 Bypass boundary 映射为 Auto,而 TUI session switching 继续投影 legacy permissionMode

maka run 已经正确拒绝该 resume 路径,但普通 Desktop 与交互式 TUI 没有拒绝。最终结果是:一个标记为 Auto 的 session 在缺少原定 external harness 的情况下执行 host Bash。

除非注入显式 external-isolation owner,否则普通交互式 surface 必须拒绝 External session。External 也绝不能显示为 Auto。

其他正确性缺口

4. [P2] Deep Research 可以请求并获得 write 或 network expansion

Deep Research 从 managed read-only profile 开始,但 Desktop 仍包含完整 builtin surface,并无条件暴露 request_sandbox_boundary

Storage 会把已批准的 expansion 应用到任意 managed profile,包括 read-only:

我复现了 Deep Research session 的 network expansion approval。结果 profile 仍名为 read-only,但 network state 已变为 enabled

Deep Research surface 应移除 mutation tool 与 boundary-request tool,其内部 read-only boundary 也不应扩张为 write 或 process-network authority。

5. [P2] Child boundary 已正确持久化,但 filesystem execution 没有完整继承 Bypass 或 External

Parent boundary 现在已经能正确持久化到 child。但 child header 仍使用 Agent definition 的 legacy permission mode,而 filesystem worker 只消费 managed boundary:

对于继承的 Bypass 或 External boundary,filesystem execution 会退回 child definition 的 legacy profile。同一个 child 因而可能让 Bash 遵循 inherited boundary,却让 Read/Write/Edit 遵循另一套 authority。

Filesystem client 应穷举处理 managed、bypass 与 external,不能再退回 permissionMode

6. [P2] 非交互 Auto 在 boundary failure 未解决后仍可能返回退出码 0

maka run 不注册 boundary-request tool。它只有在收到 sandbox_boundary_request event 后才把命令标记为失败:

Filesystem tool 也可能只把 sandbox_boundary_required 作为普通 structured tool failure 返回。如果 model 随后正常输出无法完成任务的说明,invocation 仍是 completed,maka run 最终返回 0。

未解决的 boundary requirement 必须成为非交互 invocation 的 terminal failure,不能依赖是否发布了 request event。

7. [P2] Session bundle 没有从同一个 SQLite snapshot 读取 header 与 boundary

Bundle exporter 通过两个独立 exporter 调用写入 selected session metadata 和 selected boundary:

如果两次读取之间发生并发 Auto/Bypass transition,export 可能得到一个 revision 的 header 和另一个 revision 的 boundary。Import 随后会把两者共同接受为新的 genesis state。

Storage 应在一个 read transaction 内返回不可变的 portable { header, boundary } snapshot,然后再写两个 transfer file。

实现质量问题

Runtime 的 public boundary contract 仍允许 authoritative reader 缺失:

当前 first-party production call site 看起来都提供了 reader,因此我没有把它作为独立 exploit。但 public API 仍会从 header.permissionMode 静默重建 authority,保留了本 PR 声称要删除的 dual-authority fallback。

Boundary reader 应成为 required dependency。Interactive expansion support 可以单独表示为显式的 enabled/disabled capability。

此外,当前还有若干 source-regex 与 collaborator-call test,它们锁定 implementation shape,而不是验证 public behavior。我没有把这些测试作为本次 Request changes 的主要依据,但在修复上述路径时应将其替换为 behavioral coverage。

验证

最终 head d481739

  • npm run build:test 通过。
  • Linux sandbox smoke 通过,7/7。
  • Linux filesystem-worker smoke 通过,2/2。
  • SQLite session metadata tests 通过,30/30。
  • git diff --check a454b9a..d481739 通过。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

当前绿色测试覆盖了受支持的 sandbox 路径,但没有覆盖上述 worker-unavailable fail-open 路径与跨 surface 不一致。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

Thank you for the detailed review. I reproduced the reported paths and updated the PR to head 7abc0b9de.

All seven findings have now been addressed:

  1. Managed filesystem fail-open — fixed in 48ca2f864. Managed Read/Write/Edit now fail closed when the filesystem sandbox is unavailable; the host executor is reserved for explicit Bypass or External authority.

  2. Unreachable first process-network expansion — fixed in 05585da92. Bash now declares a non-authorizing sandbox capability requirement, allowing the runtime to produce an exact network expansion without parsing command text.

  3. External sessions on local interactive surfaces — fixed across 7823ab5d4 and 7abc0b9de. TUI rejects resuming External sessions without their owning harness. Desktop may display imported External history, but it is non-interactive: the composer and permission-mode controls are unavailable, permission commands are omitted, and External is never presented as Auto. Boundary loading also fails closed so Auto cannot flash before the authority snapshot arrives.

  4. Deep Research expansion and mutation surface — fixed in 3d347d48d, with the read-only tool-surface contract strengthened in c384056c5. Deep Research no longer receives mutation or boundary-expansion tools.

  5. Child boundary inheritance — fixed in 62581d26f and f04db4bec. Child admission and filesystem execution now use the inherited ExecutionBoundary explicitly, with managed, bypass, and external paths handled deliberately and child tool surfaces defined by explicit allowlists.

  6. Non-interactive unresolved boundary returning success — fixed in 093d9fad2. maka run now exits nonzero for an unresolved boundary requirement whether it appears as a request event or a structured tool failure.

  7. Non-atomic bundle boundary snapshot — fixed in 1715039e9. Session header and execution boundary are now read from one storage transaction before transfer files are written.

The implementation-quality concern was also addressed. 581f73ec5 removed the legacy boundary fallback, and fa4314bfe now makes readExecutionBoundary a required Runtime/AiSdkBackend dependency. Missing authority is rejected instead of reconstructing External or managed authority from legacy permissionMode. Tests that intentionally exercise an externally isolated raw runtime now opt into that authority explicitly.

For the Desktop follow-up, 7abc0b9de adds behavioral coverage for managed, bypass, loading, and external boundary projections, plus command-surface coverage. I did not broaden this follow-up into a rewrite of unrelated source-contract tests.

Validation on 7abc0b9de:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • full npm run test:dist across all workspaces
  • Runtime: 2,697 passed, 9 skipped, 0 failed
  • Desktop: 2,968 passed, 0 failed
  • GitHub typecheck, test, and e2e: all green

Could you please re-review the current head?

简体中文

感谢这次详细审查。我复现了报告中的路径,并已把 PR 更新到 head 7abc0b9de

七项 findings 现已全部处理:

  1. Managed filesystem fail-open — 已在 48ca2f864 修复。Filesystem sandbox 不可用时,managed Read/Write/Edit 现在会 fail closed;host executor 只供显式 Bypass 或 External authority 使用。

  2. 首次 process-network expansion 不可达 — 已在 05585da92 修复。Bash 现在声明一个本身不授予权限的 sandbox capability requirement,使 Runtime 无需解析 command text 就能生成精确的 network expansion。

  3. External session 被本地交互 surface 执行 — 已通过 7823ab5d47abc0b9de 修复。TUI 会拒绝在缺少所属 harness 时恢复 External session。Desktop 可以查看导入的 External 历史,但保持不可交互:composer 和 permission-mode control 不可用,permission command 不会出现,External 也绝不会显示为 Auto。Boundary 加载阶段同样 fail closed,避免 authority snapshot 到达前短暂显示 Auto。

  4. Deep Research expansion 与 mutation surface — 已在 3d347d48d 修复,并由 c384056c5 加强 read-only tool-surface 契约。Deep Research 不再获得 mutation 或 boundary-expansion tool。

  5. Child boundary inheritance — 已在 62581d26ff04db4bec 修复。Child admission 与 filesystem execution 现在显式使用继承的 ExecutionBoundary,managed、bypass、external 均有明确语义,child tool surface 由显式 allowlist 定义。

  6. 非交互 unresolved boundary 错误返回成功 — 已在 093d9fad2 修复。无论 boundary requirement 来自 request event 还是 structured tool failure,maka run 都会非零退出。

  7. Bundle boundary snapshot 非原子 — 已在 1715039e9 修复。Session header 与 execution boundary 现在会在同一个 storage transaction 中读取,然后才写入 transfer files。

实现质量问题也已处理。581f73ec5 删除了 legacy boundary fallback,fa4314bfe 则将 readExecutionBoundary 设为 Runtime/AiSdkBackend 的 required dependency。缺少 authority 时现在会直接拒绝,不再从 legacy permissionMode 重建 External 或 managed authority。需要直接测试 externally isolated raw runtime 的测试也会显式选择该 authority。

Desktop follow-up 7abc0b9de 增加了 managed、bypass、loading、external boundary projection 的行为测试,以及 command surface 测试。此次 follow-up 没有盲目扩大到重写无关的 source-contract test。

7abc0b9de 上的验证结果:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • 全 workspace npm run test:dist
  • Runtime:2,697 通过,9 跳过,0 失败
  • Desktop:2,968 通过,0 失败
  • GitHub typecheckteste2e:全部绿色

能否请你基于当前 head 再 review 一次?

@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed head 7abc0b9de and reran the relevant targeted tests.

Re-review outcome

The following findings are resolved:

  1. Managed filesystem execution now fails closed when the worker sandbox is unavailable.
  2. Bash can declare an exact process-network boundary requirement without parsing command text.
  3. External sessions are rejected by TUI and remain non-interactive in Desktop.
  4. Deep Research now receives a read-only tool surface without boundary-expansion tools.
  5. Non-interactive unresolved boundary failures now produce a nonzero exit.
  6. Session bundle metadata and boundary are read from one SQLite authority snapshot.
  7. readExecutionBoundary is now required, and the Runtime legacy boundary fallback has been removed.

One finding remains open.

[P2] Child filesystem execution still does not inherit Bypass or External semantics

The parent ExecutionBoundary is persisted into the child, but ordinary child creation still stores the Agent definition’s legacy permission mode:

The filesystem worker only consumes the supplied boundary when its kind is managed. For Bypass or External, it falls back to permissionProfile or the child’s legacy mode:

Bash, by contrast, explicitly skips the Maka sandbox for the inherited Bypass or External boundary:

I reproduced the remaining mismatch on 7abc0b9de by executing an outside-workspace filesystem write with a Bypass or External boundary and a legacy child mode:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

The worker process was never launched. The operation was rejected by the legacy profile selected before sandbox execution.

The explicit child tool allowlists correctly constrain which tools a child receives, but they do not make those tools use the inherited boundary. An implementation child can therefore run Bash according to inherited Bypass/External authority while Read/Write/Edit continue to use a different filesystem authority.

Please make filesystem authority selection exhaustive over all ExecutionBoundary kinds. Once an authoritative boundary is supplied, the filesystem client should not fall back to permissionMode. A regression test should exercise a real inherited child Bypass/External boundary through the builtin filesystem tool path.

Validation

On 7abc0b9de:

  • npm run build:test passed.
  • Runtime targeted tests passed, 100/100.
  • CLI targeted tests passed, 72/72.
  • Storage targeted tests passed, 60/60.
  • Desktop targeted tests passed, 13/13.
  • Linux sandbox and filesystem-worker smoke tests passed, 9/9.
  • GitHub typecheck, test, and e2e checks are green.

I did not find another blocker in the follow-up scope. The previous findings can remain resolved; only the child filesystem-boundary finding remains open.

简体中文

@Astro-Han

我基于 head 7abc0b9de 完成了 re-review,并重新运行了相关定向测试。

Re-review 结论

以下 findings 已确认 resolved:

  1. Filesystem worker sandbox 不可用时,managed filesystem execution 现在会 fail closed。
  2. Bash 现在可以在不解析 command text 的情况下声明精确的 process-network boundary requirement。
  3. TUI 会拒绝 External session,Desktop 中的 External session 保持不可交互。
  4. Deep Research 现在只获得 read-only tool surface,不再获得 boundary-expansion tool。
  5. 非交互 unresolved boundary failure 现在会产生非零退出码。
  6. Session bundle metadata 与 boundary 现在从同一个 SQLite authority snapshot 读取。
  7. readExecutionBoundary 已成为 required dependency,Runtime legacy boundary fallback 也已删除。

仍有一项 finding 未关闭。

[P2] Child filesystem execution 仍未继承 Bypass 或 External 语义

Parent ExecutionBoundary 已经持久化到 child,但普通 child 创建仍会把 Agent definition 的 legacy permission mode 写入 header:

Filesystem worker 只有在 boundary kind 为 managed 时才消费传入的 boundary。对于 Bypass 或 External,它仍会退回 permissionProfile 或 child legacy mode

Bash 则会针对 inherited Bypass 或 External boundary 显式跳过 Maka sandbox:

我在 7abc0b9de 上使用 Bypass/External boundary 与 legacy child mode 执行 workspace 外 filesystem write,仍能复现该不一致:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

Worker process 没有启动。操作在 sandbox execution 之前就被 legacy profile 拒绝。

显式 child tool allowlist 正确限制了 child 可以获得哪些工具,但没有让这些工具使用 inherited boundary。因此 implementation child 仍可能让 Bash 遵循 inherited Bypass/External authority,而 Read/Write/Edit 使用另一套 filesystem authority。

请对所有 ExecutionBoundary kind 做穷举的 filesystem authority selection。一旦提供 authoritative boundary,filesystem client 就不应再退回 permissionMode。Regression test 应通过 builtin filesystem tool 路径,覆盖真实 inherited child Bypass/External boundary。

验证

7abc0b9de 上:

  • npm run build:test 通过。
  • Runtime 定向测试通过,100/100。
  • CLI 定向测试通过,72/72。
  • Storage 定向测试通过,60/60。
  • Desktop 定向测试通过,13/13。
  • Linux sandbox 与 filesystem-worker smoke tests 通过,9/9。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

在本次 follow-up 范围内没有发现其他 blocker。此前其余 findings 可以保持 resolved;目前只剩 child filesystem-boundary finding 未关闭。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

@M4n5ter

Thank you. I addressed the remaining child filesystem-boundary finding. The current head is 3f5443b7f.

The root cause was that the filesystem worker boundary was not explicit enough: it is a managed-only enforcement path, while Bypass and External execution must never be projected into it or reconstructed from a legacy child mode.

The fix now covers both layers:

  1. bf370bd1a makes builtin filesystem dispatch depend on the authoritative ExecutionBoundary before any worker call:

    • Managed routes through the filesystem worker and fails closed when enforcement is unavailable.
    • Bypass and External route through the executor supplied by their owning surface.
    • Neither path consults the child’s legacy permissionMode.
  2. 3f5443b7f closes the lower-level API ambiguity:

    • FilesystemWorkerClient now rejects any supplied Bypass or External boundary.
    • Once an authoritative boundary is supplied, the client can no longer fall back to permissionProfile or mode.

The regression coverage reproduces the inherited-child shape directly through builtin Write: legacy permissionMode: explore combined with authoritative Bypass and External boundaries. Both use the non-worker path, while direct attempts to pass either boundary into FilesystemWorkerClient fail before validation or process launch.

Fresh-eye validation also added bounded hardening around boundary narrowing, stale linked-child resume, External admission, descendant non-interactive failures, exact-write grant isolation, authority round-trips, and prompt response races. These remain separate atomic commits and do not reintroduce the generic permission or legacy mode paths.

Validation on 3f5443b7f:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • full serial npm run test:dist across all workspaces
  • Runtime after the final worker-client change: 2,706 passed, 9 skipped, 0 failed
  • Runtime Host: 303 passed, 0 failed
  • Desktop: 2,970 passed, 0 failed
  • targeted builtin filesystem-worker and client tests: 20 passed, 0 failed

Could you please re-review the current head?

简体中文

@M4n5ter

感谢。我已经处理了最后一项 child filesystem-boundary finding。当前 head 为 3f5443b7f

根因是 filesystem worker 的职责边界不够明确:它只应是 Managed 的 enforcement path;Bypass 与 External execution 既不应进入 worker,也不能从 legacy child mode 重建权限。

修复现在覆盖两层:

  1. bf370bd1a 让 builtin filesystem dispatch 在调用 worker 前直接依据权威 ExecutionBoundary 路由:

    • Managed 必须走 filesystem worker;enforcement 不可用时 fail closed。
    • Bypass 与 External 走所属 surface 注入的 executor。
    • 两条路径都不再查询 child 的 legacy permissionMode
  2. 3f5443b7f 关闭了底层 API 的歧义:

    • FilesystemWorkerClient 现在会拒绝任何传入的 Bypass 或 External boundary。
    • 一旦提供权威 boundary,client 就不能再回退到 permissionProfilemode

回归测试通过 builtin Write 直接复现 inherited-child 的组合:legacy permissionMode: explore 加权威 Bypass/External boundary。两者都会走非 worker 路径;如果直接把任一 boundary 传给 FilesystemWorkerClient,则会在 validation 或进程启动前 fail closed。

Fresh-eye 验证还以有限范围补强了 boundary narrowing、stale linked-child resume、External admission、非交互后代失败、exact-write grant 隔离、authority round-trip 和 prompt response race。它们都保留为独立原子提交,也没有重新引入 generic permission 或 legacy mode 路径。

3f5443b7f 上的验证:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • 全 workspace 串行 npm run test:dist
  • 最后一项 worker-client 修复后的 Runtime:2,706 通过,9 跳过,0 失败
  • Runtime Host:303 通过,0 失败
  • Desktop:2,970 通过,0 失败
  • builtin filesystem-worker 与 client 定向测试:20 通过,0 失败

能否请你基于当前 head 再 review 一次?

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 3f5443b to c4a7062CompareJuly 29, 2026 08:43
@M4n5ter

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed the latest head c4a7062c9. The rebase preserved the 13 follow-up patches; the new final commit only reconciles an AI-provider test fixture.

Re-review outcome

The previously reported child filesystem-boundary mismatch is resolved. Builtin filesystem dispatch now follows the authoritative boundary, and the targeted builtin/client tests pass 20/20.

Request changes. Three correctness blockers and four additional gaps remain.

Blocking correctness findings

1. [P1] A missing exact-write grant still blocks unrelated Bash commands on real Linux

prepareLinuxBashExactWriteTargets now prepares only exact paths declared by the current required_boundary, but the complete durable profile is still passed to bubblewrap:

Every exact-write entry in that profile remains a bind-mount source. If an undeclared exact target or its parent no longer exists, bubblewrap fails before executing the command.

I reproduced this with an unrelated command:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

The added unit test does not catch this because it uses a fake available sandbox manager and never executes the generated bubblewrap command.

This is also the current required-CI failure: Linux sandbox smoke fails 6/7 with the same missing-source error.

The per-invocation Linux mount plan should omit absent undeclared exact entries while safely preparing an exact target that the current invocation declares. This needs a real bubblewrap smoke test for both cases.

2. [P1] Legacy permissionCeiling prevents default Auto sessions from creating executable children

A normal new session still defaults to legacy permissionMode: ask, while Web Research and Implementation definitions use execute. Child creation therefore stores permissionMode: execute with permissionCeiling: ask:

Current-header normalization still treats that legacy ceiling as live authority:

I reproduced the resulting persistence failure:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

This happens before the inherited ExecutionBoundary can govern the child. permissionCeiling should be limited to legacy decoding/migration, not written or enforced for current child sessions. A SQLite-backed child-creation behavior test should cover an Implementation child spawned from the default Auto session.

3. [P1] Narrowing a parent boundary does not revoke descendant background processes

A child Bash run is registered under the child session ID:

The parent boundary transition terminates only the parent session’s shell runs:

A foreground child can start background Bash, return, and leave the process alive. The parent can then narrow from Bypass to Auto, or Auto to Explore, while that descendant process continues with its old authority. The stale-child resume guard prevents a future resume but does not revoke already-live processes.

Boundary narrowing needs lineage-wide revocation of descendant shell runs and backend generations before committing the transition, with regression coverage for a completed child turn that leaves background Bash running.

Additional correctness gap

4. [P2] An Explore-origin session cannot return from Bypass to Auto

For an Explore-origin session, genesis is the managed read-only profile. After switching to Bypass, restoration searches only for a previous non-read-only managed profile:

I reproduced:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

The transition should be total for supported UI states. If Explore sessions may enter Bypass, a missing Auto history should restore the canonical Auto genesis profile. If they must remain read-only, Bypass should be rejected and hidden before the transition.

Maintainability findings

5. [P2] Sandbox containment semantics are duplicated inside SessionManager

The follow-up adds approximately 70 lines of profile, access, path, deny, and protected-metadata containment logic to an already very large runtime coordinator:

Boundary containment is a core contract and will drift if Runtime owns a second implementation. Please expose one canonical Core helper and keep SessionManager as a caller.

6. [P2] The public legacy snapshot exporter can silently omit authoritative boundaries

exportLegacySessionTreeSnapshot accepts required records but an optional boundary map, and silently skips the boundary transfer file when an entry is absent:

The production wrapper currently supplies the map, but the exported public helper still permits a boundary-less session export. Its input should carry paired authority snapshots and require one boundary for every selected session.

7. [P2] The new External-admission regression test verifies source layout, not behavior

The test reads main.ts and uses regular expressions to require a specific helper name, handler layout, and call text:

It can pass without proving that IPC admission rejects External execution, and harmless refactoring can break it. Please replace it with an IPC behavior harness covering compact, resume, regenerate, and plan approval, asserting that runtime execution is not reached.

Validation

On c4a7062c9:

  • npm run build:test passed.
  • Child filesystem builtin/client tests passed, 20/20.
  • The default-Auto executable-child header was rejected in a direct current-header normalization reproduction.
  • Explore → Bypass → Auto failed in an in-memory SQLite reproduction.
  • An unrelated true command failed under real bubblewrap when the profile contained a missing exact-write grant.
  • Local required Linux sandbox smoke failed, 6/7.
  • GitHub typecheck and e2e are green; test is red on the same Linux smoke failure.
简体中文

@Astro-Han

我基于最新 head c4a7062c9 完成了 re-review。Rebase 保留了 13 个 follow-up patch;新增的最后一个 commit 只调整了 AI provider test fixture。

Re-review 结论

此前未关闭的 child filesystem-boundary 不一致已经解决。Builtin filesystem dispatch 现在遵循 authoritative boundary,相关 builtin/client 定向测试 20/20 通过。

仍需 Request changes。目前还有三项 correctness blocker 和四项其它问题。

阻塞性 correctness findings

1. [P1] 失效的 exact-write grant 在真实 Linux 上仍会阻断无关 Bash 命令

prepareLinuxBashExactWriteTargets 现在只准备当前 required_boundary 声明的 exact path,但完整的持久化 profile 仍会传给 bubblewrap:

Profile 中的每个 exact-write entry 仍然会成为 bind-mount source。如果一个未被本次调用声明的 exact target 或其 parent 已不存在,bubblewrap 会在执行 command 前失败。

我使用一条完全无关的命令复现了该问题:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

新增的 unit test 使用 fake available sandbox manager,并未执行生成的 bubblewrap command,因此无法覆盖真实行为。

这也是当前 required CI 的失败原因:Linux sandbox smoke 以相同的 missing-source 错误失败,结果为 6/7。

Linux 每次调用的 mount plan 应忽略不存在且未被当前调用声明的 exact entry;如果当前调用显式声明 exact target,则应安全地准备它。两条路径都需要真实 bubblewrap smoke coverage。

2. [P1] Legacy permissionCeiling 会阻止默认 Auto session 创建 executable child

普通新 session 的 legacy permissionMode 默认仍为 ask,而 Web Research 与 Implementation definition 使用 execute。Child 创建因此会同时写入 permissionMode: executepermissionCeiling: ask

Current-header normalization 仍把 legacy ceiling 当作 live authority:

我复现到的持久化结果为:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

失败发生在 inherited ExecutionBoundary 能够治理 child 之前。permissionCeiling 应仅用于 legacy decode/migration,不应继续写入或验证 current child session。需要通过真实 SQLite child-creation 行为测试覆盖默认 Auto session 创建 Implementation child 的路径。

3. [P1] 收窄 parent boundary 不会撤销 descendant background process

Child Bash run 会记录在 child session ID 下:

Parent boundary transition 只终止 parent session 自身的 shell run:

Foreground child 可以启动 background Bash 后返回,但让进程继续运行。随后 parent 可以从 Bypass 收窄到 Auto,或从 Auto 收窄到 Explore;descendant process 仍保留旧 authority。Stale-child resume guard 只能阻止未来 resume,无法撤销已经存活的进程。

Boundary narrowing 应在提交 transition 前,按 session lineage 撤销所有 descendant shell run 与 backend generation,并增加“child turn 已结束但 background Bash 仍在运行”的 regression coverage。

其它 correctness gap

4. [P2] Explore-origin session 无法从 Bypass 返回 Auto

Explore-origin session 的 genesis 是 managed read-only profile。切换到 Bypass 后,恢复逻辑只查找历史中的 non-read-only managed profile:

我的复现结果为:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

所有受支持的 UI 状态都应拥有完整 transition。如果 Explore session 可以进入 Bypass,那么缺少 Auto history 时应恢复 canonical Auto genesis profile;如果它必须始终保持 read-only,则应在 transition 之前拒绝并隐藏 Bypass。

可维护性 findings

5. [P2] Sandbox containment 语义被重复实现在 SessionManager

Follow-up 在已经非常庞大的 runtime coordinator 中增加了约 70 行 profile、access、path、deny 与 protected-metadata containment 逻辑:

Boundary containment 属于 Core contract。Runtime 保留第二套实现会产生语义漂移。建议在 Core 暴露一个 canonical helper,让 SessionManager 只负责调用。

6. [P2] Public legacy snapshot exporter 可以静默遗漏 authoritative boundary

exportLegacySessionTreeSnapshot 要求提供 records,却把 boundary map 设为 optional;如果某个 entry 不存在,就会静默跳过 boundary transfer file:

当前 production wrapper 的确提供了 map,但导出的 public helper 仍允许生成缺失 boundary 的 session export。其输入应改为成对的 authority snapshot,并要求每个被选择的 session 都有 boundary。

7. [P2] 新增的 External-admission regression test 验证 source layout,而不是行为

该测试读取 main.ts,再用正则要求特定 helper 名称、handler 布局和调用文本:

它无法证明 IPC admission 确实会拒绝 External execution,同时正常重构也会使测试破裂。应替换为 IPC behavior harness,覆盖 compact、resume、regenerate 与 plan approval,并断言 runtime execution 未被调用。

验证

c4a7062c9 上:

  • npm run build:test 通过。
  • Child filesystem builtin/client tests 20/20 通过。
  • Direct current-header normalization 复现到默认 Auto executable-child header 被拒绝。
  • In-memory SQLite 复现到 Explore → Bypass → Auto 失败。
  • 在真实 bubblewrap 下,profile 含有失效 exact-write grant 时,无关的 true command 仍会失败。
  • 本地 required Linux sandbox smoke 失败,6/7。
  • GitHub typechecke2e 通过;test 因相同 Linux smoke 错误失败。

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch 2 times, most recently from 4c0af93 to d01db12CompareJuly 29, 2026 10:43
@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 58fdec7 to 6b82f24CompareJuly 29, 2026 11:52
@Astro-Han
Astro-Han merged commit 0fe34a7 into mainJul 29, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/1564-session-sandbox-boundary branch July 29, 2026 12:00
Astro-Han added a commit that referenced this pull request Jul 29, 2026
#1581 replaced tool permissions with session sandbox boundaries and removed
`PermissionEngine` from `@maka/runtime`, but left this test importing it and
passing a `permissionEngine` dependency that the session-stream deps type no
longer has. `main` has been red since: `tsc -p tsconfig.main.json` fails with
TS2305, which takes `build:main` down and with it the typecheck, test, and e2e
jobs on every branch.
Nothing in production takes a `permissionEngine` any more, and the test's
subject is usage readiness, so the import and the dependency go. No behavioural
change and no replacement needed.
Sign up for freeto 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.

feat: replace per-tool approvals with sandbox boundaries

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: replace tool permissions with session sandbox boundaries - #1581

Merged
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary
Jul 29, 2026
Merged

feat: replace tool permissions with session sandbox boundaries#1581
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace additional permissions, one-call sandbox escalation, and the live generic tool-approval path with one revisioned, session-scoped ExecutionBoundary authority.
  • Persist genesis boundaries, immutable expansion requests, and applied revisions in the SQLite session metadata store. Approval and boundary advancement commit atomically; stale, duplicate, and concurrently decided requests settle deterministically.
  • Keep the expansion schema no broader than the product needs today: exact/subtree filesystem read/write entries plus session network enablement. Tools report exact sandbox_boundary_required deltas or requires_bypass; Bash diagnostics never parse commands or invent authority.
  • Wire the boundary lifecycle end to end through core, storage, runtime, Runtime Host, session bundles, Desktop/shared UI, TUI, headless/Harbor, and non-interactive CLI. Desktop and TUI expose Auto/Bypass, boundary prompts take over the composer, and Bypass requires an explicit second confirmation.
  • Remove the superseded PermissionEngine matrix, grant ingress, generic permission prompts, and legacy live escalation executors in the same PR so no dual-authority intermediate state ships. Historical codecs and settled audit history remain readable; OS Permission Center behavior is unchanged.

Closes#1564

Verification

  • npm run build — passed across all workspaces.
  • npm run test:dist — passed the complete repository suite with the workspace runner in serial mode, including script contracts (176/176), storage (733 passed, 1 skipped), Runtime (2675 passed, 9 skipped), Runtime Host (212/212), and Desktop (2964/2964).
  • npm run format:check — passed, 1221 files checked.
  • npm run lint — passed, 2304 files checked.
  • npm run typecheck — passed across all workspaces.
  • node --test packages/runtime/dist/__tests__/macos-seatbelt-smoke.test.js packages/runtime/dist/__tests__/filesystem-worker-smoke.test.js — passed (9/9), including exact outside-path expansion and restricted network behavior.
  • npm run e2e -w @maka/desktop -- e2e/sandbox-boundary-takeover.spec.ts — passed (1/1), covering the visible Desktop composer takeover and approval journey.
  • The all-workspace parallel npm test command intermittently exhausted a Runtime Host test's local timing window under machine load. That package passed independently (212/212), and the complete serial repository run above passed; this PR does not broaden into unrelated test-harness timing changes.

Migration and breaking change

  • Legacy ask and execute sessions enter the managed workspace-write boundary; explore enters managed read-only; bypass remains bypass. First access durably records revision 0 without rewriting settled historical records.
  • Pending legacy permission interactions close with host_restarted during recovery because their live continuation authority cannot survive the upgrade.
  • Interactive surfaces now expose only Auto and Bypass. Removed permission modes and per-tool grant flags fail during CLI argument validation.
  • maka run defaults to Auto and cannot interactively expand a boundary, so it fails closed when expansion is requested. Only explicit --yolo creates or resumes a bypass session.
  • Headless/Harbor sessions explicitly use the external boundary; imports and exports preserve the authoritative boundary even though the SQLite database itself is not bundled.

Review focus

  • The SQLite transaction boundary around request settlement and boundary revision advancement, including cross-connection races.
  • The runtime continuation/publication barrier when a sandbox boundary or user question is pending, including durable denial when a turn closes.
  • The cross-surface fail-closed behavior for ordinary expansion requests versus requires_bypass.
  • The branch contains 105 small, reversible commits ordered from contracts and storage through runtime, surfaces, legacy-path removal, and regression coverage.

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 6f15924 to d481739CompareJuly 29, 2026 01:50
@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

Review outcome

Request changes.

I reviewed the final PR head d481739 against the accepted contract in #1564 and the guarantees stated in this PR body. The SQLite transition work, prompt settlement, --yolo protection, boundary persistence, and Linux sandbox tests are meaningful improvements, but several execution paths still violate the central invariants of this change.

The latest rebase and the final d481739 cleanup commit do not change the sandbox semantics described below.

Contract used for this review

The accepted #1564 contract requires:

  • one authoritative, session-scoped ExecutionBoundary;
  • managed execution to fail closed when enforcement is unavailable;
  • an exact, reachable expansion flow for process network and filesystem boundaries;
  • External execution only when an explicit external isolation owner exists;
  • Deep Research to remain internally managed and read-only;
  • child Agents to inherit the parent boundary;
  • non-interactive Auto to exit nonzero when an unavoidable boundary requirement cannot be resolved; and
  • session bundles to restore the authoritative boundary.

The alternative proposals to enable network by default, automatically fall through to Bypass, or treat user-provided paths as implicit authorization were explicitly rejected in the issue discussion. These findings are evaluated against the accepted issue body, not those alternatives.

Blocking findings

1. [P1] Managed filesystem tools fail open when the filesystem worker is unavailable

Desktop and CLI conditionally omit the filesystem worker when the platform cannot provide the built-in worker sandbox. buildBuiltinTools then falls back to createLocalWorkspaceExecutor, and Write/Edit/Read execute on the host instead of rejecting managed execution.

Relevant paths:

I reproduced this on the final head: a Write call under an explore/read-only boundary successfully created a file when no worker was supplied.

Managed execution must return an enforcement-unavailable failure before reaching the host executor. The host path should only be reachable for an explicit Bypass or harness-owned External boundary.

2. [P1] The first process-network expansion has no valid request path

Auto starts with restricted process network, but Bash has no declarative network requirement. A denied command returns only a likely sandbox-denial signal, without sandbox_boundary_required or a concrete network expansion:

Runtime guidance simultaneously states that the Agent must not infer an expansion and may request one only after a tool returns an exact expansion:

I reproduced an EPERM network denial with sandboxType: linux; the failure contained no required expansion. Commands such as npm install, git pull, and curl therefore cannot reach the session-level network approval flow required by #1564.

This needs a declarative, non-authorizing process-network requirement or an equally reliable backend signal that can produce the exact expansion without parsing command text.

3. [P1] An External session can resume in Desktop/TUI as Auto while Bash runs without a Maka sandbox

Imported session bundles can restore an External boundary. Bash treats both Bypass and External as instructions to skip the Maka sandbox:

Desktop maps every non-Bypass boundary to Auto, while TUI session switching continues to project the legacy permissionMode:

maka run correctly rejects this resume path, but ordinary Desktop and interactive TUI do not. The result is an Auto-labelled session executing host Bash without the external harness that supposedly owns isolation.

External sessions must be rejected by ordinary interactive surfaces unless an explicit external-isolation owner is injected. External must also never be presented as Auto.

Additional correctness gaps

4. [P2] Deep Research can request and receive write or network expansion

Deep Research starts with a managed read-only profile, but Desktop still includes the complete builtin surface and unconditionally exposes request_sandbox_boundary:

Storage applies an approved expansion to any managed profile, including read-only:

I reproduced approval of a network expansion on a Deep Research session. The resulting profile was still named read-only, but its network state was enabled.

The Deep Research surface should omit mutation tools and the boundary-request tool, and its internal read-only boundary must not be expandable into write or process-network authority.

5. [P2] Child boundary persistence is fixed, but filesystem execution does not fully inherit Bypass or External

The parent boundary is now persisted into the child correctly. However, the child header still uses the Agent definition’s legacy permission mode, and the filesystem worker only consumes managed boundaries:

For an inherited Bypass or External boundary, filesystem execution falls back to the child definition’s legacy profile. The same child can therefore run Bash according to the inherited boundary while Read/Write/Edit follow a different authority.

Boundary handling in the filesystem client should be exhaustive: managed, bypass, and external must each have explicit semantics, with no fallback to permissionMode.

6. [P2] Non-interactive Auto can still return exit code 0 after an unresolved boundary failure

maka run does not register the boundary-request tool. It marks the command as failed only after receiving a sandbox_boundary_request event:

A filesystem tool can instead return sandbox_boundary_required as an ordinary structured tool failure. If the model then produces a normal final answer explaining that it could not complete the task, the invocation remains completed and maka run returns 0.

An unresolved boundary requirement must become a terminal non-interactive invocation outcome, independently of whether a request event was published.

7. [P2] A session bundle does not read its header and boundary from one SQLite snapshot

The bundle exporter writes selected session metadata and the selected boundary through two independent exporter calls:

A concurrent Auto/Bypass transition between those reads can export a header from one revision and a boundary from another. Import then accepts both as the new genesis state.

Storage should provide one read transaction that returns an immutable portable { header, boundary } snapshot before either transfer file is written.

Implementation-quality concern

The Runtime public boundary contract still permits the authoritative reader to be absent:

All current first-party production call sites appear to provide the reader, so I am not treating this as a separate exploit. However, the public API still silently reconstructs authority from header.permissionMode, which preserves the dual-authority fallback that this PR claims to remove.

The boundary reader should be required. Interactive expansion support can be represented separately as an explicit enabled/disabled capability.

There are also several source-regex and collaborator-call tests that lock implementation shape rather than public behavior. I do not use those as the primary basis for this review, but they should be replaced with behavioral coverage while these paths are being corrected.

Validation

On final head d481739:

  • npm run build:test passed.
  • Linux sandbox smoke passed, 7/7.
  • Linux filesystem-worker smoke passed, 2/2.
  • SQLite session metadata tests passed, 30/30.
  • git diff --check a454b9a..d481739 passed.
  • GitHub typecheck, test, and e2e checks are green.

The green suite validates the supported sandbox path, but it does not cover the fail-open worker-unavailable path or the cross-surface inconsistencies above.

简体中文

审查结论

Request changes。

我基于 #1564 的已接受契约与本 PR body 声明的保证,对最终 head d481739 进行了审查。SQLite transition、Prompt settlement、--yolo 保护、boundary 持久化和 Linux sandbox 测试都是有价值的改进,但若干执行路径仍违反这次改动的核心不变量。

最新 rebase 与最终的 d481739 cleanup commit 没有改变下述 sandbox 语义。

本次审查采用的契约

已接受的 #1564 契约要求:

  • 每个 session 只有一个 authoritative、session-scoped ExecutionBoundary
  • enforcement 不可用时,managed execution 必须 fail closed;
  • process network 与 filesystem boundary 必须具有精确且可达的 expansion 流程;
  • External execution 只能在存在显式 external isolation owner 时使用;
  • Deep Research 必须保持内部 managed read-only;
  • 子 Agent 必须继承父 session boundary;
  • 非交互 Auto 遇到无法解决且不可避免的 boundary requirement 时必须非零退出;
  • session bundle 必须恢复 authoritative boundary。

Issue 讨论中关于默认启用 network、自动退化到 Bypass,以及把用户给出的路径视为隐式授权的替代提案已经被明确拒绝。以下 findings 以已接受的 issue body 为准,不采用这些替代提案。

阻塞问题

1. [P1] Filesystem worker 不可用时,managed filesystem tool 会 fail open

当平台无法提供内置 worker sandbox 时,Desktop 与 CLI 会有条件地省略 filesystem worker。buildBuiltinTools 随后退回 createLocalWorkspaceExecutor,导致 Write/Edit/Read 在 host 上执行,而不是拒绝 managed execution。

相关路径:

我在最终 head 上完成了复现:未提供 worker 时,explore/read-only boundary 下的 Write 成功创建了文件。

Managed execution 必须在进入 host executor 前返回 enforcement-unavailable failure。Host 路径只能由显式 Bypass 或 harness-owned External boundary 访问。

2. [P1] 首次 process-network expansion 没有合法的请求路径

Auto 默认限制 process network,但 Bash 没有声明 network requirement 的字段。命令被拒绝时只返回可能的 sandbox-denial signal,不包含 sandbox_boundary_required 或具体 network expansion:

Runtime guidance 同时要求 Agent 不得推断 expansion,且只有在工具返回精确 expansion 后才能请求:

我复现了带有 sandboxType: linuxEPERM network denial,但 failure 中没有 required expansion。因此 npm installgit pullcurl 等命令无法进入 #1564 要求的 session-level network approval 流程。

这里需要一个声明式且本身不授予权限的 process-network requirement,或同样可靠的 backend signal,以便在不解析 command text 的情况下生成精确 expansion。

3. [P1] External session 可以在 Desktop/TUI 中以 Auto 恢复,同时 Bash 不受 Maka sandbox 约束

导入的 session bundle 可以恢复 External boundary。Bash 将 Bypass 和 External 都视为跳过 Maka sandbox 的指令:

Desktop 把所有非 Bypass boundary 映射为 Auto,而 TUI session switching 继续投影 legacy permissionMode

maka run 已经正确拒绝该 resume 路径,但普通 Desktop 与交互式 TUI 没有拒绝。最终结果是:一个标记为 Auto 的 session 在缺少原定 external harness 的情况下执行 host Bash。

除非注入显式 external-isolation owner,否则普通交互式 surface 必须拒绝 External session。External 也绝不能显示为 Auto。

其他正确性缺口

4. [P2] Deep Research 可以请求并获得 write 或 network expansion

Deep Research 从 managed read-only profile 开始,但 Desktop 仍包含完整 builtin surface,并无条件暴露 request_sandbox_boundary

Storage 会把已批准的 expansion 应用到任意 managed profile,包括 read-only:

我复现了 Deep Research session 的 network expansion approval。结果 profile 仍名为 read-only,但 network state 已变为 enabled

Deep Research surface 应移除 mutation tool 与 boundary-request tool,其内部 read-only boundary 也不应扩张为 write 或 process-network authority。

5. [P2] Child boundary 已正确持久化,但 filesystem execution 没有完整继承 Bypass 或 External

Parent boundary 现在已经能正确持久化到 child。但 child header 仍使用 Agent definition 的 legacy permission mode,而 filesystem worker 只消费 managed boundary:

对于继承的 Bypass 或 External boundary,filesystem execution 会退回 child definition 的 legacy profile。同一个 child 因而可能让 Bash 遵循 inherited boundary,却让 Read/Write/Edit 遵循另一套 authority。

Filesystem client 应穷举处理 managed、bypass 与 external,不能再退回 permissionMode

6. [P2] 非交互 Auto 在 boundary failure 未解决后仍可能返回退出码 0

maka run 不注册 boundary-request tool。它只有在收到 sandbox_boundary_request event 后才把命令标记为失败:

Filesystem tool 也可能只把 sandbox_boundary_required 作为普通 structured tool failure 返回。如果 model 随后正常输出无法完成任务的说明,invocation 仍是 completed,maka run 最终返回 0。

未解决的 boundary requirement 必须成为非交互 invocation 的 terminal failure,不能依赖是否发布了 request event。

7. [P2] Session bundle 没有从同一个 SQLite snapshot 读取 header 与 boundary

Bundle exporter 通过两个独立 exporter 调用写入 selected session metadata 和 selected boundary:

如果两次读取之间发生并发 Auto/Bypass transition,export 可能得到一个 revision 的 header 和另一个 revision 的 boundary。Import 随后会把两者共同接受为新的 genesis state。

Storage 应在一个 read transaction 内返回不可变的 portable { header, boundary } snapshot,然后再写两个 transfer file。

实现质量问题

Runtime 的 public boundary contract 仍允许 authoritative reader 缺失:

当前 first-party production call site 看起来都提供了 reader,因此我没有把它作为独立 exploit。但 public API 仍会从 header.permissionMode 静默重建 authority,保留了本 PR 声称要删除的 dual-authority fallback。

Boundary reader 应成为 required dependency。Interactive expansion support 可以单独表示为显式的 enabled/disabled capability。

此外,当前还有若干 source-regex 与 collaborator-call test,它们锁定 implementation shape,而不是验证 public behavior。我没有把这些测试作为本次 Request changes 的主要依据,但在修复上述路径时应将其替换为 behavioral coverage。

验证

最终 head d481739

  • npm run build:test 通过。
  • Linux sandbox smoke 通过,7/7。
  • Linux filesystem-worker smoke 通过,2/2。
  • SQLite session metadata tests 通过,30/30。
  • git diff --check a454b9a..d481739 通过。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

当前绿色测试覆盖了受支持的 sandbox 路径,但没有覆盖上述 worker-unavailable fail-open 路径与跨 surface 不一致。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

Thank you for the detailed review. I reproduced the reported paths and updated the PR to head 7abc0b9de.

All seven findings have now been addressed:

  1. Managed filesystem fail-open — fixed in 48ca2f864. Managed Read/Write/Edit now fail closed when the filesystem sandbox is unavailable; the host executor is reserved for explicit Bypass or External authority.

  2. Unreachable first process-network expansion — fixed in 05585da92. Bash now declares a non-authorizing sandbox capability requirement, allowing the runtime to produce an exact network expansion without parsing command text.

  3. External sessions on local interactive surfaces — fixed across 7823ab5d4 and 7abc0b9de. TUI rejects resuming External sessions without their owning harness. Desktop may display imported External history, but it is non-interactive: the composer and permission-mode controls are unavailable, permission commands are omitted, and External is never presented as Auto. Boundary loading also fails closed so Auto cannot flash before the authority snapshot arrives.

  4. Deep Research expansion and mutation surface — fixed in 3d347d48d, with the read-only tool-surface contract strengthened in c384056c5. Deep Research no longer receives mutation or boundary-expansion tools.

  5. Child boundary inheritance — fixed in 62581d26f and f04db4bec. Child admission and filesystem execution now use the inherited ExecutionBoundary explicitly, with managed, bypass, and external paths handled deliberately and child tool surfaces defined by explicit allowlists.

  6. Non-interactive unresolved boundary returning success — fixed in 093d9fad2. maka run now exits nonzero for an unresolved boundary requirement whether it appears as a request event or a structured tool failure.

  7. Non-atomic bundle boundary snapshot — fixed in 1715039e9. Session header and execution boundary are now read from one storage transaction before transfer files are written.

The implementation-quality concern was also addressed. 581f73ec5 removed the legacy boundary fallback, and fa4314bfe now makes readExecutionBoundary a required Runtime/AiSdkBackend dependency. Missing authority is rejected instead of reconstructing External or managed authority from legacy permissionMode. Tests that intentionally exercise an externally isolated raw runtime now opt into that authority explicitly.

For the Desktop follow-up, 7abc0b9de adds behavioral coverage for managed, bypass, loading, and external boundary projections, plus command-surface coverage. I did not broaden this follow-up into a rewrite of unrelated source-contract tests.

Validation on 7abc0b9de:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • full npm run test:dist across all workspaces
  • Runtime: 2,697 passed, 9 skipped, 0 failed
  • Desktop: 2,968 passed, 0 failed
  • GitHub typecheck, test, and e2e: all green

Could you please re-review the current head?

简体中文

感谢这次详细审查。我复现了报告中的路径,并已把 PR 更新到 head 7abc0b9de

七项 findings 现已全部处理:

  1. Managed filesystem fail-open — 已在 48ca2f864 修复。Filesystem sandbox 不可用时,managed Read/Write/Edit 现在会 fail closed;host executor 只供显式 Bypass 或 External authority 使用。

  2. 首次 process-network expansion 不可达 — 已在 05585da92 修复。Bash 现在声明一个本身不授予权限的 sandbox capability requirement,使 Runtime 无需解析 command text 就能生成精确的 network expansion。

  3. External session 被本地交互 surface 执行 — 已通过 7823ab5d47abc0b9de 修复。TUI 会拒绝在缺少所属 harness 时恢复 External session。Desktop 可以查看导入的 External 历史,但保持不可交互:composer 和 permission-mode control 不可用,permission command 不会出现,External 也绝不会显示为 Auto。Boundary 加载阶段同样 fail closed,避免 authority snapshot 到达前短暂显示 Auto。

  4. Deep Research expansion 与 mutation surface — 已在 3d347d48d 修复,并由 c384056c5 加强 read-only tool-surface 契约。Deep Research 不再获得 mutation 或 boundary-expansion tool。

  5. Child boundary inheritance — 已在 62581d26ff04db4bec 修复。Child admission 与 filesystem execution 现在显式使用继承的 ExecutionBoundary,managed、bypass、external 均有明确语义,child tool surface 由显式 allowlist 定义。

  6. 非交互 unresolved boundary 错误返回成功 — 已在 093d9fad2 修复。无论 boundary requirement 来自 request event 还是 structured tool failure,maka run 都会非零退出。

  7. Bundle boundary snapshot 非原子 — 已在 1715039e9 修复。Session header 与 execution boundary 现在会在同一个 storage transaction 中读取,然后才写入 transfer files。

实现质量问题也已处理。581f73ec5 删除了 legacy boundary fallback,fa4314bfe 则将 readExecutionBoundary 设为 Runtime/AiSdkBackend 的 required dependency。缺少 authority 时现在会直接拒绝,不再从 legacy permissionMode 重建 External 或 managed authority。需要直接测试 externally isolated raw runtime 的测试也会显式选择该 authority。

Desktop follow-up 7abc0b9de 增加了 managed、bypass、loading、external boundary projection 的行为测试,以及 command surface 测试。此次 follow-up 没有盲目扩大到重写无关的 source-contract test。

7abc0b9de 上的验证结果:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • 全 workspace npm run test:dist
  • Runtime:2,697 通过,9 跳过,0 失败
  • Desktop:2,968 通过,0 失败
  • GitHub typecheckteste2e:全部绿色

能否请你基于当前 head 再 review 一次?

@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed head 7abc0b9de and reran the relevant targeted tests.

Re-review outcome

The following findings are resolved:

  1. Managed filesystem execution now fails closed when the worker sandbox is unavailable.
  2. Bash can declare an exact process-network boundary requirement without parsing command text.
  3. External sessions are rejected by TUI and remain non-interactive in Desktop.
  4. Deep Research now receives a read-only tool surface without boundary-expansion tools.
  5. Non-interactive unresolved boundary failures now produce a nonzero exit.
  6. Session bundle metadata and boundary are read from one SQLite authority snapshot.
  7. readExecutionBoundary is now required, and the Runtime legacy boundary fallback has been removed.

One finding remains open.

[P2] Child filesystem execution still does not inherit Bypass or External semantics

The parent ExecutionBoundary is persisted into the child, but ordinary child creation still stores the Agent definition’s legacy permission mode:

The filesystem worker only consumes the supplied boundary when its kind is managed. For Bypass or External, it falls back to permissionProfile or the child’s legacy mode:

Bash, by contrast, explicitly skips the Maka sandbox for the inherited Bypass or External boundary:

I reproduced the remaining mismatch on 7abc0b9de by executing an outside-workspace filesystem write with a Bypass or External boundary and a legacy child mode:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

The worker process was never launched. The operation was rejected by the legacy profile selected before sandbox execution.

The explicit child tool allowlists correctly constrain which tools a child receives, but they do not make those tools use the inherited boundary. An implementation child can therefore run Bash according to inherited Bypass/External authority while Read/Write/Edit continue to use a different filesystem authority.

Please make filesystem authority selection exhaustive over all ExecutionBoundary kinds. Once an authoritative boundary is supplied, the filesystem client should not fall back to permissionMode. A regression test should exercise a real inherited child Bypass/External boundary through the builtin filesystem tool path.

Validation

On 7abc0b9de:

  • npm run build:test passed.
  • Runtime targeted tests passed, 100/100.
  • CLI targeted tests passed, 72/72.
  • Storage targeted tests passed, 60/60.
  • Desktop targeted tests passed, 13/13.
  • Linux sandbox and filesystem-worker smoke tests passed, 9/9.
  • GitHub typecheck, test, and e2e checks are green.

I did not find another blocker in the follow-up scope. The previous findings can remain resolved; only the child filesystem-boundary finding remains open.

简体中文

@Astro-Han

我基于 head 7abc0b9de 完成了 re-review,并重新运行了相关定向测试。

Re-review 结论

以下 findings 已确认 resolved:

  1. Filesystem worker sandbox 不可用时,managed filesystem execution 现在会 fail closed。
  2. Bash 现在可以在不解析 command text 的情况下声明精确的 process-network boundary requirement。
  3. TUI 会拒绝 External session,Desktop 中的 External session 保持不可交互。
  4. Deep Research 现在只获得 read-only tool surface,不再获得 boundary-expansion tool。
  5. 非交互 unresolved boundary failure 现在会产生非零退出码。
  6. Session bundle metadata 与 boundary 现在从同一个 SQLite authority snapshot 读取。
  7. readExecutionBoundary 已成为 required dependency,Runtime legacy boundary fallback 也已删除。

仍有一项 finding 未关闭。

[P2] Child filesystem execution 仍未继承 Bypass 或 External 语义

Parent ExecutionBoundary 已经持久化到 child,但普通 child 创建仍会把 Agent definition 的 legacy permission mode 写入 header:

Filesystem worker 只有在 boundary kind 为 managed 时才消费传入的 boundary。对于 Bypass 或 External,它仍会退回 permissionProfile 或 child legacy mode

Bash 则会针对 inherited Bypass 或 External boundary 显式跳过 Maka sandbox:

我在 7abc0b9de 上使用 Bypass/External boundary 与 legacy child mode 执行 workspace 外 filesystem write,仍能复现该不一致:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

Worker process 没有启动。操作在 sandbox execution 之前就被 legacy profile 拒绝。

显式 child tool allowlist 正确限制了 child 可以获得哪些工具,但没有让这些工具使用 inherited boundary。因此 implementation child 仍可能让 Bash 遵循 inherited Bypass/External authority,而 Read/Write/Edit 使用另一套 filesystem authority。

请对所有 ExecutionBoundary kind 做穷举的 filesystem authority selection。一旦提供 authoritative boundary,filesystem client 就不应再退回 permissionMode。Regression test 应通过 builtin filesystem tool 路径,覆盖真实 inherited child Bypass/External boundary。

验证

7abc0b9de 上:

  • npm run build:test 通过。
  • Runtime 定向测试通过,100/100。
  • CLI 定向测试通过,72/72。
  • Storage 定向测试通过,60/60。
  • Desktop 定向测试通过,13/13。
  • Linux sandbox 与 filesystem-worker smoke tests 通过,9/9。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

在本次 follow-up 范围内没有发现其他 blocker。此前其余 findings 可以保持 resolved;目前只剩 child filesystem-boundary finding 未关闭。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

@M4n5ter

Thank you. I addressed the remaining child filesystem-boundary finding. The current head is 3f5443b7f.

The root cause was that the filesystem worker boundary was not explicit enough: it is a managed-only enforcement path, while Bypass and External execution must never be projected into it or reconstructed from a legacy child mode.

The fix now covers both layers:

  1. bf370bd1a makes builtin filesystem dispatch depend on the authoritative ExecutionBoundary before any worker call:

    • Managed routes through the filesystem worker and fails closed when enforcement is unavailable.
    • Bypass and External route through the executor supplied by their owning surface.
    • Neither path consults the child’s legacy permissionMode.
  2. 3f5443b7f closes the lower-level API ambiguity:

    • FilesystemWorkerClient now rejects any supplied Bypass or External boundary.
    • Once an authoritative boundary is supplied, the client can no longer fall back to permissionProfile or mode.

The regression coverage reproduces the inherited-child shape directly through builtin Write: legacy permissionMode: explore combined with authoritative Bypass and External boundaries. Both use the non-worker path, while direct attempts to pass either boundary into FilesystemWorkerClient fail before validation or process launch.

Fresh-eye validation also added bounded hardening around boundary narrowing, stale linked-child resume, External admission, descendant non-interactive failures, exact-write grant isolation, authority round-trips, and prompt response races. These remain separate atomic commits and do not reintroduce the generic permission or legacy mode paths.

Validation on 3f5443b7f:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • full serial npm run test:dist across all workspaces
  • Runtime after the final worker-client change: 2,706 passed, 9 skipped, 0 failed
  • Runtime Host: 303 passed, 0 failed
  • Desktop: 2,970 passed, 0 failed
  • targeted builtin filesystem-worker and client tests: 20 passed, 0 failed

Could you please re-review the current head?

简体中文

@M4n5ter

感谢。我已经处理了最后一项 child filesystem-boundary finding。当前 head 为 3f5443b7f

根因是 filesystem worker 的职责边界不够明确:它只应是 Managed 的 enforcement path;Bypass 与 External execution 既不应进入 worker,也不能从 legacy child mode 重建权限。

修复现在覆盖两层:

  1. bf370bd1a 让 builtin filesystem dispatch 在调用 worker 前直接依据权威 ExecutionBoundary 路由:

    • Managed 必须走 filesystem worker;enforcement 不可用时 fail closed。
    • Bypass 与 External 走所属 surface 注入的 executor。
    • 两条路径都不再查询 child 的 legacy permissionMode
  2. 3f5443b7f 关闭了底层 API 的歧义:

    • FilesystemWorkerClient 现在会拒绝任何传入的 Bypass 或 External boundary。
    • 一旦提供权威 boundary,client 就不能再回退到 permissionProfilemode

回归测试通过 builtin Write 直接复现 inherited-child 的组合:legacy permissionMode: explore 加权威 Bypass/External boundary。两者都会走非 worker 路径;如果直接把任一 boundary 传给 FilesystemWorkerClient,则会在 validation 或进程启动前 fail closed。

Fresh-eye 验证还以有限范围补强了 boundary narrowing、stale linked-child resume、External admission、非交互后代失败、exact-write grant 隔离、authority round-trip 和 prompt response race。它们都保留为独立原子提交,也没有重新引入 generic permission 或 legacy mode 路径。

3f5443b7f 上的验证:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • 全 workspace 串行 npm run test:dist
  • 最后一项 worker-client 修复后的 Runtime:2,706 通过,9 跳过,0 失败
  • Runtime Host:303 通过,0 失败
  • Desktop:2,970 通过,0 失败
  • builtin filesystem-worker 与 client 定向测试:20 通过,0 失败

能否请你基于当前 head 再 review 一次?

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 3f5443b to c4a7062CompareJuly 29, 2026 08:43
@M4n5ter

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed the latest head c4a7062c9. The rebase preserved the 13 follow-up patches; the new final commit only reconciles an AI-provider test fixture.

Re-review outcome

The previously reported child filesystem-boundary mismatch is resolved. Builtin filesystem dispatch now follows the authoritative boundary, and the targeted builtin/client tests pass 20/20.

Request changes. Three correctness blockers and four additional gaps remain.

Blocking correctness findings

1. [P1] A missing exact-write grant still blocks unrelated Bash commands on real Linux

prepareLinuxBashExactWriteTargets now prepares only exact paths declared by the current required_boundary, but the complete durable profile is still passed to bubblewrap:

Every exact-write entry in that profile remains a bind-mount source. If an undeclared exact target or its parent no longer exists, bubblewrap fails before executing the command.

I reproduced this with an unrelated command:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

The added unit test does not catch this because it uses a fake available sandbox manager and never executes the generated bubblewrap command.

This is also the current required-CI failure: Linux sandbox smoke fails 6/7 with the same missing-source error.

The per-invocation Linux mount plan should omit absent undeclared exact entries while safely preparing an exact target that the current invocation declares. This needs a real bubblewrap smoke test for both cases.

2. [P1] Legacy permissionCeiling prevents default Auto sessions from creating executable children

A normal new session still defaults to legacy permissionMode: ask, while Web Research and Implementation definitions use execute. Child creation therefore stores permissionMode: execute with permissionCeiling: ask:

Current-header normalization still treats that legacy ceiling as live authority:

I reproduced the resulting persistence failure:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

This happens before the inherited ExecutionBoundary can govern the child. permissionCeiling should be limited to legacy decoding/migration, not written or enforced for current child sessions. A SQLite-backed child-creation behavior test should cover an Implementation child spawned from the default Auto session.

3. [P1] Narrowing a parent boundary does not revoke descendant background processes

A child Bash run is registered under the child session ID:

The parent boundary transition terminates only the parent session’s shell runs:

A foreground child can start background Bash, return, and leave the process alive. The parent can then narrow from Bypass to Auto, or Auto to Explore, while that descendant process continues with its old authority. The stale-child resume guard prevents a future resume but does not revoke already-live processes.

Boundary narrowing needs lineage-wide revocation of descendant shell runs and backend generations before committing the transition, with regression coverage for a completed child turn that leaves background Bash running.

Additional correctness gap

4. [P2] An Explore-origin session cannot return from Bypass to Auto

For an Explore-origin session, genesis is the managed read-only profile. After switching to Bypass, restoration searches only for a previous non-read-only managed profile:

I reproduced:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

The transition should be total for supported UI states. If Explore sessions may enter Bypass, a missing Auto history should restore the canonical Auto genesis profile. If they must remain read-only, Bypass should be rejected and hidden before the transition.

Maintainability findings

5. [P2] Sandbox containment semantics are duplicated inside SessionManager

The follow-up adds approximately 70 lines of profile, access, path, deny, and protected-metadata containment logic to an already very large runtime coordinator:

Boundary containment is a core contract and will drift if Runtime owns a second implementation. Please expose one canonical Core helper and keep SessionManager as a caller.

6. [P2] The public legacy snapshot exporter can silently omit authoritative boundaries

exportLegacySessionTreeSnapshot accepts required records but an optional boundary map, and silently skips the boundary transfer file when an entry is absent:

The production wrapper currently supplies the map, but the exported public helper still permits a boundary-less session export. Its input should carry paired authority snapshots and require one boundary for every selected session.

7. [P2] The new External-admission regression test verifies source layout, not behavior

The test reads main.ts and uses regular expressions to require a specific helper name, handler layout, and call text:

It can pass without proving that IPC admission rejects External execution, and harmless refactoring can break it. Please replace it with an IPC behavior harness covering compact, resume, regenerate, and plan approval, asserting that runtime execution is not reached.

Validation

On c4a7062c9:

  • npm run build:test passed.
  • Child filesystem builtin/client tests passed, 20/20.
  • The default-Auto executable-child header was rejected in a direct current-header normalization reproduction.
  • Explore → Bypass → Auto failed in an in-memory SQLite reproduction.
  • An unrelated true command failed under real bubblewrap when the profile contained a missing exact-write grant.
  • Local required Linux sandbox smoke failed, 6/7.
  • GitHub typecheck and e2e are green; test is red on the same Linux smoke failure.
简体中文

@Astro-Han

我基于最新 head c4a7062c9 完成了 re-review。Rebase 保留了 13 个 follow-up patch;新增的最后一个 commit 只调整了 AI provider test fixture。

Re-review 结论

此前未关闭的 child filesystem-boundary 不一致已经解决。Builtin filesystem dispatch 现在遵循 authoritative boundary,相关 builtin/client 定向测试 20/20 通过。

仍需 Request changes。目前还有三项 correctness blocker 和四项其它问题。

阻塞性 correctness findings

1. [P1] 失效的 exact-write grant 在真实 Linux 上仍会阻断无关 Bash 命令

prepareLinuxBashExactWriteTargets 现在只准备当前 required_boundary 声明的 exact path,但完整的持久化 profile 仍会传给 bubblewrap:

Profile 中的每个 exact-write entry 仍然会成为 bind-mount source。如果一个未被本次调用声明的 exact target 或其 parent 已不存在,bubblewrap 会在执行 command 前失败。

我使用一条完全无关的命令复现了该问题:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

新增的 unit test 使用 fake available sandbox manager,并未执行生成的 bubblewrap command,因此无法覆盖真实行为。

这也是当前 required CI 的失败原因:Linux sandbox smoke 以相同的 missing-source 错误失败,结果为 6/7。

Linux 每次调用的 mount plan 应忽略不存在且未被当前调用声明的 exact entry;如果当前调用显式声明 exact target,则应安全地准备它。两条路径都需要真实 bubblewrap smoke coverage。

2. [P1] Legacy permissionCeiling 会阻止默认 Auto session 创建 executable child

普通新 session 的 legacy permissionMode 默认仍为 ask,而 Web Research 与 Implementation definition 使用 execute。Child 创建因此会同时写入 permissionMode: executepermissionCeiling: ask

Current-header normalization 仍把 legacy ceiling 当作 live authority:

我复现到的持久化结果为:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

失败发生在 inherited ExecutionBoundary 能够治理 child 之前。permissionCeiling 应仅用于 legacy decode/migration,不应继续写入或验证 current child session。需要通过真实 SQLite child-creation 行为测试覆盖默认 Auto session 创建 Implementation child 的路径。

3. [P1] 收窄 parent boundary 不会撤销 descendant background process

Child Bash run 会记录在 child session ID 下:

Parent boundary transition 只终止 parent session 自身的 shell run:

Foreground child 可以启动 background Bash 后返回,但让进程继续运行。随后 parent 可以从 Bypass 收窄到 Auto,或从 Auto 收窄到 Explore;descendant process 仍保留旧 authority。Stale-child resume guard 只能阻止未来 resume,无法撤销已经存活的进程。

Boundary narrowing 应在提交 transition 前,按 session lineage 撤销所有 descendant shell run 与 backend generation,并增加“child turn 已结束但 background Bash 仍在运行”的 regression coverage。

其它 correctness gap

4. [P2] Explore-origin session 无法从 Bypass 返回 Auto

Explore-origin session 的 genesis 是 managed read-only profile。切换到 Bypass 后,恢复逻辑只查找历史中的 non-read-only managed profile:

我的复现结果为:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

所有受支持的 UI 状态都应拥有完整 transition。如果 Explore session 可以进入 Bypass,那么缺少 Auto history 时应恢复 canonical Auto genesis profile;如果它必须始终保持 read-only,则应在 transition 之前拒绝并隐藏 Bypass。

可维护性 findings

5. [P2] Sandbox containment 语义被重复实现在 SessionManager

Follow-up 在已经非常庞大的 runtime coordinator 中增加了约 70 行 profile、access、path、deny 与 protected-metadata containment 逻辑:

Boundary containment 属于 Core contract。Runtime 保留第二套实现会产生语义漂移。建议在 Core 暴露一个 canonical helper,让 SessionManager 只负责调用。

6. [P2] Public legacy snapshot exporter 可以静默遗漏 authoritative boundary

exportLegacySessionTreeSnapshot 要求提供 records,却把 boundary map 设为 optional;如果某个 entry 不存在,就会静默跳过 boundary transfer file:

当前 production wrapper 的确提供了 map,但导出的 public helper 仍允许生成缺失 boundary 的 session export。其输入应改为成对的 authority snapshot,并要求每个被选择的 session 都有 boundary。

7. [P2] 新增的 External-admission regression test 验证 source layout,而不是行为

该测试读取 main.ts,再用正则要求特定 helper 名称、handler 布局和调用文本:

它无法证明 IPC admission 确实会拒绝 External execution,同时正常重构也会使测试破裂。应替换为 IPC behavior harness,覆盖 compact、resume、regenerate 与 plan approval,并断言 runtime execution 未被调用。

验证

c4a7062c9 上:

  • npm run build:test 通过。
  • Child filesystem builtin/client tests 20/20 通过。
  • Direct current-header normalization 复现到默认 Auto executable-child header 被拒绝。
  • In-memory SQLite 复现到 Explore → Bypass → Auto 失败。
  • 在真实 bubblewrap 下,profile 含有失效 exact-write grant 时,无关的 true command 仍会失败。
  • 本地 required Linux sandbox smoke 失败,6/7。
  • GitHub typechecke2e 通过;test 因相同 Linux smoke 错误失败。

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch 2 times, most recently from 4c0af93 to d01db12CompareJuly 29, 2026 10:43
@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 58fdec7 to 6b82f24CompareJuly 29, 2026 11:52
@Astro-Han
Astro-Han merged commit 0fe34a7 into mainJul 29, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/1564-session-sandbox-boundary branch July 29, 2026 12:00
Astro-Han added a commit that referenced this pull request Jul 29, 2026
#1581 replaced tool permissions with session sandbox boundaries and removed
`PermissionEngine` from `@maka/runtime`, but left this test importing it and
passing a `permissionEngine` dependency that the session-stream deps type no
longer has. `main` has been red since: `tsc -p tsconfig.main.json` fails with
TS2305, which takes `build:main` down and with it the typecheck, test, and e2e
jobs on every branch.
Nothing in production takes a `permissionEngine` any more, and the test's
subject is usage readiness, so the import and the dependency go. No behavioural
change and no replacement needed.
Sign up for freeto 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.

feat: replace per-tool approvals with sandbox boundaries

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: replace tool permissions with session sandbox boundaries - #1581

Merged
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary
Jul 29, 2026
Merged

feat: replace tool permissions with session sandbox boundaries#1581
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace additional permissions, one-call sandbox escalation, and the live generic tool-approval path with one revisioned, session-scoped ExecutionBoundary authority.
  • Persist genesis boundaries, immutable expansion requests, and applied revisions in the SQLite session metadata store. Approval and boundary advancement commit atomically; stale, duplicate, and concurrently decided requests settle deterministically.
  • Keep the expansion schema no broader than the product needs today: exact/subtree filesystem read/write entries plus session network enablement. Tools report exact sandbox_boundary_required deltas or requires_bypass; Bash diagnostics never parse commands or invent authority.
  • Wire the boundary lifecycle end to end through core, storage, runtime, Runtime Host, session bundles, Desktop/shared UI, TUI, headless/Harbor, and non-interactive CLI. Desktop and TUI expose Auto/Bypass, boundary prompts take over the composer, and Bypass requires an explicit second confirmation.
  • Remove the superseded PermissionEngine matrix, grant ingress, generic permission prompts, and legacy live escalation executors in the same PR so no dual-authority intermediate state ships. Historical codecs and settled audit history remain readable; OS Permission Center behavior is unchanged.

Closes#1564

Verification

  • npm run build — passed across all workspaces.
  • npm run test:dist — passed the complete repository suite with the workspace runner in serial mode, including script contracts (176/176), storage (733 passed, 1 skipped), Runtime (2675 passed, 9 skipped), Runtime Host (212/212), and Desktop (2964/2964).
  • npm run format:check — passed, 1221 files checked.
  • npm run lint — passed, 2304 files checked.
  • npm run typecheck — passed across all workspaces.
  • node --test packages/runtime/dist/__tests__/macos-seatbelt-smoke.test.js packages/runtime/dist/__tests__/filesystem-worker-smoke.test.js — passed (9/9), including exact outside-path expansion and restricted network behavior.
  • npm run e2e -w @maka/desktop -- e2e/sandbox-boundary-takeover.spec.ts — passed (1/1), covering the visible Desktop composer takeover and approval journey.
  • The all-workspace parallel npm test command intermittently exhausted a Runtime Host test's local timing window under machine load. That package passed independently (212/212), and the complete serial repository run above passed; this PR does not broaden into unrelated test-harness timing changes.

Migration and breaking change

  • Legacy ask and execute sessions enter the managed workspace-write boundary; explore enters managed read-only; bypass remains bypass. First access durably records revision 0 without rewriting settled historical records.
  • Pending legacy permission interactions close with host_restarted during recovery because their live continuation authority cannot survive the upgrade.
  • Interactive surfaces now expose only Auto and Bypass. Removed permission modes and per-tool grant flags fail during CLI argument validation.
  • maka run defaults to Auto and cannot interactively expand a boundary, so it fails closed when expansion is requested. Only explicit --yolo creates or resumes a bypass session.
  • Headless/Harbor sessions explicitly use the external boundary; imports and exports preserve the authoritative boundary even though the SQLite database itself is not bundled.

Review focus

  • The SQLite transaction boundary around request settlement and boundary revision advancement, including cross-connection races.
  • The runtime continuation/publication barrier when a sandbox boundary or user question is pending, including durable denial when a turn closes.
  • The cross-surface fail-closed behavior for ordinary expansion requests versus requires_bypass.
  • The branch contains 105 small, reversible commits ordered from contracts and storage through runtime, surfaces, legacy-path removal, and regression coverage.

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 6f15924 to d481739CompareJuly 29, 2026 01:50
@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

Review outcome

Request changes.

I reviewed the final PR head d481739 against the accepted contract in #1564 and the guarantees stated in this PR body. The SQLite transition work, prompt settlement, --yolo protection, boundary persistence, and Linux sandbox tests are meaningful improvements, but several execution paths still violate the central invariants of this change.

The latest rebase and the final d481739 cleanup commit do not change the sandbox semantics described below.

Contract used for this review

The accepted #1564 contract requires:

  • one authoritative, session-scoped ExecutionBoundary;
  • managed execution to fail closed when enforcement is unavailable;
  • an exact, reachable expansion flow for process network and filesystem boundaries;
  • External execution only when an explicit external isolation owner exists;
  • Deep Research to remain internally managed and read-only;
  • child Agents to inherit the parent boundary;
  • non-interactive Auto to exit nonzero when an unavoidable boundary requirement cannot be resolved; and
  • session bundles to restore the authoritative boundary.

The alternative proposals to enable network by default, automatically fall through to Bypass, or treat user-provided paths as implicit authorization were explicitly rejected in the issue discussion. These findings are evaluated against the accepted issue body, not those alternatives.

Blocking findings

1. [P1] Managed filesystem tools fail open when the filesystem worker is unavailable

Desktop and CLI conditionally omit the filesystem worker when the platform cannot provide the built-in worker sandbox. buildBuiltinTools then falls back to createLocalWorkspaceExecutor, and Write/Edit/Read execute on the host instead of rejecting managed execution.

Relevant paths:

I reproduced this on the final head: a Write call under an explore/read-only boundary successfully created a file when no worker was supplied.

Managed execution must return an enforcement-unavailable failure before reaching the host executor. The host path should only be reachable for an explicit Bypass or harness-owned External boundary.

2. [P1] The first process-network expansion has no valid request path

Auto starts with restricted process network, but Bash has no declarative network requirement. A denied command returns only a likely sandbox-denial signal, without sandbox_boundary_required or a concrete network expansion:

Runtime guidance simultaneously states that the Agent must not infer an expansion and may request one only after a tool returns an exact expansion:

I reproduced an EPERM network denial with sandboxType: linux; the failure contained no required expansion. Commands such as npm install, git pull, and curl therefore cannot reach the session-level network approval flow required by #1564.

This needs a declarative, non-authorizing process-network requirement or an equally reliable backend signal that can produce the exact expansion without parsing command text.

3. [P1] An External session can resume in Desktop/TUI as Auto while Bash runs without a Maka sandbox

Imported session bundles can restore an External boundary. Bash treats both Bypass and External as instructions to skip the Maka sandbox:

Desktop maps every non-Bypass boundary to Auto, while TUI session switching continues to project the legacy permissionMode:

maka run correctly rejects this resume path, but ordinary Desktop and interactive TUI do not. The result is an Auto-labelled session executing host Bash without the external harness that supposedly owns isolation.

External sessions must be rejected by ordinary interactive surfaces unless an explicit external-isolation owner is injected. External must also never be presented as Auto.

Additional correctness gaps

4. [P2] Deep Research can request and receive write or network expansion

Deep Research starts with a managed read-only profile, but Desktop still includes the complete builtin surface and unconditionally exposes request_sandbox_boundary:

Storage applies an approved expansion to any managed profile, including read-only:

I reproduced approval of a network expansion on a Deep Research session. The resulting profile was still named read-only, but its network state was enabled.

The Deep Research surface should omit mutation tools and the boundary-request tool, and its internal read-only boundary must not be expandable into write or process-network authority.

5. [P2] Child boundary persistence is fixed, but filesystem execution does not fully inherit Bypass or External

The parent boundary is now persisted into the child correctly. However, the child header still uses the Agent definition’s legacy permission mode, and the filesystem worker only consumes managed boundaries:

For an inherited Bypass or External boundary, filesystem execution falls back to the child definition’s legacy profile. The same child can therefore run Bash according to the inherited boundary while Read/Write/Edit follow a different authority.

Boundary handling in the filesystem client should be exhaustive: managed, bypass, and external must each have explicit semantics, with no fallback to permissionMode.

6. [P2] Non-interactive Auto can still return exit code 0 after an unresolved boundary failure

maka run does not register the boundary-request tool. It marks the command as failed only after receiving a sandbox_boundary_request event:

A filesystem tool can instead return sandbox_boundary_required as an ordinary structured tool failure. If the model then produces a normal final answer explaining that it could not complete the task, the invocation remains completed and maka run returns 0.

An unresolved boundary requirement must become a terminal non-interactive invocation outcome, independently of whether a request event was published.

7. [P2] A session bundle does not read its header and boundary from one SQLite snapshot

The bundle exporter writes selected session metadata and the selected boundary through two independent exporter calls:

A concurrent Auto/Bypass transition between those reads can export a header from one revision and a boundary from another. Import then accepts both as the new genesis state.

Storage should provide one read transaction that returns an immutable portable { header, boundary } snapshot before either transfer file is written.

Implementation-quality concern

The Runtime public boundary contract still permits the authoritative reader to be absent:

All current first-party production call sites appear to provide the reader, so I am not treating this as a separate exploit. However, the public API still silently reconstructs authority from header.permissionMode, which preserves the dual-authority fallback that this PR claims to remove.

The boundary reader should be required. Interactive expansion support can be represented separately as an explicit enabled/disabled capability.

There are also several source-regex and collaborator-call tests that lock implementation shape rather than public behavior. I do not use those as the primary basis for this review, but they should be replaced with behavioral coverage while these paths are being corrected.

Validation

On final head d481739:

  • npm run build:test passed.
  • Linux sandbox smoke passed, 7/7.
  • Linux filesystem-worker smoke passed, 2/2.
  • SQLite session metadata tests passed, 30/30.
  • git diff --check a454b9a..d481739 passed.
  • GitHub typecheck, test, and e2e checks are green.

The green suite validates the supported sandbox path, but it does not cover the fail-open worker-unavailable path or the cross-surface inconsistencies above.

简体中文

审查结论

Request changes。

我基于 #1564 的已接受契约与本 PR body 声明的保证,对最终 head d481739 进行了审查。SQLite transition、Prompt settlement、--yolo 保护、boundary 持久化和 Linux sandbox 测试都是有价值的改进,但若干执行路径仍违反这次改动的核心不变量。

最新 rebase 与最终的 d481739 cleanup commit 没有改变下述 sandbox 语义。

本次审查采用的契约

已接受的 #1564 契约要求:

  • 每个 session 只有一个 authoritative、session-scoped ExecutionBoundary
  • enforcement 不可用时,managed execution 必须 fail closed;
  • process network 与 filesystem boundary 必须具有精确且可达的 expansion 流程;
  • External execution 只能在存在显式 external isolation owner 时使用;
  • Deep Research 必须保持内部 managed read-only;
  • 子 Agent 必须继承父 session boundary;
  • 非交互 Auto 遇到无法解决且不可避免的 boundary requirement 时必须非零退出;
  • session bundle 必须恢复 authoritative boundary。

Issue 讨论中关于默认启用 network、自动退化到 Bypass,以及把用户给出的路径视为隐式授权的替代提案已经被明确拒绝。以下 findings 以已接受的 issue body 为准,不采用这些替代提案。

阻塞问题

1. [P1] Filesystem worker 不可用时,managed filesystem tool 会 fail open

当平台无法提供内置 worker sandbox 时,Desktop 与 CLI 会有条件地省略 filesystem worker。buildBuiltinTools 随后退回 createLocalWorkspaceExecutor,导致 Write/Edit/Read 在 host 上执行,而不是拒绝 managed execution。

相关路径:

我在最终 head 上完成了复现:未提供 worker 时,explore/read-only boundary 下的 Write 成功创建了文件。

Managed execution 必须在进入 host executor 前返回 enforcement-unavailable failure。Host 路径只能由显式 Bypass 或 harness-owned External boundary 访问。

2. [P1] 首次 process-network expansion 没有合法的请求路径

Auto 默认限制 process network,但 Bash 没有声明 network requirement 的字段。命令被拒绝时只返回可能的 sandbox-denial signal,不包含 sandbox_boundary_required 或具体 network expansion:

Runtime guidance 同时要求 Agent 不得推断 expansion,且只有在工具返回精确 expansion 后才能请求:

我复现了带有 sandboxType: linuxEPERM network denial,但 failure 中没有 required expansion。因此 npm installgit pullcurl 等命令无法进入 #1564 要求的 session-level network approval 流程。

这里需要一个声明式且本身不授予权限的 process-network requirement,或同样可靠的 backend signal,以便在不解析 command text 的情况下生成精确 expansion。

3. [P1] External session 可以在 Desktop/TUI 中以 Auto 恢复,同时 Bash 不受 Maka sandbox 约束

导入的 session bundle 可以恢复 External boundary。Bash 将 Bypass 和 External 都视为跳过 Maka sandbox 的指令:

Desktop 把所有非 Bypass boundary 映射为 Auto,而 TUI session switching 继续投影 legacy permissionMode

maka run 已经正确拒绝该 resume 路径,但普通 Desktop 与交互式 TUI 没有拒绝。最终结果是:一个标记为 Auto 的 session 在缺少原定 external harness 的情况下执行 host Bash。

除非注入显式 external-isolation owner,否则普通交互式 surface 必须拒绝 External session。External 也绝不能显示为 Auto。

其他正确性缺口

4. [P2] Deep Research 可以请求并获得 write 或 network expansion

Deep Research 从 managed read-only profile 开始,但 Desktop 仍包含完整 builtin surface,并无条件暴露 request_sandbox_boundary

Storage 会把已批准的 expansion 应用到任意 managed profile,包括 read-only:

我复现了 Deep Research session 的 network expansion approval。结果 profile 仍名为 read-only,但 network state 已变为 enabled

Deep Research surface 应移除 mutation tool 与 boundary-request tool,其内部 read-only boundary 也不应扩张为 write 或 process-network authority。

5. [P2] Child boundary 已正确持久化,但 filesystem execution 没有完整继承 Bypass 或 External

Parent boundary 现在已经能正确持久化到 child。但 child header 仍使用 Agent definition 的 legacy permission mode,而 filesystem worker 只消费 managed boundary:

对于继承的 Bypass 或 External boundary,filesystem execution 会退回 child definition 的 legacy profile。同一个 child 因而可能让 Bash 遵循 inherited boundary,却让 Read/Write/Edit 遵循另一套 authority。

Filesystem client 应穷举处理 managed、bypass 与 external,不能再退回 permissionMode

6. [P2] 非交互 Auto 在 boundary failure 未解决后仍可能返回退出码 0

maka run 不注册 boundary-request tool。它只有在收到 sandbox_boundary_request event 后才把命令标记为失败:

Filesystem tool 也可能只把 sandbox_boundary_required 作为普通 structured tool failure 返回。如果 model 随后正常输出无法完成任务的说明,invocation 仍是 completed,maka run 最终返回 0。

未解决的 boundary requirement 必须成为非交互 invocation 的 terminal failure,不能依赖是否发布了 request event。

7. [P2] Session bundle 没有从同一个 SQLite snapshot 读取 header 与 boundary

Bundle exporter 通过两个独立 exporter 调用写入 selected session metadata 和 selected boundary:

如果两次读取之间发生并发 Auto/Bypass transition,export 可能得到一个 revision 的 header 和另一个 revision 的 boundary。Import 随后会把两者共同接受为新的 genesis state。

Storage 应在一个 read transaction 内返回不可变的 portable { header, boundary } snapshot,然后再写两个 transfer file。

实现质量问题

Runtime 的 public boundary contract 仍允许 authoritative reader 缺失:

当前 first-party production call site 看起来都提供了 reader,因此我没有把它作为独立 exploit。但 public API 仍会从 header.permissionMode 静默重建 authority,保留了本 PR 声称要删除的 dual-authority fallback。

Boundary reader 应成为 required dependency。Interactive expansion support 可以单独表示为显式的 enabled/disabled capability。

此外,当前还有若干 source-regex 与 collaborator-call test,它们锁定 implementation shape,而不是验证 public behavior。我没有把这些测试作为本次 Request changes 的主要依据,但在修复上述路径时应将其替换为 behavioral coverage。

验证

最终 head d481739

  • npm run build:test 通过。
  • Linux sandbox smoke 通过,7/7。
  • Linux filesystem-worker smoke 通过,2/2。
  • SQLite session metadata tests 通过,30/30。
  • git diff --check a454b9a..d481739 通过。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

当前绿色测试覆盖了受支持的 sandbox 路径,但没有覆盖上述 worker-unavailable fail-open 路径与跨 surface 不一致。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

Thank you for the detailed review. I reproduced the reported paths and updated the PR to head 7abc0b9de.

All seven findings have now been addressed:

  1. Managed filesystem fail-open — fixed in 48ca2f864. Managed Read/Write/Edit now fail closed when the filesystem sandbox is unavailable; the host executor is reserved for explicit Bypass or External authority.

  2. Unreachable first process-network expansion — fixed in 05585da92. Bash now declares a non-authorizing sandbox capability requirement, allowing the runtime to produce an exact network expansion without parsing command text.

  3. External sessions on local interactive surfaces — fixed across 7823ab5d4 and 7abc0b9de. TUI rejects resuming External sessions without their owning harness. Desktop may display imported External history, but it is non-interactive: the composer and permission-mode controls are unavailable, permission commands are omitted, and External is never presented as Auto. Boundary loading also fails closed so Auto cannot flash before the authority snapshot arrives.

  4. Deep Research expansion and mutation surface — fixed in 3d347d48d, with the read-only tool-surface contract strengthened in c384056c5. Deep Research no longer receives mutation or boundary-expansion tools.

  5. Child boundary inheritance — fixed in 62581d26f and f04db4bec. Child admission and filesystem execution now use the inherited ExecutionBoundary explicitly, with managed, bypass, and external paths handled deliberately and child tool surfaces defined by explicit allowlists.

  6. Non-interactive unresolved boundary returning success — fixed in 093d9fad2. maka run now exits nonzero for an unresolved boundary requirement whether it appears as a request event or a structured tool failure.

  7. Non-atomic bundle boundary snapshot — fixed in 1715039e9. Session header and execution boundary are now read from one storage transaction before transfer files are written.

The implementation-quality concern was also addressed. 581f73ec5 removed the legacy boundary fallback, and fa4314bfe now makes readExecutionBoundary a required Runtime/AiSdkBackend dependency. Missing authority is rejected instead of reconstructing External or managed authority from legacy permissionMode. Tests that intentionally exercise an externally isolated raw runtime now opt into that authority explicitly.

For the Desktop follow-up, 7abc0b9de adds behavioral coverage for managed, bypass, loading, and external boundary projections, plus command-surface coverage. I did not broaden this follow-up into a rewrite of unrelated source-contract tests.

Validation on 7abc0b9de:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • full npm run test:dist across all workspaces
  • Runtime: 2,697 passed, 9 skipped, 0 failed
  • Desktop: 2,968 passed, 0 failed
  • GitHub typecheck, test, and e2e: all green

Could you please re-review the current head?

简体中文

感谢这次详细审查。我复现了报告中的路径,并已把 PR 更新到 head 7abc0b9de

七项 findings 现已全部处理:

  1. Managed filesystem fail-open — 已在 48ca2f864 修复。Filesystem sandbox 不可用时,managed Read/Write/Edit 现在会 fail closed;host executor 只供显式 Bypass 或 External authority 使用。

  2. 首次 process-network expansion 不可达 — 已在 05585da92 修复。Bash 现在声明一个本身不授予权限的 sandbox capability requirement,使 Runtime 无需解析 command text 就能生成精确的 network expansion。

  3. External session 被本地交互 surface 执行 — 已通过 7823ab5d47abc0b9de 修复。TUI 会拒绝在缺少所属 harness 时恢复 External session。Desktop 可以查看导入的 External 历史,但保持不可交互:composer 和 permission-mode control 不可用,permission command 不会出现,External 也绝不会显示为 Auto。Boundary 加载阶段同样 fail closed,避免 authority snapshot 到达前短暂显示 Auto。

  4. Deep Research expansion 与 mutation surface — 已在 3d347d48d 修复,并由 c384056c5 加强 read-only tool-surface 契约。Deep Research 不再获得 mutation 或 boundary-expansion tool。

  5. Child boundary inheritance — 已在 62581d26ff04db4bec 修复。Child admission 与 filesystem execution 现在显式使用继承的 ExecutionBoundary,managed、bypass、external 均有明确语义,child tool surface 由显式 allowlist 定义。

  6. 非交互 unresolved boundary 错误返回成功 — 已在 093d9fad2 修复。无论 boundary requirement 来自 request event 还是 structured tool failure,maka run 都会非零退出。

  7. Bundle boundary snapshot 非原子 — 已在 1715039e9 修复。Session header 与 execution boundary 现在会在同一个 storage transaction 中读取,然后才写入 transfer files。

实现质量问题也已处理。581f73ec5 删除了 legacy boundary fallback,fa4314bfe 则将 readExecutionBoundary 设为 Runtime/AiSdkBackend 的 required dependency。缺少 authority 时现在会直接拒绝,不再从 legacy permissionMode 重建 External 或 managed authority。需要直接测试 externally isolated raw runtime 的测试也会显式选择该 authority。

Desktop follow-up 7abc0b9de 增加了 managed、bypass、loading、external boundary projection 的行为测试,以及 command surface 测试。此次 follow-up 没有盲目扩大到重写无关的 source-contract test。

7abc0b9de 上的验证结果:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • 全 workspace npm run test:dist
  • Runtime:2,697 通过,9 跳过,0 失败
  • Desktop:2,968 通过,0 失败
  • GitHub typecheckteste2e:全部绿色

能否请你基于当前 head 再 review 一次?

@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed head 7abc0b9de and reran the relevant targeted tests.

Re-review outcome

The following findings are resolved:

  1. Managed filesystem execution now fails closed when the worker sandbox is unavailable.
  2. Bash can declare an exact process-network boundary requirement without parsing command text.
  3. External sessions are rejected by TUI and remain non-interactive in Desktop.
  4. Deep Research now receives a read-only tool surface without boundary-expansion tools.
  5. Non-interactive unresolved boundary failures now produce a nonzero exit.
  6. Session bundle metadata and boundary are read from one SQLite authority snapshot.
  7. readExecutionBoundary is now required, and the Runtime legacy boundary fallback has been removed.

One finding remains open.

[P2] Child filesystem execution still does not inherit Bypass or External semantics

The parent ExecutionBoundary is persisted into the child, but ordinary child creation still stores the Agent definition’s legacy permission mode:

The filesystem worker only consumes the supplied boundary when its kind is managed. For Bypass or External, it falls back to permissionProfile or the child’s legacy mode:

Bash, by contrast, explicitly skips the Maka sandbox for the inherited Bypass or External boundary:

I reproduced the remaining mismatch on 7abc0b9de by executing an outside-workspace filesystem write with a Bypass or External boundary and a legacy child mode:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

The worker process was never launched. The operation was rejected by the legacy profile selected before sandbox execution.

The explicit child tool allowlists correctly constrain which tools a child receives, but they do not make those tools use the inherited boundary. An implementation child can therefore run Bash according to inherited Bypass/External authority while Read/Write/Edit continue to use a different filesystem authority.

Please make filesystem authority selection exhaustive over all ExecutionBoundary kinds. Once an authoritative boundary is supplied, the filesystem client should not fall back to permissionMode. A regression test should exercise a real inherited child Bypass/External boundary through the builtin filesystem tool path.

Validation

On 7abc0b9de:

  • npm run build:test passed.
  • Runtime targeted tests passed, 100/100.
  • CLI targeted tests passed, 72/72.
  • Storage targeted tests passed, 60/60.
  • Desktop targeted tests passed, 13/13.
  • Linux sandbox and filesystem-worker smoke tests passed, 9/9.
  • GitHub typecheck, test, and e2e checks are green.

I did not find another blocker in the follow-up scope. The previous findings can remain resolved; only the child filesystem-boundary finding remains open.

简体中文

@Astro-Han

我基于 head 7abc0b9de 完成了 re-review,并重新运行了相关定向测试。

Re-review 结论

以下 findings 已确认 resolved:

  1. Filesystem worker sandbox 不可用时,managed filesystem execution 现在会 fail closed。
  2. Bash 现在可以在不解析 command text 的情况下声明精确的 process-network boundary requirement。
  3. TUI 会拒绝 External session,Desktop 中的 External session 保持不可交互。
  4. Deep Research 现在只获得 read-only tool surface,不再获得 boundary-expansion tool。
  5. 非交互 unresolved boundary failure 现在会产生非零退出码。
  6. Session bundle metadata 与 boundary 现在从同一个 SQLite authority snapshot 读取。
  7. readExecutionBoundary 已成为 required dependency,Runtime legacy boundary fallback 也已删除。

仍有一项 finding 未关闭。

[P2] Child filesystem execution 仍未继承 Bypass 或 External 语义

Parent ExecutionBoundary 已经持久化到 child,但普通 child 创建仍会把 Agent definition 的 legacy permission mode 写入 header:

Filesystem worker 只有在 boundary kind 为 managed 时才消费传入的 boundary。对于 Bypass 或 External,它仍会退回 permissionProfile 或 child legacy mode

Bash 则会针对 inherited Bypass 或 External boundary 显式跳过 Maka sandbox:

我在 7abc0b9de 上使用 Bypass/External boundary 与 legacy child mode 执行 workspace 外 filesystem write,仍能复现该不一致:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

Worker process 没有启动。操作在 sandbox execution 之前就被 legacy profile 拒绝。

显式 child tool allowlist 正确限制了 child 可以获得哪些工具,但没有让这些工具使用 inherited boundary。因此 implementation child 仍可能让 Bash 遵循 inherited Bypass/External authority,而 Read/Write/Edit 使用另一套 filesystem authority。

请对所有 ExecutionBoundary kind 做穷举的 filesystem authority selection。一旦提供 authoritative boundary,filesystem client 就不应再退回 permissionMode。Regression test 应通过 builtin filesystem tool 路径,覆盖真实 inherited child Bypass/External boundary。

验证

7abc0b9de 上:

  • npm run build:test 通过。
  • Runtime 定向测试通过,100/100。
  • CLI 定向测试通过,72/72。
  • Storage 定向测试通过,60/60。
  • Desktop 定向测试通过,13/13。
  • Linux sandbox 与 filesystem-worker smoke tests 通过,9/9。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

在本次 follow-up 范围内没有发现其他 blocker。此前其余 findings 可以保持 resolved;目前只剩 child filesystem-boundary finding 未关闭。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

@M4n5ter

Thank you. I addressed the remaining child filesystem-boundary finding. The current head is 3f5443b7f.

The root cause was that the filesystem worker boundary was not explicit enough: it is a managed-only enforcement path, while Bypass and External execution must never be projected into it or reconstructed from a legacy child mode.

The fix now covers both layers:

  1. bf370bd1a makes builtin filesystem dispatch depend on the authoritative ExecutionBoundary before any worker call:

    • Managed routes through the filesystem worker and fails closed when enforcement is unavailable.
    • Bypass and External route through the executor supplied by their owning surface.
    • Neither path consults the child’s legacy permissionMode.
  2. 3f5443b7f closes the lower-level API ambiguity:

    • FilesystemWorkerClient now rejects any supplied Bypass or External boundary.
    • Once an authoritative boundary is supplied, the client can no longer fall back to permissionProfile or mode.

The regression coverage reproduces the inherited-child shape directly through builtin Write: legacy permissionMode: explore combined with authoritative Bypass and External boundaries. Both use the non-worker path, while direct attempts to pass either boundary into FilesystemWorkerClient fail before validation or process launch.

Fresh-eye validation also added bounded hardening around boundary narrowing, stale linked-child resume, External admission, descendant non-interactive failures, exact-write grant isolation, authority round-trips, and prompt response races. These remain separate atomic commits and do not reintroduce the generic permission or legacy mode paths.

Validation on 3f5443b7f:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • full serial npm run test:dist across all workspaces
  • Runtime after the final worker-client change: 2,706 passed, 9 skipped, 0 failed
  • Runtime Host: 303 passed, 0 failed
  • Desktop: 2,970 passed, 0 failed
  • targeted builtin filesystem-worker and client tests: 20 passed, 0 failed

Could you please re-review the current head?

简体中文

@M4n5ter

感谢。我已经处理了最后一项 child filesystem-boundary finding。当前 head 为 3f5443b7f

根因是 filesystem worker 的职责边界不够明确:它只应是 Managed 的 enforcement path;Bypass 与 External execution 既不应进入 worker,也不能从 legacy child mode 重建权限。

修复现在覆盖两层:

  1. bf370bd1a 让 builtin filesystem dispatch 在调用 worker 前直接依据权威 ExecutionBoundary 路由:

    • Managed 必须走 filesystem worker;enforcement 不可用时 fail closed。
    • Bypass 与 External 走所属 surface 注入的 executor。
    • 两条路径都不再查询 child 的 legacy permissionMode
  2. 3f5443b7f 关闭了底层 API 的歧义:

    • FilesystemWorkerClient 现在会拒绝任何传入的 Bypass 或 External boundary。
    • 一旦提供权威 boundary,client 就不能再回退到 permissionProfilemode

回归测试通过 builtin Write 直接复现 inherited-child 的组合:legacy permissionMode: explore 加权威 Bypass/External boundary。两者都会走非 worker 路径;如果直接把任一 boundary 传给 FilesystemWorkerClient,则会在 validation 或进程启动前 fail closed。

Fresh-eye 验证还以有限范围补强了 boundary narrowing、stale linked-child resume、External admission、非交互后代失败、exact-write grant 隔离、authority round-trip 和 prompt response race。它们都保留为独立原子提交,也没有重新引入 generic permission 或 legacy mode 路径。

3f5443b7f 上的验证:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • 全 workspace 串行 npm run test:dist
  • 最后一项 worker-client 修复后的 Runtime:2,706 通过,9 跳过,0 失败
  • Runtime Host:303 通过,0 失败
  • Desktop:2,970 通过,0 失败
  • builtin filesystem-worker 与 client 定向测试:20 通过,0 失败

能否请你基于当前 head 再 review 一次?

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 3f5443b to c4a7062CompareJuly 29, 2026 08:43
@M4n5ter

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed the latest head c4a7062c9. The rebase preserved the 13 follow-up patches; the new final commit only reconciles an AI-provider test fixture.

Re-review outcome

The previously reported child filesystem-boundary mismatch is resolved. Builtin filesystem dispatch now follows the authoritative boundary, and the targeted builtin/client tests pass 20/20.

Request changes. Three correctness blockers and four additional gaps remain.

Blocking correctness findings

1. [P1] A missing exact-write grant still blocks unrelated Bash commands on real Linux

prepareLinuxBashExactWriteTargets now prepares only exact paths declared by the current required_boundary, but the complete durable profile is still passed to bubblewrap:

Every exact-write entry in that profile remains a bind-mount source. If an undeclared exact target or its parent no longer exists, bubblewrap fails before executing the command.

I reproduced this with an unrelated command:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

The added unit test does not catch this because it uses a fake available sandbox manager and never executes the generated bubblewrap command.

This is also the current required-CI failure: Linux sandbox smoke fails 6/7 with the same missing-source error.

The per-invocation Linux mount plan should omit absent undeclared exact entries while safely preparing an exact target that the current invocation declares. This needs a real bubblewrap smoke test for both cases.

2. [P1] Legacy permissionCeiling prevents default Auto sessions from creating executable children

A normal new session still defaults to legacy permissionMode: ask, while Web Research and Implementation definitions use execute. Child creation therefore stores permissionMode: execute with permissionCeiling: ask:

Current-header normalization still treats that legacy ceiling as live authority:

I reproduced the resulting persistence failure:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

This happens before the inherited ExecutionBoundary can govern the child. permissionCeiling should be limited to legacy decoding/migration, not written or enforced for current child sessions. A SQLite-backed child-creation behavior test should cover an Implementation child spawned from the default Auto session.

3. [P1] Narrowing a parent boundary does not revoke descendant background processes

A child Bash run is registered under the child session ID:

The parent boundary transition terminates only the parent session’s shell runs:

A foreground child can start background Bash, return, and leave the process alive. The parent can then narrow from Bypass to Auto, or Auto to Explore, while that descendant process continues with its old authority. The stale-child resume guard prevents a future resume but does not revoke already-live processes.

Boundary narrowing needs lineage-wide revocation of descendant shell runs and backend generations before committing the transition, with regression coverage for a completed child turn that leaves background Bash running.

Additional correctness gap

4. [P2] An Explore-origin session cannot return from Bypass to Auto

For an Explore-origin session, genesis is the managed read-only profile. After switching to Bypass, restoration searches only for a previous non-read-only managed profile:

I reproduced:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

The transition should be total for supported UI states. If Explore sessions may enter Bypass, a missing Auto history should restore the canonical Auto genesis profile. If they must remain read-only, Bypass should be rejected and hidden before the transition.

Maintainability findings

5. [P2] Sandbox containment semantics are duplicated inside SessionManager

The follow-up adds approximately 70 lines of profile, access, path, deny, and protected-metadata containment logic to an already very large runtime coordinator:

Boundary containment is a core contract and will drift if Runtime owns a second implementation. Please expose one canonical Core helper and keep SessionManager as a caller.

6. [P2] The public legacy snapshot exporter can silently omit authoritative boundaries

exportLegacySessionTreeSnapshot accepts required records but an optional boundary map, and silently skips the boundary transfer file when an entry is absent:

The production wrapper currently supplies the map, but the exported public helper still permits a boundary-less session export. Its input should carry paired authority snapshots and require one boundary for every selected session.

7. [P2] The new External-admission regression test verifies source layout, not behavior

The test reads main.ts and uses regular expressions to require a specific helper name, handler layout, and call text:

It can pass without proving that IPC admission rejects External execution, and harmless refactoring can break it. Please replace it with an IPC behavior harness covering compact, resume, regenerate, and plan approval, asserting that runtime execution is not reached.

Validation

On c4a7062c9:

  • npm run build:test passed.
  • Child filesystem builtin/client tests passed, 20/20.
  • The default-Auto executable-child header was rejected in a direct current-header normalization reproduction.
  • Explore → Bypass → Auto failed in an in-memory SQLite reproduction.
  • An unrelated true command failed under real bubblewrap when the profile contained a missing exact-write grant.
  • Local required Linux sandbox smoke failed, 6/7.
  • GitHub typecheck and e2e are green; test is red on the same Linux smoke failure.
简体中文

@Astro-Han

我基于最新 head c4a7062c9 完成了 re-review。Rebase 保留了 13 个 follow-up patch;新增的最后一个 commit 只调整了 AI provider test fixture。

Re-review 结论

此前未关闭的 child filesystem-boundary 不一致已经解决。Builtin filesystem dispatch 现在遵循 authoritative boundary,相关 builtin/client 定向测试 20/20 通过。

仍需 Request changes。目前还有三项 correctness blocker 和四项其它问题。

阻塞性 correctness findings

1. [P1] 失效的 exact-write grant 在真实 Linux 上仍会阻断无关 Bash 命令

prepareLinuxBashExactWriteTargets 现在只准备当前 required_boundary 声明的 exact path,但完整的持久化 profile 仍会传给 bubblewrap:

Profile 中的每个 exact-write entry 仍然会成为 bind-mount source。如果一个未被本次调用声明的 exact target 或其 parent 已不存在,bubblewrap 会在执行 command 前失败。

我使用一条完全无关的命令复现了该问题:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

新增的 unit test 使用 fake available sandbox manager,并未执行生成的 bubblewrap command,因此无法覆盖真实行为。

这也是当前 required CI 的失败原因:Linux sandbox smoke 以相同的 missing-source 错误失败,结果为 6/7。

Linux 每次调用的 mount plan 应忽略不存在且未被当前调用声明的 exact entry;如果当前调用显式声明 exact target,则应安全地准备它。两条路径都需要真实 bubblewrap smoke coverage。

2. [P1] Legacy permissionCeiling 会阻止默认 Auto session 创建 executable child

普通新 session 的 legacy permissionMode 默认仍为 ask,而 Web Research 与 Implementation definition 使用 execute。Child 创建因此会同时写入 permissionMode: executepermissionCeiling: ask

Current-header normalization 仍把 legacy ceiling 当作 live authority:

我复现到的持久化结果为:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

失败发生在 inherited ExecutionBoundary 能够治理 child 之前。permissionCeiling 应仅用于 legacy decode/migration,不应继续写入或验证 current child session。需要通过真实 SQLite child-creation 行为测试覆盖默认 Auto session 创建 Implementation child 的路径。

3. [P1] 收窄 parent boundary 不会撤销 descendant background process

Child Bash run 会记录在 child session ID 下:

Parent boundary transition 只终止 parent session 自身的 shell run:

Foreground child 可以启动 background Bash 后返回,但让进程继续运行。随后 parent 可以从 Bypass 收窄到 Auto,或从 Auto 收窄到 Explore;descendant process 仍保留旧 authority。Stale-child resume guard 只能阻止未来 resume,无法撤销已经存活的进程。

Boundary narrowing 应在提交 transition 前,按 session lineage 撤销所有 descendant shell run 与 backend generation,并增加“child turn 已结束但 background Bash 仍在运行”的 regression coverage。

其它 correctness gap

4. [P2] Explore-origin session 无法从 Bypass 返回 Auto

Explore-origin session 的 genesis 是 managed read-only profile。切换到 Bypass 后,恢复逻辑只查找历史中的 non-read-only managed profile:

我的复现结果为:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

所有受支持的 UI 状态都应拥有完整 transition。如果 Explore session 可以进入 Bypass,那么缺少 Auto history 时应恢复 canonical Auto genesis profile;如果它必须始终保持 read-only,则应在 transition 之前拒绝并隐藏 Bypass。

可维护性 findings

5. [P2] Sandbox containment 语义被重复实现在 SessionManager

Follow-up 在已经非常庞大的 runtime coordinator 中增加了约 70 行 profile、access、path、deny 与 protected-metadata containment 逻辑:

Boundary containment 属于 Core contract。Runtime 保留第二套实现会产生语义漂移。建议在 Core 暴露一个 canonical helper,让 SessionManager 只负责调用。

6. [P2] Public legacy snapshot exporter 可以静默遗漏 authoritative boundary

exportLegacySessionTreeSnapshot 要求提供 records,却把 boundary map 设为 optional;如果某个 entry 不存在,就会静默跳过 boundary transfer file:

当前 production wrapper 的确提供了 map,但导出的 public helper 仍允许生成缺失 boundary 的 session export。其输入应改为成对的 authority snapshot,并要求每个被选择的 session 都有 boundary。

7. [P2] 新增的 External-admission regression test 验证 source layout,而不是行为

该测试读取 main.ts,再用正则要求特定 helper 名称、handler 布局和调用文本:

它无法证明 IPC admission 确实会拒绝 External execution,同时正常重构也会使测试破裂。应替换为 IPC behavior harness,覆盖 compact、resume、regenerate 与 plan approval,并断言 runtime execution 未被调用。

验证

c4a7062c9 上:

  • npm run build:test 通过。
  • Child filesystem builtin/client tests 20/20 通过。
  • Direct current-header normalization 复现到默认 Auto executable-child header 被拒绝。
  • In-memory SQLite 复现到 Explore → Bypass → Auto 失败。
  • 在真实 bubblewrap 下,profile 含有失效 exact-write grant 时,无关的 true command 仍会失败。
  • 本地 required Linux sandbox smoke 失败,6/7。
  • GitHub typechecke2e 通过;test 因相同 Linux smoke 错误失败。

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch 2 times, most recently from 4c0af93 to d01db12CompareJuly 29, 2026 10:43
@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 58fdec7 to 6b82f24CompareJuly 29, 2026 11:52
@Astro-Han
Astro-Han merged commit 0fe34a7 into mainJul 29, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/1564-session-sandbox-boundary branch July 29, 2026 12:00
Astro-Han added a commit that referenced this pull request Jul 29, 2026
#1581 replaced tool permissions with session sandbox boundaries and removed
`PermissionEngine` from `@maka/runtime`, but left this test importing it and
passing a `permissionEngine` dependency that the session-stream deps type no
longer has. `main` has been red since: `tsc -p tsconfig.main.json` fails with
TS2305, which takes `build:main` down and with it the typecheck, test, and e2e
jobs on every branch.
Nothing in production takes a `permissionEngine` any more, and the test's
subject is usage readiness, so the import and the dependency go. No behavioural
change and no replacement needed.
Sign up for freeto 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.

feat: replace per-tool approvals with sandbox boundaries

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: replace tool permissions with session sandbox boundaries - #1581

Merged
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary
Jul 29, 2026
Merged

feat: replace tool permissions with session sandbox boundaries#1581
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace additional permissions, one-call sandbox escalation, and the live generic tool-approval path with one revisioned, session-scoped ExecutionBoundary authority.
  • Persist genesis boundaries, immutable expansion requests, and applied revisions in the SQLite session metadata store. Approval and boundary advancement commit atomically; stale, duplicate, and concurrently decided requests settle deterministically.
  • Keep the expansion schema no broader than the product needs today: exact/subtree filesystem read/write entries plus session network enablement. Tools report exact sandbox_boundary_required deltas or requires_bypass; Bash diagnostics never parse commands or invent authority.
  • Wire the boundary lifecycle end to end through core, storage, runtime, Runtime Host, session bundles, Desktop/shared UI, TUI, headless/Harbor, and non-interactive CLI. Desktop and TUI expose Auto/Bypass, boundary prompts take over the composer, and Bypass requires an explicit second confirmation.
  • Remove the superseded PermissionEngine matrix, grant ingress, generic permission prompts, and legacy live escalation executors in the same PR so no dual-authority intermediate state ships. Historical codecs and settled audit history remain readable; OS Permission Center behavior is unchanged.

Closes#1564

Verification

  • npm run build — passed across all workspaces.
  • npm run test:dist — passed the complete repository suite with the workspace runner in serial mode, including script contracts (176/176), storage (733 passed, 1 skipped), Runtime (2675 passed, 9 skipped), Runtime Host (212/212), and Desktop (2964/2964).
  • npm run format:check — passed, 1221 files checked.
  • npm run lint — passed, 2304 files checked.
  • npm run typecheck — passed across all workspaces.
  • node --test packages/runtime/dist/__tests__/macos-seatbelt-smoke.test.js packages/runtime/dist/__tests__/filesystem-worker-smoke.test.js — passed (9/9), including exact outside-path expansion and restricted network behavior.
  • npm run e2e -w @maka/desktop -- e2e/sandbox-boundary-takeover.spec.ts — passed (1/1), covering the visible Desktop composer takeover and approval journey.
  • The all-workspace parallel npm test command intermittently exhausted a Runtime Host test's local timing window under machine load. That package passed independently (212/212), and the complete serial repository run above passed; this PR does not broaden into unrelated test-harness timing changes.

Migration and breaking change

  • Legacy ask and execute sessions enter the managed workspace-write boundary; explore enters managed read-only; bypass remains bypass. First access durably records revision 0 without rewriting settled historical records.
  • Pending legacy permission interactions close with host_restarted during recovery because their live continuation authority cannot survive the upgrade.
  • Interactive surfaces now expose only Auto and Bypass. Removed permission modes and per-tool grant flags fail during CLI argument validation.
  • maka run defaults to Auto and cannot interactively expand a boundary, so it fails closed when expansion is requested. Only explicit --yolo creates or resumes a bypass session.
  • Headless/Harbor sessions explicitly use the external boundary; imports and exports preserve the authoritative boundary even though the SQLite database itself is not bundled.

Review focus

  • The SQLite transaction boundary around request settlement and boundary revision advancement, including cross-connection races.
  • The runtime continuation/publication barrier when a sandbox boundary or user question is pending, including durable denial when a turn closes.
  • The cross-surface fail-closed behavior for ordinary expansion requests versus requires_bypass.
  • The branch contains 105 small, reversible commits ordered from contracts and storage through runtime, surfaces, legacy-path removal, and regression coverage.

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 6f15924 to d481739CompareJuly 29, 2026 01:50
@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

Review outcome

Request changes.

I reviewed the final PR head d481739 against the accepted contract in #1564 and the guarantees stated in this PR body. The SQLite transition work, prompt settlement, --yolo protection, boundary persistence, and Linux sandbox tests are meaningful improvements, but several execution paths still violate the central invariants of this change.

The latest rebase and the final d481739 cleanup commit do not change the sandbox semantics described below.

Contract used for this review

The accepted #1564 contract requires:

  • one authoritative, session-scoped ExecutionBoundary;
  • managed execution to fail closed when enforcement is unavailable;
  • an exact, reachable expansion flow for process network and filesystem boundaries;
  • External execution only when an explicit external isolation owner exists;
  • Deep Research to remain internally managed and read-only;
  • child Agents to inherit the parent boundary;
  • non-interactive Auto to exit nonzero when an unavoidable boundary requirement cannot be resolved; and
  • session bundles to restore the authoritative boundary.

The alternative proposals to enable network by default, automatically fall through to Bypass, or treat user-provided paths as implicit authorization were explicitly rejected in the issue discussion. These findings are evaluated against the accepted issue body, not those alternatives.

Blocking findings

1. [P1] Managed filesystem tools fail open when the filesystem worker is unavailable

Desktop and CLI conditionally omit the filesystem worker when the platform cannot provide the built-in worker sandbox. buildBuiltinTools then falls back to createLocalWorkspaceExecutor, and Write/Edit/Read execute on the host instead of rejecting managed execution.

Relevant paths:

I reproduced this on the final head: a Write call under an explore/read-only boundary successfully created a file when no worker was supplied.

Managed execution must return an enforcement-unavailable failure before reaching the host executor. The host path should only be reachable for an explicit Bypass or harness-owned External boundary.

2. [P1] The first process-network expansion has no valid request path

Auto starts with restricted process network, but Bash has no declarative network requirement. A denied command returns only a likely sandbox-denial signal, without sandbox_boundary_required or a concrete network expansion:

Runtime guidance simultaneously states that the Agent must not infer an expansion and may request one only after a tool returns an exact expansion:

I reproduced an EPERM network denial with sandboxType: linux; the failure contained no required expansion. Commands such as npm install, git pull, and curl therefore cannot reach the session-level network approval flow required by #1564.

This needs a declarative, non-authorizing process-network requirement or an equally reliable backend signal that can produce the exact expansion without parsing command text.

3. [P1] An External session can resume in Desktop/TUI as Auto while Bash runs without a Maka sandbox

Imported session bundles can restore an External boundary. Bash treats both Bypass and External as instructions to skip the Maka sandbox:

Desktop maps every non-Bypass boundary to Auto, while TUI session switching continues to project the legacy permissionMode:

maka run correctly rejects this resume path, but ordinary Desktop and interactive TUI do not. The result is an Auto-labelled session executing host Bash without the external harness that supposedly owns isolation.

External sessions must be rejected by ordinary interactive surfaces unless an explicit external-isolation owner is injected. External must also never be presented as Auto.

Additional correctness gaps

4. [P2] Deep Research can request and receive write or network expansion

Deep Research starts with a managed read-only profile, but Desktop still includes the complete builtin surface and unconditionally exposes request_sandbox_boundary:

Storage applies an approved expansion to any managed profile, including read-only:

I reproduced approval of a network expansion on a Deep Research session. The resulting profile was still named read-only, but its network state was enabled.

The Deep Research surface should omit mutation tools and the boundary-request tool, and its internal read-only boundary must not be expandable into write or process-network authority.

5. [P2] Child boundary persistence is fixed, but filesystem execution does not fully inherit Bypass or External

The parent boundary is now persisted into the child correctly. However, the child header still uses the Agent definition’s legacy permission mode, and the filesystem worker only consumes managed boundaries:

For an inherited Bypass or External boundary, filesystem execution falls back to the child definition’s legacy profile. The same child can therefore run Bash according to the inherited boundary while Read/Write/Edit follow a different authority.

Boundary handling in the filesystem client should be exhaustive: managed, bypass, and external must each have explicit semantics, with no fallback to permissionMode.

6. [P2] Non-interactive Auto can still return exit code 0 after an unresolved boundary failure

maka run does not register the boundary-request tool. It marks the command as failed only after receiving a sandbox_boundary_request event:

A filesystem tool can instead return sandbox_boundary_required as an ordinary structured tool failure. If the model then produces a normal final answer explaining that it could not complete the task, the invocation remains completed and maka run returns 0.

An unresolved boundary requirement must become a terminal non-interactive invocation outcome, independently of whether a request event was published.

7. [P2] A session bundle does not read its header and boundary from one SQLite snapshot

The bundle exporter writes selected session metadata and the selected boundary through two independent exporter calls:

A concurrent Auto/Bypass transition between those reads can export a header from one revision and a boundary from another. Import then accepts both as the new genesis state.

Storage should provide one read transaction that returns an immutable portable { header, boundary } snapshot before either transfer file is written.

Implementation-quality concern

The Runtime public boundary contract still permits the authoritative reader to be absent:

All current first-party production call sites appear to provide the reader, so I am not treating this as a separate exploit. However, the public API still silently reconstructs authority from header.permissionMode, which preserves the dual-authority fallback that this PR claims to remove.

The boundary reader should be required. Interactive expansion support can be represented separately as an explicit enabled/disabled capability.

There are also several source-regex and collaborator-call tests that lock implementation shape rather than public behavior. I do not use those as the primary basis for this review, but they should be replaced with behavioral coverage while these paths are being corrected.

Validation

On final head d481739:

  • npm run build:test passed.
  • Linux sandbox smoke passed, 7/7.
  • Linux filesystem-worker smoke passed, 2/2.
  • SQLite session metadata tests passed, 30/30.
  • git diff --check a454b9a..d481739 passed.
  • GitHub typecheck, test, and e2e checks are green.

The green suite validates the supported sandbox path, but it does not cover the fail-open worker-unavailable path or the cross-surface inconsistencies above.

简体中文

审查结论

Request changes。

我基于 #1564 的已接受契约与本 PR body 声明的保证,对最终 head d481739 进行了审查。SQLite transition、Prompt settlement、--yolo 保护、boundary 持久化和 Linux sandbox 测试都是有价值的改进,但若干执行路径仍违反这次改动的核心不变量。

最新 rebase 与最终的 d481739 cleanup commit 没有改变下述 sandbox 语义。

本次审查采用的契约

已接受的 #1564 契约要求:

  • 每个 session 只有一个 authoritative、session-scoped ExecutionBoundary
  • enforcement 不可用时,managed execution 必须 fail closed;
  • process network 与 filesystem boundary 必须具有精确且可达的 expansion 流程;
  • External execution 只能在存在显式 external isolation owner 时使用;
  • Deep Research 必须保持内部 managed read-only;
  • 子 Agent 必须继承父 session boundary;
  • 非交互 Auto 遇到无法解决且不可避免的 boundary requirement 时必须非零退出;
  • session bundle 必须恢复 authoritative boundary。

Issue 讨论中关于默认启用 network、自动退化到 Bypass,以及把用户给出的路径视为隐式授权的替代提案已经被明确拒绝。以下 findings 以已接受的 issue body 为准,不采用这些替代提案。

阻塞问题

1. [P1] Filesystem worker 不可用时,managed filesystem tool 会 fail open

当平台无法提供内置 worker sandbox 时,Desktop 与 CLI 会有条件地省略 filesystem worker。buildBuiltinTools 随后退回 createLocalWorkspaceExecutor,导致 Write/Edit/Read 在 host 上执行,而不是拒绝 managed execution。

相关路径:

我在最终 head 上完成了复现:未提供 worker 时,explore/read-only boundary 下的 Write 成功创建了文件。

Managed execution 必须在进入 host executor 前返回 enforcement-unavailable failure。Host 路径只能由显式 Bypass 或 harness-owned External boundary 访问。

2. [P1] 首次 process-network expansion 没有合法的请求路径

Auto 默认限制 process network,但 Bash 没有声明 network requirement 的字段。命令被拒绝时只返回可能的 sandbox-denial signal,不包含 sandbox_boundary_required 或具体 network expansion:

Runtime guidance 同时要求 Agent 不得推断 expansion,且只有在工具返回精确 expansion 后才能请求:

我复现了带有 sandboxType: linuxEPERM network denial,但 failure 中没有 required expansion。因此 npm installgit pullcurl 等命令无法进入 #1564 要求的 session-level network approval 流程。

这里需要一个声明式且本身不授予权限的 process-network requirement,或同样可靠的 backend signal,以便在不解析 command text 的情况下生成精确 expansion。

3. [P1] External session 可以在 Desktop/TUI 中以 Auto 恢复,同时 Bash 不受 Maka sandbox 约束

导入的 session bundle 可以恢复 External boundary。Bash 将 Bypass 和 External 都视为跳过 Maka sandbox 的指令:

Desktop 把所有非 Bypass boundary 映射为 Auto,而 TUI session switching 继续投影 legacy permissionMode

maka run 已经正确拒绝该 resume 路径,但普通 Desktop 与交互式 TUI 没有拒绝。最终结果是:一个标记为 Auto 的 session 在缺少原定 external harness 的情况下执行 host Bash。

除非注入显式 external-isolation owner,否则普通交互式 surface 必须拒绝 External session。External 也绝不能显示为 Auto。

其他正确性缺口

4. [P2] Deep Research 可以请求并获得 write 或 network expansion

Deep Research 从 managed read-only profile 开始,但 Desktop 仍包含完整 builtin surface,并无条件暴露 request_sandbox_boundary

Storage 会把已批准的 expansion 应用到任意 managed profile,包括 read-only:

我复现了 Deep Research session 的 network expansion approval。结果 profile 仍名为 read-only,但 network state 已变为 enabled

Deep Research surface 应移除 mutation tool 与 boundary-request tool,其内部 read-only boundary 也不应扩张为 write 或 process-network authority。

5. [P2] Child boundary 已正确持久化,但 filesystem execution 没有完整继承 Bypass 或 External

Parent boundary 现在已经能正确持久化到 child。但 child header 仍使用 Agent definition 的 legacy permission mode,而 filesystem worker 只消费 managed boundary:

对于继承的 Bypass 或 External boundary,filesystem execution 会退回 child definition 的 legacy profile。同一个 child 因而可能让 Bash 遵循 inherited boundary,却让 Read/Write/Edit 遵循另一套 authority。

Filesystem client 应穷举处理 managed、bypass 与 external,不能再退回 permissionMode

6. [P2] 非交互 Auto 在 boundary failure 未解决后仍可能返回退出码 0

maka run 不注册 boundary-request tool。它只有在收到 sandbox_boundary_request event 后才把命令标记为失败:

Filesystem tool 也可能只把 sandbox_boundary_required 作为普通 structured tool failure 返回。如果 model 随后正常输出无法完成任务的说明,invocation 仍是 completed,maka run 最终返回 0。

未解决的 boundary requirement 必须成为非交互 invocation 的 terminal failure,不能依赖是否发布了 request event。

7. [P2] Session bundle 没有从同一个 SQLite snapshot 读取 header 与 boundary

Bundle exporter 通过两个独立 exporter 调用写入 selected session metadata 和 selected boundary:

如果两次读取之间发生并发 Auto/Bypass transition,export 可能得到一个 revision 的 header 和另一个 revision 的 boundary。Import 随后会把两者共同接受为新的 genesis state。

Storage 应在一个 read transaction 内返回不可变的 portable { header, boundary } snapshot,然后再写两个 transfer file。

实现质量问题

Runtime 的 public boundary contract 仍允许 authoritative reader 缺失:

当前 first-party production call site 看起来都提供了 reader,因此我没有把它作为独立 exploit。但 public API 仍会从 header.permissionMode 静默重建 authority,保留了本 PR 声称要删除的 dual-authority fallback。

Boundary reader 应成为 required dependency。Interactive expansion support 可以单独表示为显式的 enabled/disabled capability。

此外,当前还有若干 source-regex 与 collaborator-call test,它们锁定 implementation shape,而不是验证 public behavior。我没有把这些测试作为本次 Request changes 的主要依据,但在修复上述路径时应将其替换为 behavioral coverage。

验证

最终 head d481739

  • npm run build:test 通过。
  • Linux sandbox smoke 通过,7/7。
  • Linux filesystem-worker smoke 通过,2/2。
  • SQLite session metadata tests 通过,30/30。
  • git diff --check a454b9a..d481739 通过。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

当前绿色测试覆盖了受支持的 sandbox 路径,但没有覆盖上述 worker-unavailable fail-open 路径与跨 surface 不一致。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

Thank you for the detailed review. I reproduced the reported paths and updated the PR to head 7abc0b9de.

All seven findings have now been addressed:

  1. Managed filesystem fail-open — fixed in 48ca2f864. Managed Read/Write/Edit now fail closed when the filesystem sandbox is unavailable; the host executor is reserved for explicit Bypass or External authority.

  2. Unreachable first process-network expansion — fixed in 05585da92. Bash now declares a non-authorizing sandbox capability requirement, allowing the runtime to produce an exact network expansion without parsing command text.

  3. External sessions on local interactive surfaces — fixed across 7823ab5d4 and 7abc0b9de. TUI rejects resuming External sessions without their owning harness. Desktop may display imported External history, but it is non-interactive: the composer and permission-mode controls are unavailable, permission commands are omitted, and External is never presented as Auto. Boundary loading also fails closed so Auto cannot flash before the authority snapshot arrives.

  4. Deep Research expansion and mutation surface — fixed in 3d347d48d, with the read-only tool-surface contract strengthened in c384056c5. Deep Research no longer receives mutation or boundary-expansion tools.

  5. Child boundary inheritance — fixed in 62581d26f and f04db4bec. Child admission and filesystem execution now use the inherited ExecutionBoundary explicitly, with managed, bypass, and external paths handled deliberately and child tool surfaces defined by explicit allowlists.

  6. Non-interactive unresolved boundary returning success — fixed in 093d9fad2. maka run now exits nonzero for an unresolved boundary requirement whether it appears as a request event or a structured tool failure.

  7. Non-atomic bundle boundary snapshot — fixed in 1715039e9. Session header and execution boundary are now read from one storage transaction before transfer files are written.

The implementation-quality concern was also addressed. 581f73ec5 removed the legacy boundary fallback, and fa4314bfe now makes readExecutionBoundary a required Runtime/AiSdkBackend dependency. Missing authority is rejected instead of reconstructing External or managed authority from legacy permissionMode. Tests that intentionally exercise an externally isolated raw runtime now opt into that authority explicitly.

For the Desktop follow-up, 7abc0b9de adds behavioral coverage for managed, bypass, loading, and external boundary projections, plus command-surface coverage. I did not broaden this follow-up into a rewrite of unrelated source-contract tests.

Validation on 7abc0b9de:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • full npm run test:dist across all workspaces
  • Runtime: 2,697 passed, 9 skipped, 0 failed
  • Desktop: 2,968 passed, 0 failed
  • GitHub typecheck, test, and e2e: all green

Could you please re-review the current head?

简体中文

感谢这次详细审查。我复现了报告中的路径,并已把 PR 更新到 head 7abc0b9de

七项 findings 现已全部处理:

  1. Managed filesystem fail-open — 已在 48ca2f864 修复。Filesystem sandbox 不可用时,managed Read/Write/Edit 现在会 fail closed;host executor 只供显式 Bypass 或 External authority 使用。

  2. 首次 process-network expansion 不可达 — 已在 05585da92 修复。Bash 现在声明一个本身不授予权限的 sandbox capability requirement,使 Runtime 无需解析 command text 就能生成精确的 network expansion。

  3. External session 被本地交互 surface 执行 — 已通过 7823ab5d47abc0b9de 修复。TUI 会拒绝在缺少所属 harness 时恢复 External session。Desktop 可以查看导入的 External 历史,但保持不可交互:composer 和 permission-mode control 不可用,permission command 不会出现,External 也绝不会显示为 Auto。Boundary 加载阶段同样 fail closed,避免 authority snapshot 到达前短暂显示 Auto。

  4. Deep Research expansion 与 mutation surface — 已在 3d347d48d 修复,并由 c384056c5 加强 read-only tool-surface 契约。Deep Research 不再获得 mutation 或 boundary-expansion tool。

  5. Child boundary inheritance — 已在 62581d26ff04db4bec 修复。Child admission 与 filesystem execution 现在显式使用继承的 ExecutionBoundary,managed、bypass、external 均有明确语义,child tool surface 由显式 allowlist 定义。

  6. 非交互 unresolved boundary 错误返回成功 — 已在 093d9fad2 修复。无论 boundary requirement 来自 request event 还是 structured tool failure,maka run 都会非零退出。

  7. Bundle boundary snapshot 非原子 — 已在 1715039e9 修复。Session header 与 execution boundary 现在会在同一个 storage transaction 中读取,然后才写入 transfer files。

实现质量问题也已处理。581f73ec5 删除了 legacy boundary fallback,fa4314bfe 则将 readExecutionBoundary 设为 Runtime/AiSdkBackend 的 required dependency。缺少 authority 时现在会直接拒绝,不再从 legacy permissionMode 重建 External 或 managed authority。需要直接测试 externally isolated raw runtime 的测试也会显式选择该 authority。

Desktop follow-up 7abc0b9de 增加了 managed、bypass、loading、external boundary projection 的行为测试,以及 command surface 测试。此次 follow-up 没有盲目扩大到重写无关的 source-contract test。

7abc0b9de 上的验证结果:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • 全 workspace npm run test:dist
  • Runtime:2,697 通过,9 跳过,0 失败
  • Desktop:2,968 通过,0 失败
  • GitHub typecheckteste2e:全部绿色

能否请你基于当前 head 再 review 一次?

@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed head 7abc0b9de and reran the relevant targeted tests.

Re-review outcome

The following findings are resolved:

  1. Managed filesystem execution now fails closed when the worker sandbox is unavailable.
  2. Bash can declare an exact process-network boundary requirement without parsing command text.
  3. External sessions are rejected by TUI and remain non-interactive in Desktop.
  4. Deep Research now receives a read-only tool surface without boundary-expansion tools.
  5. Non-interactive unresolved boundary failures now produce a nonzero exit.
  6. Session bundle metadata and boundary are read from one SQLite authority snapshot.
  7. readExecutionBoundary is now required, and the Runtime legacy boundary fallback has been removed.

One finding remains open.

[P2] Child filesystem execution still does not inherit Bypass or External semantics

The parent ExecutionBoundary is persisted into the child, but ordinary child creation still stores the Agent definition’s legacy permission mode:

The filesystem worker only consumes the supplied boundary when its kind is managed. For Bypass or External, it falls back to permissionProfile or the child’s legacy mode:

Bash, by contrast, explicitly skips the Maka sandbox for the inherited Bypass or External boundary:

I reproduced the remaining mismatch on 7abc0b9de by executing an outside-workspace filesystem write with a Bypass or External boundary and a legacy child mode:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

The worker process was never launched. The operation was rejected by the legacy profile selected before sandbox execution.

The explicit child tool allowlists correctly constrain which tools a child receives, but they do not make those tools use the inherited boundary. An implementation child can therefore run Bash according to inherited Bypass/External authority while Read/Write/Edit continue to use a different filesystem authority.

Please make filesystem authority selection exhaustive over all ExecutionBoundary kinds. Once an authoritative boundary is supplied, the filesystem client should not fall back to permissionMode. A regression test should exercise a real inherited child Bypass/External boundary through the builtin filesystem tool path.

Validation

On 7abc0b9de:

  • npm run build:test passed.
  • Runtime targeted tests passed, 100/100.
  • CLI targeted tests passed, 72/72.
  • Storage targeted tests passed, 60/60.
  • Desktop targeted tests passed, 13/13.
  • Linux sandbox and filesystem-worker smoke tests passed, 9/9.
  • GitHub typecheck, test, and e2e checks are green.

I did not find another blocker in the follow-up scope. The previous findings can remain resolved; only the child filesystem-boundary finding remains open.

简体中文

@Astro-Han

我基于 head 7abc0b9de 完成了 re-review,并重新运行了相关定向测试。

Re-review 结论

以下 findings 已确认 resolved:

  1. Filesystem worker sandbox 不可用时,managed filesystem execution 现在会 fail closed。
  2. Bash 现在可以在不解析 command text 的情况下声明精确的 process-network boundary requirement。
  3. TUI 会拒绝 External session,Desktop 中的 External session 保持不可交互。
  4. Deep Research 现在只获得 read-only tool surface,不再获得 boundary-expansion tool。
  5. 非交互 unresolved boundary failure 现在会产生非零退出码。
  6. Session bundle metadata 与 boundary 现在从同一个 SQLite authority snapshot 读取。
  7. readExecutionBoundary 已成为 required dependency,Runtime legacy boundary fallback 也已删除。

仍有一项 finding 未关闭。

[P2] Child filesystem execution 仍未继承 Bypass 或 External 语义

Parent ExecutionBoundary 已经持久化到 child,但普通 child 创建仍会把 Agent definition 的 legacy permission mode 写入 header:

Filesystem worker 只有在 boundary kind 为 managed 时才消费传入的 boundary。对于 Bypass 或 External,它仍会退回 permissionProfile 或 child legacy mode

Bash 则会针对 inherited Bypass 或 External boundary 显式跳过 Maka sandbox:

我在 7abc0b9de 上使用 Bypass/External boundary 与 legacy child mode 执行 workspace 外 filesystem write,仍能复现该不一致:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

Worker process 没有启动。操作在 sandbox execution 之前就被 legacy profile 拒绝。

显式 child tool allowlist 正确限制了 child 可以获得哪些工具,但没有让这些工具使用 inherited boundary。因此 implementation child 仍可能让 Bash 遵循 inherited Bypass/External authority,而 Read/Write/Edit 使用另一套 filesystem authority。

请对所有 ExecutionBoundary kind 做穷举的 filesystem authority selection。一旦提供 authoritative boundary,filesystem client 就不应再退回 permissionMode。Regression test 应通过 builtin filesystem tool 路径,覆盖真实 inherited child Bypass/External boundary。

验证

7abc0b9de 上:

  • npm run build:test 通过。
  • Runtime 定向测试通过,100/100。
  • CLI 定向测试通过,72/72。
  • Storage 定向测试通过,60/60。
  • Desktop 定向测试通过,13/13。
  • Linux sandbox 与 filesystem-worker smoke tests 通过,9/9。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

在本次 follow-up 范围内没有发现其他 blocker。此前其余 findings 可以保持 resolved;目前只剩 child filesystem-boundary finding 未关闭。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

@M4n5ter

Thank you. I addressed the remaining child filesystem-boundary finding. The current head is 3f5443b7f.

The root cause was that the filesystem worker boundary was not explicit enough: it is a managed-only enforcement path, while Bypass and External execution must never be projected into it or reconstructed from a legacy child mode.

The fix now covers both layers:

  1. bf370bd1a makes builtin filesystem dispatch depend on the authoritative ExecutionBoundary before any worker call:

    • Managed routes through the filesystem worker and fails closed when enforcement is unavailable.
    • Bypass and External route through the executor supplied by their owning surface.
    • Neither path consults the child’s legacy permissionMode.
  2. 3f5443b7f closes the lower-level API ambiguity:

    • FilesystemWorkerClient now rejects any supplied Bypass or External boundary.
    • Once an authoritative boundary is supplied, the client can no longer fall back to permissionProfile or mode.

The regression coverage reproduces the inherited-child shape directly through builtin Write: legacy permissionMode: explore combined with authoritative Bypass and External boundaries. Both use the non-worker path, while direct attempts to pass either boundary into FilesystemWorkerClient fail before validation or process launch.

Fresh-eye validation also added bounded hardening around boundary narrowing, stale linked-child resume, External admission, descendant non-interactive failures, exact-write grant isolation, authority round-trips, and prompt response races. These remain separate atomic commits and do not reintroduce the generic permission or legacy mode paths.

Validation on 3f5443b7f:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • full serial npm run test:dist across all workspaces
  • Runtime after the final worker-client change: 2,706 passed, 9 skipped, 0 failed
  • Runtime Host: 303 passed, 0 failed
  • Desktop: 2,970 passed, 0 failed
  • targeted builtin filesystem-worker and client tests: 20 passed, 0 failed

Could you please re-review the current head?

简体中文

@M4n5ter

感谢。我已经处理了最后一项 child filesystem-boundary finding。当前 head 为 3f5443b7f

根因是 filesystem worker 的职责边界不够明确:它只应是 Managed 的 enforcement path;Bypass 与 External execution 既不应进入 worker,也不能从 legacy child mode 重建权限。

修复现在覆盖两层:

  1. bf370bd1a 让 builtin filesystem dispatch 在调用 worker 前直接依据权威 ExecutionBoundary 路由:

    • Managed 必须走 filesystem worker;enforcement 不可用时 fail closed。
    • Bypass 与 External 走所属 surface 注入的 executor。
    • 两条路径都不再查询 child 的 legacy permissionMode
  2. 3f5443b7f 关闭了底层 API 的歧义:

    • FilesystemWorkerClient 现在会拒绝任何传入的 Bypass 或 External boundary。
    • 一旦提供权威 boundary,client 就不能再回退到 permissionProfilemode

回归测试通过 builtin Write 直接复现 inherited-child 的组合:legacy permissionMode: explore 加权威 Bypass/External boundary。两者都会走非 worker 路径;如果直接把任一 boundary 传给 FilesystemWorkerClient,则会在 validation 或进程启动前 fail closed。

Fresh-eye 验证还以有限范围补强了 boundary narrowing、stale linked-child resume、External admission、非交互后代失败、exact-write grant 隔离、authority round-trip 和 prompt response race。它们都保留为独立原子提交,也没有重新引入 generic permission 或 legacy mode 路径。

3f5443b7f 上的验证:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • 全 workspace 串行 npm run test:dist
  • 最后一项 worker-client 修复后的 Runtime:2,706 通过,9 跳过,0 失败
  • Runtime Host:303 通过,0 失败
  • Desktop:2,970 通过,0 失败
  • builtin filesystem-worker 与 client 定向测试:20 通过,0 失败

能否请你基于当前 head 再 review 一次?

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 3f5443b to c4a7062CompareJuly 29, 2026 08:43
@M4n5ter

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed the latest head c4a7062c9. The rebase preserved the 13 follow-up patches; the new final commit only reconciles an AI-provider test fixture.

Re-review outcome

The previously reported child filesystem-boundary mismatch is resolved. Builtin filesystem dispatch now follows the authoritative boundary, and the targeted builtin/client tests pass 20/20.

Request changes. Three correctness blockers and four additional gaps remain.

Blocking correctness findings

1. [P1] A missing exact-write grant still blocks unrelated Bash commands on real Linux

prepareLinuxBashExactWriteTargets now prepares only exact paths declared by the current required_boundary, but the complete durable profile is still passed to bubblewrap:

Every exact-write entry in that profile remains a bind-mount source. If an undeclared exact target or its parent no longer exists, bubblewrap fails before executing the command.

I reproduced this with an unrelated command:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

The added unit test does not catch this because it uses a fake available sandbox manager and never executes the generated bubblewrap command.

This is also the current required-CI failure: Linux sandbox smoke fails 6/7 with the same missing-source error.

The per-invocation Linux mount plan should omit absent undeclared exact entries while safely preparing an exact target that the current invocation declares. This needs a real bubblewrap smoke test for both cases.

2. [P1] Legacy permissionCeiling prevents default Auto sessions from creating executable children

A normal new session still defaults to legacy permissionMode: ask, while Web Research and Implementation definitions use execute. Child creation therefore stores permissionMode: execute with permissionCeiling: ask:

Current-header normalization still treats that legacy ceiling as live authority:

I reproduced the resulting persistence failure:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

This happens before the inherited ExecutionBoundary can govern the child. permissionCeiling should be limited to legacy decoding/migration, not written or enforced for current child sessions. A SQLite-backed child-creation behavior test should cover an Implementation child spawned from the default Auto session.

3. [P1] Narrowing a parent boundary does not revoke descendant background processes

A child Bash run is registered under the child session ID:

The parent boundary transition terminates only the parent session’s shell runs:

A foreground child can start background Bash, return, and leave the process alive. The parent can then narrow from Bypass to Auto, or Auto to Explore, while that descendant process continues with its old authority. The stale-child resume guard prevents a future resume but does not revoke already-live processes.

Boundary narrowing needs lineage-wide revocation of descendant shell runs and backend generations before committing the transition, with regression coverage for a completed child turn that leaves background Bash running.

Additional correctness gap

4. [P2] An Explore-origin session cannot return from Bypass to Auto

For an Explore-origin session, genesis is the managed read-only profile. After switching to Bypass, restoration searches only for a previous non-read-only managed profile:

I reproduced:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

The transition should be total for supported UI states. If Explore sessions may enter Bypass, a missing Auto history should restore the canonical Auto genesis profile. If they must remain read-only, Bypass should be rejected and hidden before the transition.

Maintainability findings

5. [P2] Sandbox containment semantics are duplicated inside SessionManager

The follow-up adds approximately 70 lines of profile, access, path, deny, and protected-metadata containment logic to an already very large runtime coordinator:

Boundary containment is a core contract and will drift if Runtime owns a second implementation. Please expose one canonical Core helper and keep SessionManager as a caller.

6. [P2] The public legacy snapshot exporter can silently omit authoritative boundaries

exportLegacySessionTreeSnapshot accepts required records but an optional boundary map, and silently skips the boundary transfer file when an entry is absent:

The production wrapper currently supplies the map, but the exported public helper still permits a boundary-less session export. Its input should carry paired authority snapshots and require one boundary for every selected session.

7. [P2] The new External-admission regression test verifies source layout, not behavior

The test reads main.ts and uses regular expressions to require a specific helper name, handler layout, and call text:

It can pass without proving that IPC admission rejects External execution, and harmless refactoring can break it. Please replace it with an IPC behavior harness covering compact, resume, regenerate, and plan approval, asserting that runtime execution is not reached.

Validation

On c4a7062c9:

  • npm run build:test passed.
  • Child filesystem builtin/client tests passed, 20/20.
  • The default-Auto executable-child header was rejected in a direct current-header normalization reproduction.
  • Explore → Bypass → Auto failed in an in-memory SQLite reproduction.
  • An unrelated true command failed under real bubblewrap when the profile contained a missing exact-write grant.
  • Local required Linux sandbox smoke failed, 6/7.
  • GitHub typecheck and e2e are green; test is red on the same Linux smoke failure.
简体中文

@Astro-Han

我基于最新 head c4a7062c9 完成了 re-review。Rebase 保留了 13 个 follow-up patch;新增的最后一个 commit 只调整了 AI provider test fixture。

Re-review 结论

此前未关闭的 child filesystem-boundary 不一致已经解决。Builtin filesystem dispatch 现在遵循 authoritative boundary,相关 builtin/client 定向测试 20/20 通过。

仍需 Request changes。目前还有三项 correctness blocker 和四项其它问题。

阻塞性 correctness findings

1. [P1] 失效的 exact-write grant 在真实 Linux 上仍会阻断无关 Bash 命令

prepareLinuxBashExactWriteTargets 现在只准备当前 required_boundary 声明的 exact path,但完整的持久化 profile 仍会传给 bubblewrap:

Profile 中的每个 exact-write entry 仍然会成为 bind-mount source。如果一个未被本次调用声明的 exact target 或其 parent 已不存在,bubblewrap 会在执行 command 前失败。

我使用一条完全无关的命令复现了该问题:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

新增的 unit test 使用 fake available sandbox manager,并未执行生成的 bubblewrap command,因此无法覆盖真实行为。

这也是当前 required CI 的失败原因:Linux sandbox smoke 以相同的 missing-source 错误失败,结果为 6/7。

Linux 每次调用的 mount plan 应忽略不存在且未被当前调用声明的 exact entry;如果当前调用显式声明 exact target,则应安全地准备它。两条路径都需要真实 bubblewrap smoke coverage。

2. [P1] Legacy permissionCeiling 会阻止默认 Auto session 创建 executable child

普通新 session 的 legacy permissionMode 默认仍为 ask,而 Web Research 与 Implementation definition 使用 execute。Child 创建因此会同时写入 permissionMode: executepermissionCeiling: ask

Current-header normalization 仍把 legacy ceiling 当作 live authority:

我复现到的持久化结果为:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

失败发生在 inherited ExecutionBoundary 能够治理 child 之前。permissionCeiling 应仅用于 legacy decode/migration,不应继续写入或验证 current child session。需要通过真实 SQLite child-creation 行为测试覆盖默认 Auto session 创建 Implementation child 的路径。

3. [P1] 收窄 parent boundary 不会撤销 descendant background process

Child Bash run 会记录在 child session ID 下:

Parent boundary transition 只终止 parent session 自身的 shell run:

Foreground child 可以启动 background Bash 后返回,但让进程继续运行。随后 parent 可以从 Bypass 收窄到 Auto,或从 Auto 收窄到 Explore;descendant process 仍保留旧 authority。Stale-child resume guard 只能阻止未来 resume,无法撤销已经存活的进程。

Boundary narrowing 应在提交 transition 前,按 session lineage 撤销所有 descendant shell run 与 backend generation,并增加“child turn 已结束但 background Bash 仍在运行”的 regression coverage。

其它 correctness gap

4. [P2] Explore-origin session 无法从 Bypass 返回 Auto

Explore-origin session 的 genesis 是 managed read-only profile。切换到 Bypass 后,恢复逻辑只查找历史中的 non-read-only managed profile:

我的复现结果为:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

所有受支持的 UI 状态都应拥有完整 transition。如果 Explore session 可以进入 Bypass,那么缺少 Auto history 时应恢复 canonical Auto genesis profile;如果它必须始终保持 read-only,则应在 transition 之前拒绝并隐藏 Bypass。

可维护性 findings

5. [P2] Sandbox containment 语义被重复实现在 SessionManager

Follow-up 在已经非常庞大的 runtime coordinator 中增加了约 70 行 profile、access、path、deny 与 protected-metadata containment 逻辑:

Boundary containment 属于 Core contract。Runtime 保留第二套实现会产生语义漂移。建议在 Core 暴露一个 canonical helper,让 SessionManager 只负责调用。

6. [P2] Public legacy snapshot exporter 可以静默遗漏 authoritative boundary

exportLegacySessionTreeSnapshot 要求提供 records,却把 boundary map 设为 optional;如果某个 entry 不存在,就会静默跳过 boundary transfer file:

当前 production wrapper 的确提供了 map,但导出的 public helper 仍允许生成缺失 boundary 的 session export。其输入应改为成对的 authority snapshot,并要求每个被选择的 session 都有 boundary。

7. [P2] 新增的 External-admission regression test 验证 source layout,而不是行为

该测试读取 main.ts,再用正则要求特定 helper 名称、handler 布局和调用文本:

它无法证明 IPC admission 确实会拒绝 External execution,同时正常重构也会使测试破裂。应替换为 IPC behavior harness,覆盖 compact、resume、regenerate 与 plan approval,并断言 runtime execution 未被调用。

验证

c4a7062c9 上:

  • npm run build:test 通过。
  • Child filesystem builtin/client tests 20/20 通过。
  • Direct current-header normalization 复现到默认 Auto executable-child header 被拒绝。
  • In-memory SQLite 复现到 Explore → Bypass → Auto 失败。
  • 在真实 bubblewrap 下,profile 含有失效 exact-write grant 时,无关的 true command 仍会失败。
  • 本地 required Linux sandbox smoke 失败,6/7。
  • GitHub typechecke2e 通过;test 因相同 Linux smoke 错误失败。

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch 2 times, most recently from 4c0af93 to d01db12CompareJuly 29, 2026 10:43
@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 58fdec7 to 6b82f24CompareJuly 29, 2026 11:52
@Astro-Han
Astro-Han merged commit 0fe34a7 into mainJul 29, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/1564-session-sandbox-boundary branch July 29, 2026 12:00
Astro-Han added a commit that referenced this pull request Jul 29, 2026
#1581 replaced tool permissions with session sandbox boundaries and removed
`PermissionEngine` from `@maka/runtime`, but left this test importing it and
passing a `permissionEngine` dependency that the session-stream deps type no
longer has. `main` has been red since: `tsc -p tsconfig.main.json` fails with
TS2305, which takes `build:main` down and with it the typecheck, test, and e2e
jobs on every branch.
Nothing in production takes a `permissionEngine` any more, and the test's
subject is usage readiness, so the import and the dependency go. No behavioural
change and no replacement needed.
Sign up for freeto 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.

feat: replace per-tool approvals with sandbox boundaries

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: replace tool permissions with session sandbox boundaries - #1581

Merged
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary
Jul 29, 2026
Merged

feat: replace tool permissions with session sandbox boundaries#1581
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace additional permissions, one-call sandbox escalation, and the live generic tool-approval path with one revisioned, session-scoped ExecutionBoundary authority.
  • Persist genesis boundaries, immutable expansion requests, and applied revisions in the SQLite session metadata store. Approval and boundary advancement commit atomically; stale, duplicate, and concurrently decided requests settle deterministically.
  • Keep the expansion schema no broader than the product needs today: exact/subtree filesystem read/write entries plus session network enablement. Tools report exact sandbox_boundary_required deltas or requires_bypass; Bash diagnostics never parse commands or invent authority.
  • Wire the boundary lifecycle end to end through core, storage, runtime, Runtime Host, session bundles, Desktop/shared UI, TUI, headless/Harbor, and non-interactive CLI. Desktop and TUI expose Auto/Bypass, boundary prompts take over the composer, and Bypass requires an explicit second confirmation.
  • Remove the superseded PermissionEngine matrix, grant ingress, generic permission prompts, and legacy live escalation executors in the same PR so no dual-authority intermediate state ships. Historical codecs and settled audit history remain readable; OS Permission Center behavior is unchanged.

Closes#1564

Verification

  • npm run build — passed across all workspaces.
  • npm run test:dist — passed the complete repository suite with the workspace runner in serial mode, including script contracts (176/176), storage (733 passed, 1 skipped), Runtime (2675 passed, 9 skipped), Runtime Host (212/212), and Desktop (2964/2964).
  • npm run format:check — passed, 1221 files checked.
  • npm run lint — passed, 2304 files checked.
  • npm run typecheck — passed across all workspaces.
  • node --test packages/runtime/dist/__tests__/macos-seatbelt-smoke.test.js packages/runtime/dist/__tests__/filesystem-worker-smoke.test.js — passed (9/9), including exact outside-path expansion and restricted network behavior.
  • npm run e2e -w @maka/desktop -- e2e/sandbox-boundary-takeover.spec.ts — passed (1/1), covering the visible Desktop composer takeover and approval journey.
  • The all-workspace parallel npm test command intermittently exhausted a Runtime Host test's local timing window under machine load. That package passed independently (212/212), and the complete serial repository run above passed; this PR does not broaden into unrelated test-harness timing changes.

Migration and breaking change

  • Legacy ask and execute sessions enter the managed workspace-write boundary; explore enters managed read-only; bypass remains bypass. First access durably records revision 0 without rewriting settled historical records.
  • Pending legacy permission interactions close with host_restarted during recovery because their live continuation authority cannot survive the upgrade.
  • Interactive surfaces now expose only Auto and Bypass. Removed permission modes and per-tool grant flags fail during CLI argument validation.
  • maka run defaults to Auto and cannot interactively expand a boundary, so it fails closed when expansion is requested. Only explicit --yolo creates or resumes a bypass session.
  • Headless/Harbor sessions explicitly use the external boundary; imports and exports preserve the authoritative boundary even though the SQLite database itself is not bundled.

Review focus

  • The SQLite transaction boundary around request settlement and boundary revision advancement, including cross-connection races.
  • The runtime continuation/publication barrier when a sandbox boundary or user question is pending, including durable denial when a turn closes.
  • The cross-surface fail-closed behavior for ordinary expansion requests versus requires_bypass.
  • The branch contains 105 small, reversible commits ordered from contracts and storage through runtime, surfaces, legacy-path removal, and regression coverage.

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 6f15924 to d481739CompareJuly 29, 2026 01:50
@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

Review outcome

Request changes.

I reviewed the final PR head d481739 against the accepted contract in #1564 and the guarantees stated in this PR body. The SQLite transition work, prompt settlement, --yolo protection, boundary persistence, and Linux sandbox tests are meaningful improvements, but several execution paths still violate the central invariants of this change.

The latest rebase and the final d481739 cleanup commit do not change the sandbox semantics described below.

Contract used for this review

The accepted #1564 contract requires:

  • one authoritative, session-scoped ExecutionBoundary;
  • managed execution to fail closed when enforcement is unavailable;
  • an exact, reachable expansion flow for process network and filesystem boundaries;
  • External execution only when an explicit external isolation owner exists;
  • Deep Research to remain internally managed and read-only;
  • child Agents to inherit the parent boundary;
  • non-interactive Auto to exit nonzero when an unavoidable boundary requirement cannot be resolved; and
  • session bundles to restore the authoritative boundary.

The alternative proposals to enable network by default, automatically fall through to Bypass, or treat user-provided paths as implicit authorization were explicitly rejected in the issue discussion. These findings are evaluated against the accepted issue body, not those alternatives.

Blocking findings

1. [P1] Managed filesystem tools fail open when the filesystem worker is unavailable

Desktop and CLI conditionally omit the filesystem worker when the platform cannot provide the built-in worker sandbox. buildBuiltinTools then falls back to createLocalWorkspaceExecutor, and Write/Edit/Read execute on the host instead of rejecting managed execution.

Relevant paths:

I reproduced this on the final head: a Write call under an explore/read-only boundary successfully created a file when no worker was supplied.

Managed execution must return an enforcement-unavailable failure before reaching the host executor. The host path should only be reachable for an explicit Bypass or harness-owned External boundary.

2. [P1] The first process-network expansion has no valid request path

Auto starts with restricted process network, but Bash has no declarative network requirement. A denied command returns only a likely sandbox-denial signal, without sandbox_boundary_required or a concrete network expansion:

Runtime guidance simultaneously states that the Agent must not infer an expansion and may request one only after a tool returns an exact expansion:

I reproduced an EPERM network denial with sandboxType: linux; the failure contained no required expansion. Commands such as npm install, git pull, and curl therefore cannot reach the session-level network approval flow required by #1564.

This needs a declarative, non-authorizing process-network requirement or an equally reliable backend signal that can produce the exact expansion without parsing command text.

3. [P1] An External session can resume in Desktop/TUI as Auto while Bash runs without a Maka sandbox

Imported session bundles can restore an External boundary. Bash treats both Bypass and External as instructions to skip the Maka sandbox:

Desktop maps every non-Bypass boundary to Auto, while TUI session switching continues to project the legacy permissionMode:

maka run correctly rejects this resume path, but ordinary Desktop and interactive TUI do not. The result is an Auto-labelled session executing host Bash without the external harness that supposedly owns isolation.

External sessions must be rejected by ordinary interactive surfaces unless an explicit external-isolation owner is injected. External must also never be presented as Auto.

Additional correctness gaps

4. [P2] Deep Research can request and receive write or network expansion

Deep Research starts with a managed read-only profile, but Desktop still includes the complete builtin surface and unconditionally exposes request_sandbox_boundary:

Storage applies an approved expansion to any managed profile, including read-only:

I reproduced approval of a network expansion on a Deep Research session. The resulting profile was still named read-only, but its network state was enabled.

The Deep Research surface should omit mutation tools and the boundary-request tool, and its internal read-only boundary must not be expandable into write or process-network authority.

5. [P2] Child boundary persistence is fixed, but filesystem execution does not fully inherit Bypass or External

The parent boundary is now persisted into the child correctly. However, the child header still uses the Agent definition’s legacy permission mode, and the filesystem worker only consumes managed boundaries:

For an inherited Bypass or External boundary, filesystem execution falls back to the child definition’s legacy profile. The same child can therefore run Bash according to the inherited boundary while Read/Write/Edit follow a different authority.

Boundary handling in the filesystem client should be exhaustive: managed, bypass, and external must each have explicit semantics, with no fallback to permissionMode.

6. [P2] Non-interactive Auto can still return exit code 0 after an unresolved boundary failure

maka run does not register the boundary-request tool. It marks the command as failed only after receiving a sandbox_boundary_request event:

A filesystem tool can instead return sandbox_boundary_required as an ordinary structured tool failure. If the model then produces a normal final answer explaining that it could not complete the task, the invocation remains completed and maka run returns 0.

An unresolved boundary requirement must become a terminal non-interactive invocation outcome, independently of whether a request event was published.

7. [P2] A session bundle does not read its header and boundary from one SQLite snapshot

The bundle exporter writes selected session metadata and the selected boundary through two independent exporter calls:

A concurrent Auto/Bypass transition between those reads can export a header from one revision and a boundary from another. Import then accepts both as the new genesis state.

Storage should provide one read transaction that returns an immutable portable { header, boundary } snapshot before either transfer file is written.

Implementation-quality concern

The Runtime public boundary contract still permits the authoritative reader to be absent:

All current first-party production call sites appear to provide the reader, so I am not treating this as a separate exploit. However, the public API still silently reconstructs authority from header.permissionMode, which preserves the dual-authority fallback that this PR claims to remove.

The boundary reader should be required. Interactive expansion support can be represented separately as an explicit enabled/disabled capability.

There are also several source-regex and collaborator-call tests that lock implementation shape rather than public behavior. I do not use those as the primary basis for this review, but they should be replaced with behavioral coverage while these paths are being corrected.

Validation

On final head d481739:

  • npm run build:test passed.
  • Linux sandbox smoke passed, 7/7.
  • Linux filesystem-worker smoke passed, 2/2.
  • SQLite session metadata tests passed, 30/30.
  • git diff --check a454b9a..d481739 passed.
  • GitHub typecheck, test, and e2e checks are green.

The green suite validates the supported sandbox path, but it does not cover the fail-open worker-unavailable path or the cross-surface inconsistencies above.

简体中文

审查结论

Request changes。

我基于 #1564 的已接受契约与本 PR body 声明的保证,对最终 head d481739 进行了审查。SQLite transition、Prompt settlement、--yolo 保护、boundary 持久化和 Linux sandbox 测试都是有价值的改进,但若干执行路径仍违反这次改动的核心不变量。

最新 rebase 与最终的 d481739 cleanup commit 没有改变下述 sandbox 语义。

本次审查采用的契约

已接受的 #1564 契约要求:

  • 每个 session 只有一个 authoritative、session-scoped ExecutionBoundary
  • enforcement 不可用时,managed execution 必须 fail closed;
  • process network 与 filesystem boundary 必须具有精确且可达的 expansion 流程;
  • External execution 只能在存在显式 external isolation owner 时使用;
  • Deep Research 必须保持内部 managed read-only;
  • 子 Agent 必须继承父 session boundary;
  • 非交互 Auto 遇到无法解决且不可避免的 boundary requirement 时必须非零退出;
  • session bundle 必须恢复 authoritative boundary。

Issue 讨论中关于默认启用 network、自动退化到 Bypass,以及把用户给出的路径视为隐式授权的替代提案已经被明确拒绝。以下 findings 以已接受的 issue body 为准,不采用这些替代提案。

阻塞问题

1. [P1] Filesystem worker 不可用时,managed filesystem tool 会 fail open

当平台无法提供内置 worker sandbox 时,Desktop 与 CLI 会有条件地省略 filesystem worker。buildBuiltinTools 随后退回 createLocalWorkspaceExecutor,导致 Write/Edit/Read 在 host 上执行,而不是拒绝 managed execution。

相关路径:

我在最终 head 上完成了复现:未提供 worker 时,explore/read-only boundary 下的 Write 成功创建了文件。

Managed execution 必须在进入 host executor 前返回 enforcement-unavailable failure。Host 路径只能由显式 Bypass 或 harness-owned External boundary 访问。

2. [P1] 首次 process-network expansion 没有合法的请求路径

Auto 默认限制 process network,但 Bash 没有声明 network requirement 的字段。命令被拒绝时只返回可能的 sandbox-denial signal,不包含 sandbox_boundary_required 或具体 network expansion:

Runtime guidance 同时要求 Agent 不得推断 expansion,且只有在工具返回精确 expansion 后才能请求:

我复现了带有 sandboxType: linuxEPERM network denial,但 failure 中没有 required expansion。因此 npm installgit pullcurl 等命令无法进入 #1564 要求的 session-level network approval 流程。

这里需要一个声明式且本身不授予权限的 process-network requirement,或同样可靠的 backend signal,以便在不解析 command text 的情况下生成精确 expansion。

3. [P1] External session 可以在 Desktop/TUI 中以 Auto 恢复,同时 Bash 不受 Maka sandbox 约束

导入的 session bundle 可以恢复 External boundary。Bash 将 Bypass 和 External 都视为跳过 Maka sandbox 的指令:

Desktop 把所有非 Bypass boundary 映射为 Auto,而 TUI session switching 继续投影 legacy permissionMode

maka run 已经正确拒绝该 resume 路径,但普通 Desktop 与交互式 TUI 没有拒绝。最终结果是:一个标记为 Auto 的 session 在缺少原定 external harness 的情况下执行 host Bash。

除非注入显式 external-isolation owner,否则普通交互式 surface 必须拒绝 External session。External 也绝不能显示为 Auto。

其他正确性缺口

4. [P2] Deep Research 可以请求并获得 write 或 network expansion

Deep Research 从 managed read-only profile 开始,但 Desktop 仍包含完整 builtin surface,并无条件暴露 request_sandbox_boundary

Storage 会把已批准的 expansion 应用到任意 managed profile,包括 read-only:

我复现了 Deep Research session 的 network expansion approval。结果 profile 仍名为 read-only,但 network state 已变为 enabled

Deep Research surface 应移除 mutation tool 与 boundary-request tool,其内部 read-only boundary 也不应扩张为 write 或 process-network authority。

5. [P2] Child boundary 已正确持久化,但 filesystem execution 没有完整继承 Bypass 或 External

Parent boundary 现在已经能正确持久化到 child。但 child header 仍使用 Agent definition 的 legacy permission mode,而 filesystem worker 只消费 managed boundary:

对于继承的 Bypass 或 External boundary,filesystem execution 会退回 child definition 的 legacy profile。同一个 child 因而可能让 Bash 遵循 inherited boundary,却让 Read/Write/Edit 遵循另一套 authority。

Filesystem client 应穷举处理 managed、bypass 与 external,不能再退回 permissionMode

6. [P2] 非交互 Auto 在 boundary failure 未解决后仍可能返回退出码 0

maka run 不注册 boundary-request tool。它只有在收到 sandbox_boundary_request event 后才把命令标记为失败:

Filesystem tool 也可能只把 sandbox_boundary_required 作为普通 structured tool failure 返回。如果 model 随后正常输出无法完成任务的说明,invocation 仍是 completed,maka run 最终返回 0。

未解决的 boundary requirement 必须成为非交互 invocation 的 terminal failure,不能依赖是否发布了 request event。

7. [P2] Session bundle 没有从同一个 SQLite snapshot 读取 header 与 boundary

Bundle exporter 通过两个独立 exporter 调用写入 selected session metadata 和 selected boundary:

如果两次读取之间发生并发 Auto/Bypass transition,export 可能得到一个 revision 的 header 和另一个 revision 的 boundary。Import 随后会把两者共同接受为新的 genesis state。

Storage 应在一个 read transaction 内返回不可变的 portable { header, boundary } snapshot,然后再写两个 transfer file。

实现质量问题

Runtime 的 public boundary contract 仍允许 authoritative reader 缺失:

当前 first-party production call site 看起来都提供了 reader,因此我没有把它作为独立 exploit。但 public API 仍会从 header.permissionMode 静默重建 authority,保留了本 PR 声称要删除的 dual-authority fallback。

Boundary reader 应成为 required dependency。Interactive expansion support 可以单独表示为显式的 enabled/disabled capability。

此外,当前还有若干 source-regex 与 collaborator-call test,它们锁定 implementation shape,而不是验证 public behavior。我没有把这些测试作为本次 Request changes 的主要依据,但在修复上述路径时应将其替换为 behavioral coverage。

验证

最终 head d481739

  • npm run build:test 通过。
  • Linux sandbox smoke 通过,7/7。
  • Linux filesystem-worker smoke 通过,2/2。
  • SQLite session metadata tests 通过,30/30。
  • git diff --check a454b9a..d481739 通过。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

当前绿色测试覆盖了受支持的 sandbox 路径,但没有覆盖上述 worker-unavailable fail-open 路径与跨 surface 不一致。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

Thank you for the detailed review. I reproduced the reported paths and updated the PR to head 7abc0b9de.

All seven findings have now been addressed:

  1. Managed filesystem fail-open — fixed in 48ca2f864. Managed Read/Write/Edit now fail closed when the filesystem sandbox is unavailable; the host executor is reserved for explicit Bypass or External authority.

  2. Unreachable first process-network expansion — fixed in 05585da92. Bash now declares a non-authorizing sandbox capability requirement, allowing the runtime to produce an exact network expansion without parsing command text.

  3. External sessions on local interactive surfaces — fixed across 7823ab5d4 and 7abc0b9de. TUI rejects resuming External sessions without their owning harness. Desktop may display imported External history, but it is non-interactive: the composer and permission-mode controls are unavailable, permission commands are omitted, and External is never presented as Auto. Boundary loading also fails closed so Auto cannot flash before the authority snapshot arrives.

  4. Deep Research expansion and mutation surface — fixed in 3d347d48d, with the read-only tool-surface contract strengthened in c384056c5. Deep Research no longer receives mutation or boundary-expansion tools.

  5. Child boundary inheritance — fixed in 62581d26f and f04db4bec. Child admission and filesystem execution now use the inherited ExecutionBoundary explicitly, with managed, bypass, and external paths handled deliberately and child tool surfaces defined by explicit allowlists.

  6. Non-interactive unresolved boundary returning success — fixed in 093d9fad2. maka run now exits nonzero for an unresolved boundary requirement whether it appears as a request event or a structured tool failure.

  7. Non-atomic bundle boundary snapshot — fixed in 1715039e9. Session header and execution boundary are now read from one storage transaction before transfer files are written.

The implementation-quality concern was also addressed. 581f73ec5 removed the legacy boundary fallback, and fa4314bfe now makes readExecutionBoundary a required Runtime/AiSdkBackend dependency. Missing authority is rejected instead of reconstructing External or managed authority from legacy permissionMode. Tests that intentionally exercise an externally isolated raw runtime now opt into that authority explicitly.

For the Desktop follow-up, 7abc0b9de adds behavioral coverage for managed, bypass, loading, and external boundary projections, plus command-surface coverage. I did not broaden this follow-up into a rewrite of unrelated source-contract tests.

Validation on 7abc0b9de:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • full npm run test:dist across all workspaces
  • Runtime: 2,697 passed, 9 skipped, 0 failed
  • Desktop: 2,968 passed, 0 failed
  • GitHub typecheck, test, and e2e: all green

Could you please re-review the current head?

简体中文

感谢这次详细审查。我复现了报告中的路径,并已把 PR 更新到 head 7abc0b9de

七项 findings 现已全部处理:

  1. Managed filesystem fail-open — 已在 48ca2f864 修复。Filesystem sandbox 不可用时,managed Read/Write/Edit 现在会 fail closed;host executor 只供显式 Bypass 或 External authority 使用。

  2. 首次 process-network expansion 不可达 — 已在 05585da92 修复。Bash 现在声明一个本身不授予权限的 sandbox capability requirement,使 Runtime 无需解析 command text 就能生成精确的 network expansion。

  3. External session 被本地交互 surface 执行 — 已通过 7823ab5d47abc0b9de 修复。TUI 会拒绝在缺少所属 harness 时恢复 External session。Desktop 可以查看导入的 External 历史,但保持不可交互:composer 和 permission-mode control 不可用,permission command 不会出现,External 也绝不会显示为 Auto。Boundary 加载阶段同样 fail closed,避免 authority snapshot 到达前短暂显示 Auto。

  4. Deep Research expansion 与 mutation surface — 已在 3d347d48d 修复,并由 c384056c5 加强 read-only tool-surface 契约。Deep Research 不再获得 mutation 或 boundary-expansion tool。

  5. Child boundary inheritance — 已在 62581d26ff04db4bec 修复。Child admission 与 filesystem execution 现在显式使用继承的 ExecutionBoundary,managed、bypass、external 均有明确语义,child tool surface 由显式 allowlist 定义。

  6. 非交互 unresolved boundary 错误返回成功 — 已在 093d9fad2 修复。无论 boundary requirement 来自 request event 还是 structured tool failure,maka run 都会非零退出。

  7. Bundle boundary snapshot 非原子 — 已在 1715039e9 修复。Session header 与 execution boundary 现在会在同一个 storage transaction 中读取,然后才写入 transfer files。

实现质量问题也已处理。581f73ec5 删除了 legacy boundary fallback,fa4314bfe 则将 readExecutionBoundary 设为 Runtime/AiSdkBackend 的 required dependency。缺少 authority 时现在会直接拒绝,不再从 legacy permissionMode 重建 External 或 managed authority。需要直接测试 externally isolated raw runtime 的测试也会显式选择该 authority。

Desktop follow-up 7abc0b9de 增加了 managed、bypass、loading、external boundary projection 的行为测试,以及 command surface 测试。此次 follow-up 没有盲目扩大到重写无关的 source-contract test。

7abc0b9de 上的验证结果:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • 全 workspace npm run test:dist
  • Runtime:2,697 通过,9 跳过,0 失败
  • Desktop:2,968 通过,0 失败
  • GitHub typecheckteste2e:全部绿色

能否请你基于当前 head 再 review 一次?

@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed head 7abc0b9de and reran the relevant targeted tests.

Re-review outcome

The following findings are resolved:

  1. Managed filesystem execution now fails closed when the worker sandbox is unavailable.
  2. Bash can declare an exact process-network boundary requirement without parsing command text.
  3. External sessions are rejected by TUI and remain non-interactive in Desktop.
  4. Deep Research now receives a read-only tool surface without boundary-expansion tools.
  5. Non-interactive unresolved boundary failures now produce a nonzero exit.
  6. Session bundle metadata and boundary are read from one SQLite authority snapshot.
  7. readExecutionBoundary is now required, and the Runtime legacy boundary fallback has been removed.

One finding remains open.

[P2] Child filesystem execution still does not inherit Bypass or External semantics

The parent ExecutionBoundary is persisted into the child, but ordinary child creation still stores the Agent definition’s legacy permission mode:

The filesystem worker only consumes the supplied boundary when its kind is managed. For Bypass or External, it falls back to permissionProfile or the child’s legacy mode:

Bash, by contrast, explicitly skips the Maka sandbox for the inherited Bypass or External boundary:

I reproduced the remaining mismatch on 7abc0b9de by executing an outside-workspace filesystem write with a Bypass or External boundary and a legacy child mode:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

The worker process was never launched. The operation was rejected by the legacy profile selected before sandbox execution.

The explicit child tool allowlists correctly constrain which tools a child receives, but they do not make those tools use the inherited boundary. An implementation child can therefore run Bash according to inherited Bypass/External authority while Read/Write/Edit continue to use a different filesystem authority.

Please make filesystem authority selection exhaustive over all ExecutionBoundary kinds. Once an authoritative boundary is supplied, the filesystem client should not fall back to permissionMode. A regression test should exercise a real inherited child Bypass/External boundary through the builtin filesystem tool path.

Validation

On 7abc0b9de:

  • npm run build:test passed.
  • Runtime targeted tests passed, 100/100.
  • CLI targeted tests passed, 72/72.
  • Storage targeted tests passed, 60/60.
  • Desktop targeted tests passed, 13/13.
  • Linux sandbox and filesystem-worker smoke tests passed, 9/9.
  • GitHub typecheck, test, and e2e checks are green.

I did not find another blocker in the follow-up scope. The previous findings can remain resolved; only the child filesystem-boundary finding remains open.

简体中文

@Astro-Han

我基于 head 7abc0b9de 完成了 re-review,并重新运行了相关定向测试。

Re-review 结论

以下 findings 已确认 resolved:

  1. Filesystem worker sandbox 不可用时,managed filesystem execution 现在会 fail closed。
  2. Bash 现在可以在不解析 command text 的情况下声明精确的 process-network boundary requirement。
  3. TUI 会拒绝 External session,Desktop 中的 External session 保持不可交互。
  4. Deep Research 现在只获得 read-only tool surface,不再获得 boundary-expansion tool。
  5. 非交互 unresolved boundary failure 现在会产生非零退出码。
  6. Session bundle metadata 与 boundary 现在从同一个 SQLite authority snapshot 读取。
  7. readExecutionBoundary 已成为 required dependency,Runtime legacy boundary fallback 也已删除。

仍有一项 finding 未关闭。

[P2] Child filesystem execution 仍未继承 Bypass 或 External 语义

Parent ExecutionBoundary 已经持久化到 child,但普通 child 创建仍会把 Agent definition 的 legacy permission mode 写入 header:

Filesystem worker 只有在 boundary kind 为 managed 时才消费传入的 boundary。对于 Bypass 或 External,它仍会退回 permissionProfile 或 child legacy mode

Bash 则会针对 inherited Bypass 或 External boundary 显式跳过 Maka sandbox:

我在 7abc0b9de 上使用 Bypass/External boundary 与 legacy child mode 执行 workspace 外 filesystem write,仍能复现该不一致:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

Worker process 没有启动。操作在 sandbox execution 之前就被 legacy profile 拒绝。

显式 child tool allowlist 正确限制了 child 可以获得哪些工具,但没有让这些工具使用 inherited boundary。因此 implementation child 仍可能让 Bash 遵循 inherited Bypass/External authority,而 Read/Write/Edit 使用另一套 filesystem authority。

请对所有 ExecutionBoundary kind 做穷举的 filesystem authority selection。一旦提供 authoritative boundary,filesystem client 就不应再退回 permissionMode。Regression test 应通过 builtin filesystem tool 路径,覆盖真实 inherited child Bypass/External boundary。

验证

7abc0b9de 上:

  • npm run build:test 通过。
  • Runtime 定向测试通过,100/100。
  • CLI 定向测试通过,72/72。
  • Storage 定向测试通过,60/60。
  • Desktop 定向测试通过,13/13。
  • Linux sandbox 与 filesystem-worker smoke tests 通过,9/9。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

在本次 follow-up 范围内没有发现其他 blocker。此前其余 findings 可以保持 resolved;目前只剩 child filesystem-boundary finding 未关闭。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

@M4n5ter

Thank you. I addressed the remaining child filesystem-boundary finding. The current head is 3f5443b7f.

The root cause was that the filesystem worker boundary was not explicit enough: it is a managed-only enforcement path, while Bypass and External execution must never be projected into it or reconstructed from a legacy child mode.

The fix now covers both layers:

  1. bf370bd1a makes builtin filesystem dispatch depend on the authoritative ExecutionBoundary before any worker call:

    • Managed routes through the filesystem worker and fails closed when enforcement is unavailable.
    • Bypass and External route through the executor supplied by their owning surface.
    • Neither path consults the child’s legacy permissionMode.
  2. 3f5443b7f closes the lower-level API ambiguity:

    • FilesystemWorkerClient now rejects any supplied Bypass or External boundary.
    • Once an authoritative boundary is supplied, the client can no longer fall back to permissionProfile or mode.

The regression coverage reproduces the inherited-child shape directly through builtin Write: legacy permissionMode: explore combined with authoritative Bypass and External boundaries. Both use the non-worker path, while direct attempts to pass either boundary into FilesystemWorkerClient fail before validation or process launch.

Fresh-eye validation also added bounded hardening around boundary narrowing, stale linked-child resume, External admission, descendant non-interactive failures, exact-write grant isolation, authority round-trips, and prompt response races. These remain separate atomic commits and do not reintroduce the generic permission or legacy mode paths.

Validation on 3f5443b7f:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • full serial npm run test:dist across all workspaces
  • Runtime after the final worker-client change: 2,706 passed, 9 skipped, 0 failed
  • Runtime Host: 303 passed, 0 failed
  • Desktop: 2,970 passed, 0 failed
  • targeted builtin filesystem-worker and client tests: 20 passed, 0 failed

Could you please re-review the current head?

简体中文

@M4n5ter

感谢。我已经处理了最后一项 child filesystem-boundary finding。当前 head 为 3f5443b7f

根因是 filesystem worker 的职责边界不够明确:它只应是 Managed 的 enforcement path;Bypass 与 External execution 既不应进入 worker,也不能从 legacy child mode 重建权限。

修复现在覆盖两层:

  1. bf370bd1a 让 builtin filesystem dispatch 在调用 worker 前直接依据权威 ExecutionBoundary 路由:

    • Managed 必须走 filesystem worker;enforcement 不可用时 fail closed。
    • Bypass 与 External 走所属 surface 注入的 executor。
    • 两条路径都不再查询 child 的 legacy permissionMode
  2. 3f5443b7f 关闭了底层 API 的歧义:

    • FilesystemWorkerClient 现在会拒绝任何传入的 Bypass 或 External boundary。
    • 一旦提供权威 boundary,client 就不能再回退到 permissionProfilemode

回归测试通过 builtin Write 直接复现 inherited-child 的组合:legacy permissionMode: explore 加权威 Bypass/External boundary。两者都会走非 worker 路径;如果直接把任一 boundary 传给 FilesystemWorkerClient,则会在 validation 或进程启动前 fail closed。

Fresh-eye 验证还以有限范围补强了 boundary narrowing、stale linked-child resume、External admission、非交互后代失败、exact-write grant 隔离、authority round-trip 和 prompt response race。它们都保留为独立原子提交,也没有重新引入 generic permission 或 legacy mode 路径。

3f5443b7f 上的验证:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • 全 workspace 串行 npm run test:dist
  • 最后一项 worker-client 修复后的 Runtime:2,706 通过,9 跳过,0 失败
  • Runtime Host:303 通过,0 失败
  • Desktop:2,970 通过,0 失败
  • builtin filesystem-worker 与 client 定向测试:20 通过,0 失败

能否请你基于当前 head 再 review 一次?

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 3f5443b to c4a7062CompareJuly 29, 2026 08:43
@M4n5ter

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed the latest head c4a7062c9. The rebase preserved the 13 follow-up patches; the new final commit only reconciles an AI-provider test fixture.

Re-review outcome

The previously reported child filesystem-boundary mismatch is resolved. Builtin filesystem dispatch now follows the authoritative boundary, and the targeted builtin/client tests pass 20/20.

Request changes. Three correctness blockers and four additional gaps remain.

Blocking correctness findings

1. [P1] A missing exact-write grant still blocks unrelated Bash commands on real Linux

prepareLinuxBashExactWriteTargets now prepares only exact paths declared by the current required_boundary, but the complete durable profile is still passed to bubblewrap:

Every exact-write entry in that profile remains a bind-mount source. If an undeclared exact target or its parent no longer exists, bubblewrap fails before executing the command.

I reproduced this with an unrelated command:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

The added unit test does not catch this because it uses a fake available sandbox manager and never executes the generated bubblewrap command.

This is also the current required-CI failure: Linux sandbox smoke fails 6/7 with the same missing-source error.

The per-invocation Linux mount plan should omit absent undeclared exact entries while safely preparing an exact target that the current invocation declares. This needs a real bubblewrap smoke test for both cases.

2. [P1] Legacy permissionCeiling prevents default Auto sessions from creating executable children

A normal new session still defaults to legacy permissionMode: ask, while Web Research and Implementation definitions use execute. Child creation therefore stores permissionMode: execute with permissionCeiling: ask:

Current-header normalization still treats that legacy ceiling as live authority:

I reproduced the resulting persistence failure:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

This happens before the inherited ExecutionBoundary can govern the child. permissionCeiling should be limited to legacy decoding/migration, not written or enforced for current child sessions. A SQLite-backed child-creation behavior test should cover an Implementation child spawned from the default Auto session.

3. [P1] Narrowing a parent boundary does not revoke descendant background processes

A child Bash run is registered under the child session ID:

The parent boundary transition terminates only the parent session’s shell runs:

A foreground child can start background Bash, return, and leave the process alive. The parent can then narrow from Bypass to Auto, or Auto to Explore, while that descendant process continues with its old authority. The stale-child resume guard prevents a future resume but does not revoke already-live processes.

Boundary narrowing needs lineage-wide revocation of descendant shell runs and backend generations before committing the transition, with regression coverage for a completed child turn that leaves background Bash running.

Additional correctness gap

4. [P2] An Explore-origin session cannot return from Bypass to Auto

For an Explore-origin session, genesis is the managed read-only profile. After switching to Bypass, restoration searches only for a previous non-read-only managed profile:

I reproduced:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

The transition should be total for supported UI states. If Explore sessions may enter Bypass, a missing Auto history should restore the canonical Auto genesis profile. If they must remain read-only, Bypass should be rejected and hidden before the transition.

Maintainability findings

5. [P2] Sandbox containment semantics are duplicated inside SessionManager

The follow-up adds approximately 70 lines of profile, access, path, deny, and protected-metadata containment logic to an already very large runtime coordinator:

Boundary containment is a core contract and will drift if Runtime owns a second implementation. Please expose one canonical Core helper and keep SessionManager as a caller.

6. [P2] The public legacy snapshot exporter can silently omit authoritative boundaries

exportLegacySessionTreeSnapshot accepts required records but an optional boundary map, and silently skips the boundary transfer file when an entry is absent:

The production wrapper currently supplies the map, but the exported public helper still permits a boundary-less session export. Its input should carry paired authority snapshots and require one boundary for every selected session.

7. [P2] The new External-admission regression test verifies source layout, not behavior

The test reads main.ts and uses regular expressions to require a specific helper name, handler layout, and call text:

It can pass without proving that IPC admission rejects External execution, and harmless refactoring can break it. Please replace it with an IPC behavior harness covering compact, resume, regenerate, and plan approval, asserting that runtime execution is not reached.

Validation

On c4a7062c9:

  • npm run build:test passed.
  • Child filesystem builtin/client tests passed, 20/20.
  • The default-Auto executable-child header was rejected in a direct current-header normalization reproduction.
  • Explore → Bypass → Auto failed in an in-memory SQLite reproduction.
  • An unrelated true command failed under real bubblewrap when the profile contained a missing exact-write grant.
  • Local required Linux sandbox smoke failed, 6/7.
  • GitHub typecheck and e2e are green; test is red on the same Linux smoke failure.
简体中文

@Astro-Han

我基于最新 head c4a7062c9 完成了 re-review。Rebase 保留了 13 个 follow-up patch;新增的最后一个 commit 只调整了 AI provider test fixture。

Re-review 结论

此前未关闭的 child filesystem-boundary 不一致已经解决。Builtin filesystem dispatch 现在遵循 authoritative boundary,相关 builtin/client 定向测试 20/20 通过。

仍需 Request changes。目前还有三项 correctness blocker 和四项其它问题。

阻塞性 correctness findings

1. [P1] 失效的 exact-write grant 在真实 Linux 上仍会阻断无关 Bash 命令

prepareLinuxBashExactWriteTargets 现在只准备当前 required_boundary 声明的 exact path,但完整的持久化 profile 仍会传给 bubblewrap:

Profile 中的每个 exact-write entry 仍然会成为 bind-mount source。如果一个未被本次调用声明的 exact target 或其 parent 已不存在,bubblewrap 会在执行 command 前失败。

我使用一条完全无关的命令复现了该问题:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

新增的 unit test 使用 fake available sandbox manager,并未执行生成的 bubblewrap command,因此无法覆盖真实行为。

这也是当前 required CI 的失败原因:Linux sandbox smoke 以相同的 missing-source 错误失败,结果为 6/7。

Linux 每次调用的 mount plan 应忽略不存在且未被当前调用声明的 exact entry;如果当前调用显式声明 exact target,则应安全地准备它。两条路径都需要真实 bubblewrap smoke coverage。

2. [P1] Legacy permissionCeiling 会阻止默认 Auto session 创建 executable child

普通新 session 的 legacy permissionMode 默认仍为 ask,而 Web Research 与 Implementation definition 使用 execute。Child 创建因此会同时写入 permissionMode: executepermissionCeiling: ask

Current-header normalization 仍把 legacy ceiling 当作 live authority:

我复现到的持久化结果为:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

失败发生在 inherited ExecutionBoundary 能够治理 child 之前。permissionCeiling 应仅用于 legacy decode/migration,不应继续写入或验证 current child session。需要通过真实 SQLite child-creation 行为测试覆盖默认 Auto session 创建 Implementation child 的路径。

3. [P1] 收窄 parent boundary 不会撤销 descendant background process

Child Bash run 会记录在 child session ID 下:

Parent boundary transition 只终止 parent session 自身的 shell run:

Foreground child 可以启动 background Bash 后返回,但让进程继续运行。随后 parent 可以从 Bypass 收窄到 Auto,或从 Auto 收窄到 Explore;descendant process 仍保留旧 authority。Stale-child resume guard 只能阻止未来 resume,无法撤销已经存活的进程。

Boundary narrowing 应在提交 transition 前,按 session lineage 撤销所有 descendant shell run 与 backend generation,并增加“child turn 已结束但 background Bash 仍在运行”的 regression coverage。

其它 correctness gap

4. [P2] Explore-origin session 无法从 Bypass 返回 Auto

Explore-origin session 的 genesis 是 managed read-only profile。切换到 Bypass 后,恢复逻辑只查找历史中的 non-read-only managed profile:

我的复现结果为:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

所有受支持的 UI 状态都应拥有完整 transition。如果 Explore session 可以进入 Bypass,那么缺少 Auto history 时应恢复 canonical Auto genesis profile;如果它必须始终保持 read-only,则应在 transition 之前拒绝并隐藏 Bypass。

可维护性 findings

5. [P2] Sandbox containment 语义被重复实现在 SessionManager

Follow-up 在已经非常庞大的 runtime coordinator 中增加了约 70 行 profile、access、path、deny 与 protected-metadata containment 逻辑:

Boundary containment 属于 Core contract。Runtime 保留第二套实现会产生语义漂移。建议在 Core 暴露一个 canonical helper,让 SessionManager 只负责调用。

6. [P2] Public legacy snapshot exporter 可以静默遗漏 authoritative boundary

exportLegacySessionTreeSnapshot 要求提供 records,却把 boundary map 设为 optional;如果某个 entry 不存在,就会静默跳过 boundary transfer file:

当前 production wrapper 的确提供了 map,但导出的 public helper 仍允许生成缺失 boundary 的 session export。其输入应改为成对的 authority snapshot,并要求每个被选择的 session 都有 boundary。

7. [P2] 新增的 External-admission regression test 验证 source layout,而不是行为

该测试读取 main.ts,再用正则要求特定 helper 名称、handler 布局和调用文本:

它无法证明 IPC admission 确实会拒绝 External execution,同时正常重构也会使测试破裂。应替换为 IPC behavior harness,覆盖 compact、resume、regenerate 与 plan approval,并断言 runtime execution 未被调用。

验证

c4a7062c9 上:

  • npm run build:test 通过。
  • Child filesystem builtin/client tests 20/20 通过。
  • Direct current-header normalization 复现到默认 Auto executable-child header 被拒绝。
  • In-memory SQLite 复现到 Explore → Bypass → Auto 失败。
  • 在真实 bubblewrap 下,profile 含有失效 exact-write grant 时,无关的 true command 仍会失败。
  • 本地 required Linux sandbox smoke 失败,6/7。
  • GitHub typechecke2e 通过;test 因相同 Linux smoke 错误失败。

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch 2 times, most recently from 4c0af93 to d01db12CompareJuly 29, 2026 10:43
@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 58fdec7 to 6b82f24CompareJuly 29, 2026 11:52
@Astro-Han
Astro-Han merged commit 0fe34a7 into mainJul 29, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/1564-session-sandbox-boundary branch July 29, 2026 12:00
Astro-Han added a commit that referenced this pull request Jul 29, 2026
#1581 replaced tool permissions with session sandbox boundaries and removed
`PermissionEngine` from `@maka/runtime`, but left this test importing it and
passing a `permissionEngine` dependency that the session-stream deps type no
longer has. `main` has been red since: `tsc -p tsconfig.main.json` fails with
TS2305, which takes `build:main` down and with it the typecheck, test, and e2e
jobs on every branch.
Nothing in production takes a `permissionEngine` any more, and the test's
subject is usage readiness, so the import and the dependency go. No behavioural
change and no replacement needed.
Sign up for freeto 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.

feat: replace per-tool approvals with sandbox boundaries

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: replace tool permissions with session sandbox boundaries - #1581

Merged
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary
Jul 29, 2026
Merged

feat: replace tool permissions with session sandbox boundaries#1581
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace additional permissions, one-call sandbox escalation, and the live generic tool-approval path with one revisioned, session-scoped ExecutionBoundary authority.
  • Persist genesis boundaries, immutable expansion requests, and applied revisions in the SQLite session metadata store. Approval and boundary advancement commit atomically; stale, duplicate, and concurrently decided requests settle deterministically.
  • Keep the expansion schema no broader than the product needs today: exact/subtree filesystem read/write entries plus session network enablement. Tools report exact sandbox_boundary_required deltas or requires_bypass; Bash diagnostics never parse commands or invent authority.
  • Wire the boundary lifecycle end to end through core, storage, runtime, Runtime Host, session bundles, Desktop/shared UI, TUI, headless/Harbor, and non-interactive CLI. Desktop and TUI expose Auto/Bypass, boundary prompts take over the composer, and Bypass requires an explicit second confirmation.
  • Remove the superseded PermissionEngine matrix, grant ingress, generic permission prompts, and legacy live escalation executors in the same PR so no dual-authority intermediate state ships. Historical codecs and settled audit history remain readable; OS Permission Center behavior is unchanged.

Closes#1564

Verification

  • npm run build — passed across all workspaces.
  • npm run test:dist — passed the complete repository suite with the workspace runner in serial mode, including script contracts (176/176), storage (733 passed, 1 skipped), Runtime (2675 passed, 9 skipped), Runtime Host (212/212), and Desktop (2964/2964).
  • npm run format:check — passed, 1221 files checked.
  • npm run lint — passed, 2304 files checked.
  • npm run typecheck — passed across all workspaces.
  • node --test packages/runtime/dist/__tests__/macos-seatbelt-smoke.test.js packages/runtime/dist/__tests__/filesystem-worker-smoke.test.js — passed (9/9), including exact outside-path expansion and restricted network behavior.
  • npm run e2e -w @maka/desktop -- e2e/sandbox-boundary-takeover.spec.ts — passed (1/1), covering the visible Desktop composer takeover and approval journey.
  • The all-workspace parallel npm test command intermittently exhausted a Runtime Host test's local timing window under machine load. That package passed independently (212/212), and the complete serial repository run above passed; this PR does not broaden into unrelated test-harness timing changes.

Migration and breaking change

  • Legacy ask and execute sessions enter the managed workspace-write boundary; explore enters managed read-only; bypass remains bypass. First access durably records revision 0 without rewriting settled historical records.
  • Pending legacy permission interactions close with host_restarted during recovery because their live continuation authority cannot survive the upgrade.
  • Interactive surfaces now expose only Auto and Bypass. Removed permission modes and per-tool grant flags fail during CLI argument validation.
  • maka run defaults to Auto and cannot interactively expand a boundary, so it fails closed when expansion is requested. Only explicit --yolo creates or resumes a bypass session.
  • Headless/Harbor sessions explicitly use the external boundary; imports and exports preserve the authoritative boundary even though the SQLite database itself is not bundled.

Review focus

  • The SQLite transaction boundary around request settlement and boundary revision advancement, including cross-connection races.
  • The runtime continuation/publication barrier when a sandbox boundary or user question is pending, including durable denial when a turn closes.
  • The cross-surface fail-closed behavior for ordinary expansion requests versus requires_bypass.
  • The branch contains 105 small, reversible commits ordered from contracts and storage through runtime, surfaces, legacy-path removal, and regression coverage.

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 6f15924 to d481739CompareJuly 29, 2026 01:50
@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

Review outcome

Request changes.

I reviewed the final PR head d481739 against the accepted contract in #1564 and the guarantees stated in this PR body. The SQLite transition work, prompt settlement, --yolo protection, boundary persistence, and Linux sandbox tests are meaningful improvements, but several execution paths still violate the central invariants of this change.

The latest rebase and the final d481739 cleanup commit do not change the sandbox semantics described below.

Contract used for this review

The accepted #1564 contract requires:

  • one authoritative, session-scoped ExecutionBoundary;
  • managed execution to fail closed when enforcement is unavailable;
  • an exact, reachable expansion flow for process network and filesystem boundaries;
  • External execution only when an explicit external isolation owner exists;
  • Deep Research to remain internally managed and read-only;
  • child Agents to inherit the parent boundary;
  • non-interactive Auto to exit nonzero when an unavoidable boundary requirement cannot be resolved; and
  • session bundles to restore the authoritative boundary.

The alternative proposals to enable network by default, automatically fall through to Bypass, or treat user-provided paths as implicit authorization were explicitly rejected in the issue discussion. These findings are evaluated against the accepted issue body, not those alternatives.

Blocking findings

1. [P1] Managed filesystem tools fail open when the filesystem worker is unavailable

Desktop and CLI conditionally omit the filesystem worker when the platform cannot provide the built-in worker sandbox. buildBuiltinTools then falls back to createLocalWorkspaceExecutor, and Write/Edit/Read execute on the host instead of rejecting managed execution.

Relevant paths:

I reproduced this on the final head: a Write call under an explore/read-only boundary successfully created a file when no worker was supplied.

Managed execution must return an enforcement-unavailable failure before reaching the host executor. The host path should only be reachable for an explicit Bypass or harness-owned External boundary.

2. [P1] The first process-network expansion has no valid request path

Auto starts with restricted process network, but Bash has no declarative network requirement. A denied command returns only a likely sandbox-denial signal, without sandbox_boundary_required or a concrete network expansion:

Runtime guidance simultaneously states that the Agent must not infer an expansion and may request one only after a tool returns an exact expansion:

I reproduced an EPERM network denial with sandboxType: linux; the failure contained no required expansion. Commands such as npm install, git pull, and curl therefore cannot reach the session-level network approval flow required by #1564.

This needs a declarative, non-authorizing process-network requirement or an equally reliable backend signal that can produce the exact expansion without parsing command text.

3. [P1] An External session can resume in Desktop/TUI as Auto while Bash runs without a Maka sandbox

Imported session bundles can restore an External boundary. Bash treats both Bypass and External as instructions to skip the Maka sandbox:

Desktop maps every non-Bypass boundary to Auto, while TUI session switching continues to project the legacy permissionMode:

maka run correctly rejects this resume path, but ordinary Desktop and interactive TUI do not. The result is an Auto-labelled session executing host Bash without the external harness that supposedly owns isolation.

External sessions must be rejected by ordinary interactive surfaces unless an explicit external-isolation owner is injected. External must also never be presented as Auto.

Additional correctness gaps

4. [P2] Deep Research can request and receive write or network expansion

Deep Research starts with a managed read-only profile, but Desktop still includes the complete builtin surface and unconditionally exposes request_sandbox_boundary:

Storage applies an approved expansion to any managed profile, including read-only:

I reproduced approval of a network expansion on a Deep Research session. The resulting profile was still named read-only, but its network state was enabled.

The Deep Research surface should omit mutation tools and the boundary-request tool, and its internal read-only boundary must not be expandable into write or process-network authority.

5. [P2] Child boundary persistence is fixed, but filesystem execution does not fully inherit Bypass or External

The parent boundary is now persisted into the child correctly. However, the child header still uses the Agent definition’s legacy permission mode, and the filesystem worker only consumes managed boundaries:

For an inherited Bypass or External boundary, filesystem execution falls back to the child definition’s legacy profile. The same child can therefore run Bash according to the inherited boundary while Read/Write/Edit follow a different authority.

Boundary handling in the filesystem client should be exhaustive: managed, bypass, and external must each have explicit semantics, with no fallback to permissionMode.

6. [P2] Non-interactive Auto can still return exit code 0 after an unresolved boundary failure

maka run does not register the boundary-request tool. It marks the command as failed only after receiving a sandbox_boundary_request event:

A filesystem tool can instead return sandbox_boundary_required as an ordinary structured tool failure. If the model then produces a normal final answer explaining that it could not complete the task, the invocation remains completed and maka run returns 0.

An unresolved boundary requirement must become a terminal non-interactive invocation outcome, independently of whether a request event was published.

7. [P2] A session bundle does not read its header and boundary from one SQLite snapshot

The bundle exporter writes selected session metadata and the selected boundary through two independent exporter calls:

A concurrent Auto/Bypass transition between those reads can export a header from one revision and a boundary from another. Import then accepts both as the new genesis state.

Storage should provide one read transaction that returns an immutable portable { header, boundary } snapshot before either transfer file is written.

Implementation-quality concern

The Runtime public boundary contract still permits the authoritative reader to be absent:

All current first-party production call sites appear to provide the reader, so I am not treating this as a separate exploit. However, the public API still silently reconstructs authority from header.permissionMode, which preserves the dual-authority fallback that this PR claims to remove.

The boundary reader should be required. Interactive expansion support can be represented separately as an explicit enabled/disabled capability.

There are also several source-regex and collaborator-call tests that lock implementation shape rather than public behavior. I do not use those as the primary basis for this review, but they should be replaced with behavioral coverage while these paths are being corrected.

Validation

On final head d481739:

  • npm run build:test passed.
  • Linux sandbox smoke passed, 7/7.
  • Linux filesystem-worker smoke passed, 2/2.
  • SQLite session metadata tests passed, 30/30.
  • git diff --check a454b9a..d481739 passed.
  • GitHub typecheck, test, and e2e checks are green.

The green suite validates the supported sandbox path, but it does not cover the fail-open worker-unavailable path or the cross-surface inconsistencies above.

简体中文

审查结论

Request changes。

我基于 #1564 的已接受契约与本 PR body 声明的保证,对最终 head d481739 进行了审查。SQLite transition、Prompt settlement、--yolo 保护、boundary 持久化和 Linux sandbox 测试都是有价值的改进,但若干执行路径仍违反这次改动的核心不变量。

最新 rebase 与最终的 d481739 cleanup commit 没有改变下述 sandbox 语义。

本次审查采用的契约

已接受的 #1564 契约要求:

  • 每个 session 只有一个 authoritative、session-scoped ExecutionBoundary
  • enforcement 不可用时,managed execution 必须 fail closed;
  • process network 与 filesystem boundary 必须具有精确且可达的 expansion 流程;
  • External execution 只能在存在显式 external isolation owner 时使用;
  • Deep Research 必须保持内部 managed read-only;
  • 子 Agent 必须继承父 session boundary;
  • 非交互 Auto 遇到无法解决且不可避免的 boundary requirement 时必须非零退出;
  • session bundle 必须恢复 authoritative boundary。

Issue 讨论中关于默认启用 network、自动退化到 Bypass,以及把用户给出的路径视为隐式授权的替代提案已经被明确拒绝。以下 findings 以已接受的 issue body 为准,不采用这些替代提案。

阻塞问题

1. [P1] Filesystem worker 不可用时,managed filesystem tool 会 fail open

当平台无法提供内置 worker sandbox 时,Desktop 与 CLI 会有条件地省略 filesystem worker。buildBuiltinTools 随后退回 createLocalWorkspaceExecutor,导致 Write/Edit/Read 在 host 上执行,而不是拒绝 managed execution。

相关路径:

我在最终 head 上完成了复现:未提供 worker 时,explore/read-only boundary 下的 Write 成功创建了文件。

Managed execution 必须在进入 host executor 前返回 enforcement-unavailable failure。Host 路径只能由显式 Bypass 或 harness-owned External boundary 访问。

2. [P1] 首次 process-network expansion 没有合法的请求路径

Auto 默认限制 process network,但 Bash 没有声明 network requirement 的字段。命令被拒绝时只返回可能的 sandbox-denial signal,不包含 sandbox_boundary_required 或具体 network expansion:

Runtime guidance 同时要求 Agent 不得推断 expansion,且只有在工具返回精确 expansion 后才能请求:

我复现了带有 sandboxType: linuxEPERM network denial,但 failure 中没有 required expansion。因此 npm installgit pullcurl 等命令无法进入 #1564 要求的 session-level network approval 流程。

这里需要一个声明式且本身不授予权限的 process-network requirement,或同样可靠的 backend signal,以便在不解析 command text 的情况下生成精确 expansion。

3. [P1] External session 可以在 Desktop/TUI 中以 Auto 恢复,同时 Bash 不受 Maka sandbox 约束

导入的 session bundle 可以恢复 External boundary。Bash 将 Bypass 和 External 都视为跳过 Maka sandbox 的指令:

Desktop 把所有非 Bypass boundary 映射为 Auto,而 TUI session switching 继续投影 legacy permissionMode

maka run 已经正确拒绝该 resume 路径,但普通 Desktop 与交互式 TUI 没有拒绝。最终结果是:一个标记为 Auto 的 session 在缺少原定 external harness 的情况下执行 host Bash。

除非注入显式 external-isolation owner,否则普通交互式 surface 必须拒绝 External session。External 也绝不能显示为 Auto。

其他正确性缺口

4. [P2] Deep Research 可以请求并获得 write 或 network expansion

Deep Research 从 managed read-only profile 开始,但 Desktop 仍包含完整 builtin surface,并无条件暴露 request_sandbox_boundary

Storage 会把已批准的 expansion 应用到任意 managed profile,包括 read-only:

我复现了 Deep Research session 的 network expansion approval。结果 profile 仍名为 read-only,但 network state 已变为 enabled

Deep Research surface 应移除 mutation tool 与 boundary-request tool,其内部 read-only boundary 也不应扩张为 write 或 process-network authority。

5. [P2] Child boundary 已正确持久化,但 filesystem execution 没有完整继承 Bypass 或 External

Parent boundary 现在已经能正确持久化到 child。但 child header 仍使用 Agent definition 的 legacy permission mode,而 filesystem worker 只消费 managed boundary:

对于继承的 Bypass 或 External boundary,filesystem execution 会退回 child definition 的 legacy profile。同一个 child 因而可能让 Bash 遵循 inherited boundary,却让 Read/Write/Edit 遵循另一套 authority。

Filesystem client 应穷举处理 managed、bypass 与 external,不能再退回 permissionMode

6. [P2] 非交互 Auto 在 boundary failure 未解决后仍可能返回退出码 0

maka run 不注册 boundary-request tool。它只有在收到 sandbox_boundary_request event 后才把命令标记为失败:

Filesystem tool 也可能只把 sandbox_boundary_required 作为普通 structured tool failure 返回。如果 model 随后正常输出无法完成任务的说明,invocation 仍是 completed,maka run 最终返回 0。

未解决的 boundary requirement 必须成为非交互 invocation 的 terminal failure,不能依赖是否发布了 request event。

7. [P2] Session bundle 没有从同一个 SQLite snapshot 读取 header 与 boundary

Bundle exporter 通过两个独立 exporter 调用写入 selected session metadata 和 selected boundary:

如果两次读取之间发生并发 Auto/Bypass transition,export 可能得到一个 revision 的 header 和另一个 revision 的 boundary。Import 随后会把两者共同接受为新的 genesis state。

Storage 应在一个 read transaction 内返回不可变的 portable { header, boundary } snapshot,然后再写两个 transfer file。

实现质量问题

Runtime 的 public boundary contract 仍允许 authoritative reader 缺失:

当前 first-party production call site 看起来都提供了 reader,因此我没有把它作为独立 exploit。但 public API 仍会从 header.permissionMode 静默重建 authority,保留了本 PR 声称要删除的 dual-authority fallback。

Boundary reader 应成为 required dependency。Interactive expansion support 可以单独表示为显式的 enabled/disabled capability。

此外,当前还有若干 source-regex 与 collaborator-call test,它们锁定 implementation shape,而不是验证 public behavior。我没有把这些测试作为本次 Request changes 的主要依据,但在修复上述路径时应将其替换为 behavioral coverage。

验证

最终 head d481739

  • npm run build:test 通过。
  • Linux sandbox smoke 通过,7/7。
  • Linux filesystem-worker smoke 通过,2/2。
  • SQLite session metadata tests 通过,30/30。
  • git diff --check a454b9a..d481739 通过。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

当前绿色测试覆盖了受支持的 sandbox 路径,但没有覆盖上述 worker-unavailable fail-open 路径与跨 surface 不一致。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

Thank you for the detailed review. I reproduced the reported paths and updated the PR to head 7abc0b9de.

All seven findings have now been addressed:

  1. Managed filesystem fail-open — fixed in 48ca2f864. Managed Read/Write/Edit now fail closed when the filesystem sandbox is unavailable; the host executor is reserved for explicit Bypass or External authority.

  2. Unreachable first process-network expansion — fixed in 05585da92. Bash now declares a non-authorizing sandbox capability requirement, allowing the runtime to produce an exact network expansion without parsing command text.

  3. External sessions on local interactive surfaces — fixed across 7823ab5d4 and 7abc0b9de. TUI rejects resuming External sessions without their owning harness. Desktop may display imported External history, but it is non-interactive: the composer and permission-mode controls are unavailable, permission commands are omitted, and External is never presented as Auto. Boundary loading also fails closed so Auto cannot flash before the authority snapshot arrives.

  4. Deep Research expansion and mutation surface — fixed in 3d347d48d, with the read-only tool-surface contract strengthened in c384056c5. Deep Research no longer receives mutation or boundary-expansion tools.

  5. Child boundary inheritance — fixed in 62581d26f and f04db4bec. Child admission and filesystem execution now use the inherited ExecutionBoundary explicitly, with managed, bypass, and external paths handled deliberately and child tool surfaces defined by explicit allowlists.

  6. Non-interactive unresolved boundary returning success — fixed in 093d9fad2. maka run now exits nonzero for an unresolved boundary requirement whether it appears as a request event or a structured tool failure.

  7. Non-atomic bundle boundary snapshot — fixed in 1715039e9. Session header and execution boundary are now read from one storage transaction before transfer files are written.

The implementation-quality concern was also addressed. 581f73ec5 removed the legacy boundary fallback, and fa4314bfe now makes readExecutionBoundary a required Runtime/AiSdkBackend dependency. Missing authority is rejected instead of reconstructing External or managed authority from legacy permissionMode. Tests that intentionally exercise an externally isolated raw runtime now opt into that authority explicitly.

For the Desktop follow-up, 7abc0b9de adds behavioral coverage for managed, bypass, loading, and external boundary projections, plus command-surface coverage. I did not broaden this follow-up into a rewrite of unrelated source-contract tests.

Validation on 7abc0b9de:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • full npm run test:dist across all workspaces
  • Runtime: 2,697 passed, 9 skipped, 0 failed
  • Desktop: 2,968 passed, 0 failed
  • GitHub typecheck, test, and e2e: all green

Could you please re-review the current head?

简体中文

感谢这次详细审查。我复现了报告中的路径,并已把 PR 更新到 head 7abc0b9de

七项 findings 现已全部处理:

  1. Managed filesystem fail-open — 已在 48ca2f864 修复。Filesystem sandbox 不可用时,managed Read/Write/Edit 现在会 fail closed;host executor 只供显式 Bypass 或 External authority 使用。

  2. 首次 process-network expansion 不可达 — 已在 05585da92 修复。Bash 现在声明一个本身不授予权限的 sandbox capability requirement,使 Runtime 无需解析 command text 就能生成精确的 network expansion。

  3. External session 被本地交互 surface 执行 — 已通过 7823ab5d47abc0b9de 修复。TUI 会拒绝在缺少所属 harness 时恢复 External session。Desktop 可以查看导入的 External 历史,但保持不可交互:composer 和 permission-mode control 不可用,permission command 不会出现,External 也绝不会显示为 Auto。Boundary 加载阶段同样 fail closed,避免 authority snapshot 到达前短暂显示 Auto。

  4. Deep Research expansion 与 mutation surface — 已在 3d347d48d 修复,并由 c384056c5 加强 read-only tool-surface 契约。Deep Research 不再获得 mutation 或 boundary-expansion tool。

  5. Child boundary inheritance — 已在 62581d26ff04db4bec 修复。Child admission 与 filesystem execution 现在显式使用继承的 ExecutionBoundary,managed、bypass、external 均有明确语义,child tool surface 由显式 allowlist 定义。

  6. 非交互 unresolved boundary 错误返回成功 — 已在 093d9fad2 修复。无论 boundary requirement 来自 request event 还是 structured tool failure,maka run 都会非零退出。

  7. Bundle boundary snapshot 非原子 — 已在 1715039e9 修复。Session header 与 execution boundary 现在会在同一个 storage transaction 中读取,然后才写入 transfer files。

实现质量问题也已处理。581f73ec5 删除了 legacy boundary fallback,fa4314bfe 则将 readExecutionBoundary 设为 Runtime/AiSdkBackend 的 required dependency。缺少 authority 时现在会直接拒绝,不再从 legacy permissionMode 重建 External 或 managed authority。需要直接测试 externally isolated raw runtime 的测试也会显式选择该 authority。

Desktop follow-up 7abc0b9de 增加了 managed、bypass、loading、external boundary projection 的行为测试,以及 command surface 测试。此次 follow-up 没有盲目扩大到重写无关的 source-contract test。

7abc0b9de 上的验证结果:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • 全 workspace npm run test:dist
  • Runtime:2,697 通过,9 跳过,0 失败
  • Desktop:2,968 通过,0 失败
  • GitHub typecheckteste2e:全部绿色

能否请你基于当前 head 再 review 一次?

@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed head 7abc0b9de and reran the relevant targeted tests.

Re-review outcome

The following findings are resolved:

  1. Managed filesystem execution now fails closed when the worker sandbox is unavailable.
  2. Bash can declare an exact process-network boundary requirement without parsing command text.
  3. External sessions are rejected by TUI and remain non-interactive in Desktop.
  4. Deep Research now receives a read-only tool surface without boundary-expansion tools.
  5. Non-interactive unresolved boundary failures now produce a nonzero exit.
  6. Session bundle metadata and boundary are read from one SQLite authority snapshot.
  7. readExecutionBoundary is now required, and the Runtime legacy boundary fallback has been removed.

One finding remains open.

[P2] Child filesystem execution still does not inherit Bypass or External semantics

The parent ExecutionBoundary is persisted into the child, but ordinary child creation still stores the Agent definition’s legacy permission mode:

The filesystem worker only consumes the supplied boundary when its kind is managed. For Bypass or External, it falls back to permissionProfile or the child’s legacy mode:

Bash, by contrast, explicitly skips the Maka sandbox for the inherited Bypass or External boundary:

I reproduced the remaining mismatch on 7abc0b9de by executing an outside-workspace filesystem write with a Bypass or External boundary and a legacy child mode:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

The worker process was never launched. The operation was rejected by the legacy profile selected before sandbox execution.

The explicit child tool allowlists correctly constrain which tools a child receives, but they do not make those tools use the inherited boundary. An implementation child can therefore run Bash according to inherited Bypass/External authority while Read/Write/Edit continue to use a different filesystem authority.

Please make filesystem authority selection exhaustive over all ExecutionBoundary kinds. Once an authoritative boundary is supplied, the filesystem client should not fall back to permissionMode. A regression test should exercise a real inherited child Bypass/External boundary through the builtin filesystem tool path.

Validation

On 7abc0b9de:

  • npm run build:test passed.
  • Runtime targeted tests passed, 100/100.
  • CLI targeted tests passed, 72/72.
  • Storage targeted tests passed, 60/60.
  • Desktop targeted tests passed, 13/13.
  • Linux sandbox and filesystem-worker smoke tests passed, 9/9.
  • GitHub typecheck, test, and e2e checks are green.

I did not find another blocker in the follow-up scope. The previous findings can remain resolved; only the child filesystem-boundary finding remains open.

简体中文

@Astro-Han

我基于 head 7abc0b9de 完成了 re-review,并重新运行了相关定向测试。

Re-review 结论

以下 findings 已确认 resolved:

  1. Filesystem worker sandbox 不可用时,managed filesystem execution 现在会 fail closed。
  2. Bash 现在可以在不解析 command text 的情况下声明精确的 process-network boundary requirement。
  3. TUI 会拒绝 External session,Desktop 中的 External session 保持不可交互。
  4. Deep Research 现在只获得 read-only tool surface,不再获得 boundary-expansion tool。
  5. 非交互 unresolved boundary failure 现在会产生非零退出码。
  6. Session bundle metadata 与 boundary 现在从同一个 SQLite authority snapshot 读取。
  7. readExecutionBoundary 已成为 required dependency,Runtime legacy boundary fallback 也已删除。

仍有一项 finding 未关闭。

[P2] Child filesystem execution 仍未继承 Bypass 或 External 语义

Parent ExecutionBoundary 已经持久化到 child,但普通 child 创建仍会把 Agent definition 的 legacy permission mode 写入 header:

Filesystem worker 只有在 boundary kind 为 managed 时才消费传入的 boundary。对于 Bypass 或 External,它仍会退回 permissionProfile 或 child legacy mode

Bash 则会针对 inherited Bypass 或 External boundary 显式跳过 Maka sandbox:

我在 7abc0b9de 上使用 Bypass/External boundary 与 legacy child mode 执行 workspace 外 filesystem write,仍能复现该不一致:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

Worker process 没有启动。操作在 sandbox execution 之前就被 legacy profile 拒绝。

显式 child tool allowlist 正确限制了 child 可以获得哪些工具,但没有让这些工具使用 inherited boundary。因此 implementation child 仍可能让 Bash 遵循 inherited Bypass/External authority,而 Read/Write/Edit 使用另一套 filesystem authority。

请对所有 ExecutionBoundary kind 做穷举的 filesystem authority selection。一旦提供 authoritative boundary,filesystem client 就不应再退回 permissionMode。Regression test 应通过 builtin filesystem tool 路径,覆盖真实 inherited child Bypass/External boundary。

验证

7abc0b9de 上:

  • npm run build:test 通过。
  • Runtime 定向测试通过,100/100。
  • CLI 定向测试通过,72/72。
  • Storage 定向测试通过,60/60。
  • Desktop 定向测试通过,13/13。
  • Linux sandbox 与 filesystem-worker smoke tests 通过,9/9。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

在本次 follow-up 范围内没有发现其他 blocker。此前其余 findings 可以保持 resolved;目前只剩 child filesystem-boundary finding 未关闭。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

@M4n5ter

Thank you. I addressed the remaining child filesystem-boundary finding. The current head is 3f5443b7f.

The root cause was that the filesystem worker boundary was not explicit enough: it is a managed-only enforcement path, while Bypass and External execution must never be projected into it or reconstructed from a legacy child mode.

The fix now covers both layers:

  1. bf370bd1a makes builtin filesystem dispatch depend on the authoritative ExecutionBoundary before any worker call:

    • Managed routes through the filesystem worker and fails closed when enforcement is unavailable.
    • Bypass and External route through the executor supplied by their owning surface.
    • Neither path consults the child’s legacy permissionMode.
  2. 3f5443b7f closes the lower-level API ambiguity:

    • FilesystemWorkerClient now rejects any supplied Bypass or External boundary.
    • Once an authoritative boundary is supplied, the client can no longer fall back to permissionProfile or mode.

The regression coverage reproduces the inherited-child shape directly through builtin Write: legacy permissionMode: explore combined with authoritative Bypass and External boundaries. Both use the non-worker path, while direct attempts to pass either boundary into FilesystemWorkerClient fail before validation or process launch.

Fresh-eye validation also added bounded hardening around boundary narrowing, stale linked-child resume, External admission, descendant non-interactive failures, exact-write grant isolation, authority round-trips, and prompt response races. These remain separate atomic commits and do not reintroduce the generic permission or legacy mode paths.

Validation on 3f5443b7f:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • full serial npm run test:dist across all workspaces
  • Runtime after the final worker-client change: 2,706 passed, 9 skipped, 0 failed
  • Runtime Host: 303 passed, 0 failed
  • Desktop: 2,970 passed, 0 failed
  • targeted builtin filesystem-worker and client tests: 20 passed, 0 failed

Could you please re-review the current head?

简体中文

@M4n5ter

感谢。我已经处理了最后一项 child filesystem-boundary finding。当前 head 为 3f5443b7f

根因是 filesystem worker 的职责边界不够明确:它只应是 Managed 的 enforcement path;Bypass 与 External execution 既不应进入 worker,也不能从 legacy child mode 重建权限。

修复现在覆盖两层:

  1. bf370bd1a 让 builtin filesystem dispatch 在调用 worker 前直接依据权威 ExecutionBoundary 路由:

    • Managed 必须走 filesystem worker;enforcement 不可用时 fail closed。
    • Bypass 与 External 走所属 surface 注入的 executor。
    • 两条路径都不再查询 child 的 legacy permissionMode
  2. 3f5443b7f 关闭了底层 API 的歧义:

    • FilesystemWorkerClient 现在会拒绝任何传入的 Bypass 或 External boundary。
    • 一旦提供权威 boundary,client 就不能再回退到 permissionProfilemode

回归测试通过 builtin Write 直接复现 inherited-child 的组合:legacy permissionMode: explore 加权威 Bypass/External boundary。两者都会走非 worker 路径;如果直接把任一 boundary 传给 FilesystemWorkerClient,则会在 validation 或进程启动前 fail closed。

Fresh-eye 验证还以有限范围补强了 boundary narrowing、stale linked-child resume、External admission、非交互后代失败、exact-write grant 隔离、authority round-trip 和 prompt response race。它们都保留为独立原子提交,也没有重新引入 generic permission 或 legacy mode 路径。

3f5443b7f 上的验证:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • 全 workspace 串行 npm run test:dist
  • 最后一项 worker-client 修复后的 Runtime:2,706 通过,9 跳过,0 失败
  • Runtime Host:303 通过,0 失败
  • Desktop:2,970 通过,0 失败
  • builtin filesystem-worker 与 client 定向测试:20 通过,0 失败

能否请你基于当前 head 再 review 一次?

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 3f5443b to c4a7062CompareJuly 29, 2026 08:43
@M4n5ter

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed the latest head c4a7062c9. The rebase preserved the 13 follow-up patches; the new final commit only reconciles an AI-provider test fixture.

Re-review outcome

The previously reported child filesystem-boundary mismatch is resolved. Builtin filesystem dispatch now follows the authoritative boundary, and the targeted builtin/client tests pass 20/20.

Request changes. Three correctness blockers and four additional gaps remain.

Blocking correctness findings

1. [P1] A missing exact-write grant still blocks unrelated Bash commands on real Linux

prepareLinuxBashExactWriteTargets now prepares only exact paths declared by the current required_boundary, but the complete durable profile is still passed to bubblewrap:

Every exact-write entry in that profile remains a bind-mount source. If an undeclared exact target or its parent no longer exists, bubblewrap fails before executing the command.

I reproduced this with an unrelated command:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

The added unit test does not catch this because it uses a fake available sandbox manager and never executes the generated bubblewrap command.

This is also the current required-CI failure: Linux sandbox smoke fails 6/7 with the same missing-source error.

The per-invocation Linux mount plan should omit absent undeclared exact entries while safely preparing an exact target that the current invocation declares. This needs a real bubblewrap smoke test for both cases.

2. [P1] Legacy permissionCeiling prevents default Auto sessions from creating executable children

A normal new session still defaults to legacy permissionMode: ask, while Web Research and Implementation definitions use execute. Child creation therefore stores permissionMode: execute with permissionCeiling: ask:

Current-header normalization still treats that legacy ceiling as live authority:

I reproduced the resulting persistence failure:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

This happens before the inherited ExecutionBoundary can govern the child. permissionCeiling should be limited to legacy decoding/migration, not written or enforced for current child sessions. A SQLite-backed child-creation behavior test should cover an Implementation child spawned from the default Auto session.

3. [P1] Narrowing a parent boundary does not revoke descendant background processes

A child Bash run is registered under the child session ID:

The parent boundary transition terminates only the parent session’s shell runs:

A foreground child can start background Bash, return, and leave the process alive. The parent can then narrow from Bypass to Auto, or Auto to Explore, while that descendant process continues with its old authority. The stale-child resume guard prevents a future resume but does not revoke already-live processes.

Boundary narrowing needs lineage-wide revocation of descendant shell runs and backend generations before committing the transition, with regression coverage for a completed child turn that leaves background Bash running.

Additional correctness gap

4. [P2] An Explore-origin session cannot return from Bypass to Auto

For an Explore-origin session, genesis is the managed read-only profile. After switching to Bypass, restoration searches only for a previous non-read-only managed profile:

I reproduced:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

The transition should be total for supported UI states. If Explore sessions may enter Bypass, a missing Auto history should restore the canonical Auto genesis profile. If they must remain read-only, Bypass should be rejected and hidden before the transition.

Maintainability findings

5. [P2] Sandbox containment semantics are duplicated inside SessionManager

The follow-up adds approximately 70 lines of profile, access, path, deny, and protected-metadata containment logic to an already very large runtime coordinator:

Boundary containment is a core contract and will drift if Runtime owns a second implementation. Please expose one canonical Core helper and keep SessionManager as a caller.

6. [P2] The public legacy snapshot exporter can silently omit authoritative boundaries

exportLegacySessionTreeSnapshot accepts required records but an optional boundary map, and silently skips the boundary transfer file when an entry is absent:

The production wrapper currently supplies the map, but the exported public helper still permits a boundary-less session export. Its input should carry paired authority snapshots and require one boundary for every selected session.

7. [P2] The new External-admission regression test verifies source layout, not behavior

The test reads main.ts and uses regular expressions to require a specific helper name, handler layout, and call text:

It can pass without proving that IPC admission rejects External execution, and harmless refactoring can break it. Please replace it with an IPC behavior harness covering compact, resume, regenerate, and plan approval, asserting that runtime execution is not reached.

Validation

On c4a7062c9:

  • npm run build:test passed.
  • Child filesystem builtin/client tests passed, 20/20.
  • The default-Auto executable-child header was rejected in a direct current-header normalization reproduction.
  • Explore → Bypass → Auto failed in an in-memory SQLite reproduction.
  • An unrelated true command failed under real bubblewrap when the profile contained a missing exact-write grant.
  • Local required Linux sandbox smoke failed, 6/7.
  • GitHub typecheck and e2e are green; test is red on the same Linux smoke failure.
简体中文

@Astro-Han

我基于最新 head c4a7062c9 完成了 re-review。Rebase 保留了 13 个 follow-up patch;新增的最后一个 commit 只调整了 AI provider test fixture。

Re-review 结论

此前未关闭的 child filesystem-boundary 不一致已经解决。Builtin filesystem dispatch 现在遵循 authoritative boundary,相关 builtin/client 定向测试 20/20 通过。

仍需 Request changes。目前还有三项 correctness blocker 和四项其它问题。

阻塞性 correctness findings

1. [P1] 失效的 exact-write grant 在真实 Linux 上仍会阻断无关 Bash 命令

prepareLinuxBashExactWriteTargets 现在只准备当前 required_boundary 声明的 exact path,但完整的持久化 profile 仍会传给 bubblewrap:

Profile 中的每个 exact-write entry 仍然会成为 bind-mount source。如果一个未被本次调用声明的 exact target 或其 parent 已不存在,bubblewrap 会在执行 command 前失败。

我使用一条完全无关的命令复现了该问题:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

新增的 unit test 使用 fake available sandbox manager,并未执行生成的 bubblewrap command,因此无法覆盖真实行为。

这也是当前 required CI 的失败原因:Linux sandbox smoke 以相同的 missing-source 错误失败,结果为 6/7。

Linux 每次调用的 mount plan 应忽略不存在且未被当前调用声明的 exact entry;如果当前调用显式声明 exact target,则应安全地准备它。两条路径都需要真实 bubblewrap smoke coverage。

2. [P1] Legacy permissionCeiling 会阻止默认 Auto session 创建 executable child

普通新 session 的 legacy permissionMode 默认仍为 ask,而 Web Research 与 Implementation definition 使用 execute。Child 创建因此会同时写入 permissionMode: executepermissionCeiling: ask

Current-header normalization 仍把 legacy ceiling 当作 live authority:

我复现到的持久化结果为:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

失败发生在 inherited ExecutionBoundary 能够治理 child 之前。permissionCeiling 应仅用于 legacy decode/migration,不应继续写入或验证 current child session。需要通过真实 SQLite child-creation 行为测试覆盖默认 Auto session 创建 Implementation child 的路径。

3. [P1] 收窄 parent boundary 不会撤销 descendant background process

Child Bash run 会记录在 child session ID 下:

Parent boundary transition 只终止 parent session 自身的 shell run:

Foreground child 可以启动 background Bash 后返回,但让进程继续运行。随后 parent 可以从 Bypass 收窄到 Auto,或从 Auto 收窄到 Explore;descendant process 仍保留旧 authority。Stale-child resume guard 只能阻止未来 resume,无法撤销已经存活的进程。

Boundary narrowing 应在提交 transition 前,按 session lineage 撤销所有 descendant shell run 与 backend generation,并增加“child turn 已结束但 background Bash 仍在运行”的 regression coverage。

其它 correctness gap

4. [P2] Explore-origin session 无法从 Bypass 返回 Auto

Explore-origin session 的 genesis 是 managed read-only profile。切换到 Bypass 后,恢复逻辑只查找历史中的 non-read-only managed profile:

我的复现结果为:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

所有受支持的 UI 状态都应拥有完整 transition。如果 Explore session 可以进入 Bypass,那么缺少 Auto history 时应恢复 canonical Auto genesis profile;如果它必须始终保持 read-only,则应在 transition 之前拒绝并隐藏 Bypass。

可维护性 findings

5. [P2] Sandbox containment 语义被重复实现在 SessionManager

Follow-up 在已经非常庞大的 runtime coordinator 中增加了约 70 行 profile、access、path、deny 与 protected-metadata containment 逻辑:

Boundary containment 属于 Core contract。Runtime 保留第二套实现会产生语义漂移。建议在 Core 暴露一个 canonical helper,让 SessionManager 只负责调用。

6. [P2] Public legacy snapshot exporter 可以静默遗漏 authoritative boundary

exportLegacySessionTreeSnapshot 要求提供 records,却把 boundary map 设为 optional;如果某个 entry 不存在,就会静默跳过 boundary transfer file:

当前 production wrapper 的确提供了 map,但导出的 public helper 仍允许生成缺失 boundary 的 session export。其输入应改为成对的 authority snapshot,并要求每个被选择的 session 都有 boundary。

7. [P2] 新增的 External-admission regression test 验证 source layout,而不是行为

该测试读取 main.ts,再用正则要求特定 helper 名称、handler 布局和调用文本:

它无法证明 IPC admission 确实会拒绝 External execution,同时正常重构也会使测试破裂。应替换为 IPC behavior harness,覆盖 compact、resume、regenerate 与 plan approval,并断言 runtime execution 未被调用。

验证

c4a7062c9 上:

  • npm run build:test 通过。
  • Child filesystem builtin/client tests 20/20 通过。
  • Direct current-header normalization 复现到默认 Auto executable-child header 被拒绝。
  • In-memory SQLite 复现到 Explore → Bypass → Auto 失败。
  • 在真实 bubblewrap 下,profile 含有失效 exact-write grant 时,无关的 true command 仍会失败。
  • 本地 required Linux sandbox smoke 失败,6/7。
  • GitHub typechecke2e 通过;test 因相同 Linux smoke 错误失败。

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch 2 times, most recently from 4c0af93 to d01db12CompareJuly 29, 2026 10:43
@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 58fdec7 to 6b82f24CompareJuly 29, 2026 11:52
@Astro-Han
Astro-Han merged commit 0fe34a7 into mainJul 29, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/1564-session-sandbox-boundary branch July 29, 2026 12:00
Astro-Han added a commit that referenced this pull request Jul 29, 2026
#1581 replaced tool permissions with session sandbox boundaries and removed
`PermissionEngine` from `@maka/runtime`, but left this test importing it and
passing a `permissionEngine` dependency that the session-stream deps type no
longer has. `main` has been red since: `tsc -p tsconfig.main.json` fails with
TS2305, which takes `build:main` down and with it the typecheck, test, and e2e
jobs on every branch.
Nothing in production takes a `permissionEngine` any more, and the test's
subject is usage readiness, so the import and the dependency go. No behavioural
change and no replacement needed.
Sign up for freeto 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.

feat: replace per-tool approvals with sandbox boundaries

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: replace tool permissions with session sandbox boundaries - #1581

Merged
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary
Jul 29, 2026
Merged

feat: replace tool permissions with session sandbox boundaries#1581
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace additional permissions, one-call sandbox escalation, and the live generic tool-approval path with one revisioned, session-scoped ExecutionBoundary authority.
  • Persist genesis boundaries, immutable expansion requests, and applied revisions in the SQLite session metadata store. Approval and boundary advancement commit atomically; stale, duplicate, and concurrently decided requests settle deterministically.
  • Keep the expansion schema no broader than the product needs today: exact/subtree filesystem read/write entries plus session network enablement. Tools report exact sandbox_boundary_required deltas or requires_bypass; Bash diagnostics never parse commands or invent authority.
  • Wire the boundary lifecycle end to end through core, storage, runtime, Runtime Host, session bundles, Desktop/shared UI, TUI, headless/Harbor, and non-interactive CLI. Desktop and TUI expose Auto/Bypass, boundary prompts take over the composer, and Bypass requires an explicit second confirmation.
  • Remove the superseded PermissionEngine matrix, grant ingress, generic permission prompts, and legacy live escalation executors in the same PR so no dual-authority intermediate state ships. Historical codecs and settled audit history remain readable; OS Permission Center behavior is unchanged.

Closes#1564

Verification

  • npm run build — passed across all workspaces.
  • npm run test:dist — passed the complete repository suite with the workspace runner in serial mode, including script contracts (176/176), storage (733 passed, 1 skipped), Runtime (2675 passed, 9 skipped), Runtime Host (212/212), and Desktop (2964/2964).
  • npm run format:check — passed, 1221 files checked.
  • npm run lint — passed, 2304 files checked.
  • npm run typecheck — passed across all workspaces.
  • node --test packages/runtime/dist/__tests__/macos-seatbelt-smoke.test.js packages/runtime/dist/__tests__/filesystem-worker-smoke.test.js — passed (9/9), including exact outside-path expansion and restricted network behavior.
  • npm run e2e -w @maka/desktop -- e2e/sandbox-boundary-takeover.spec.ts — passed (1/1), covering the visible Desktop composer takeover and approval journey.
  • The all-workspace parallel npm test command intermittently exhausted a Runtime Host test's local timing window under machine load. That package passed independently (212/212), and the complete serial repository run above passed; this PR does not broaden into unrelated test-harness timing changes.

Migration and breaking change

  • Legacy ask and execute sessions enter the managed workspace-write boundary; explore enters managed read-only; bypass remains bypass. First access durably records revision 0 without rewriting settled historical records.
  • Pending legacy permission interactions close with host_restarted during recovery because their live continuation authority cannot survive the upgrade.
  • Interactive surfaces now expose only Auto and Bypass. Removed permission modes and per-tool grant flags fail during CLI argument validation.
  • maka run defaults to Auto and cannot interactively expand a boundary, so it fails closed when expansion is requested. Only explicit --yolo creates or resumes a bypass session.
  • Headless/Harbor sessions explicitly use the external boundary; imports and exports preserve the authoritative boundary even though the SQLite database itself is not bundled.

Review focus

  • The SQLite transaction boundary around request settlement and boundary revision advancement, including cross-connection races.
  • The runtime continuation/publication barrier when a sandbox boundary or user question is pending, including durable denial when a turn closes.
  • The cross-surface fail-closed behavior for ordinary expansion requests versus requires_bypass.
  • The branch contains 105 small, reversible commits ordered from contracts and storage through runtime, surfaces, legacy-path removal, and regression coverage.

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 6f15924 to d481739CompareJuly 29, 2026 01:50
@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

Review outcome

Request changes.

I reviewed the final PR head d481739 against the accepted contract in #1564 and the guarantees stated in this PR body. The SQLite transition work, prompt settlement, --yolo protection, boundary persistence, and Linux sandbox tests are meaningful improvements, but several execution paths still violate the central invariants of this change.

The latest rebase and the final d481739 cleanup commit do not change the sandbox semantics described below.

Contract used for this review

The accepted #1564 contract requires:

  • one authoritative, session-scoped ExecutionBoundary;
  • managed execution to fail closed when enforcement is unavailable;
  • an exact, reachable expansion flow for process network and filesystem boundaries;
  • External execution only when an explicit external isolation owner exists;
  • Deep Research to remain internally managed and read-only;
  • child Agents to inherit the parent boundary;
  • non-interactive Auto to exit nonzero when an unavoidable boundary requirement cannot be resolved; and
  • session bundles to restore the authoritative boundary.

The alternative proposals to enable network by default, automatically fall through to Bypass, or treat user-provided paths as implicit authorization were explicitly rejected in the issue discussion. These findings are evaluated against the accepted issue body, not those alternatives.

Blocking findings

1. [P1] Managed filesystem tools fail open when the filesystem worker is unavailable

Desktop and CLI conditionally omit the filesystem worker when the platform cannot provide the built-in worker sandbox. buildBuiltinTools then falls back to createLocalWorkspaceExecutor, and Write/Edit/Read execute on the host instead of rejecting managed execution.

Relevant paths:

I reproduced this on the final head: a Write call under an explore/read-only boundary successfully created a file when no worker was supplied.

Managed execution must return an enforcement-unavailable failure before reaching the host executor. The host path should only be reachable for an explicit Bypass or harness-owned External boundary.

2. [P1] The first process-network expansion has no valid request path

Auto starts with restricted process network, but Bash has no declarative network requirement. A denied command returns only a likely sandbox-denial signal, without sandbox_boundary_required or a concrete network expansion:

Runtime guidance simultaneously states that the Agent must not infer an expansion and may request one only after a tool returns an exact expansion:

I reproduced an EPERM network denial with sandboxType: linux; the failure contained no required expansion. Commands such as npm install, git pull, and curl therefore cannot reach the session-level network approval flow required by #1564.

This needs a declarative, non-authorizing process-network requirement or an equally reliable backend signal that can produce the exact expansion without parsing command text.

3. [P1] An External session can resume in Desktop/TUI as Auto while Bash runs without a Maka sandbox

Imported session bundles can restore an External boundary. Bash treats both Bypass and External as instructions to skip the Maka sandbox:

Desktop maps every non-Bypass boundary to Auto, while TUI session switching continues to project the legacy permissionMode:

maka run correctly rejects this resume path, but ordinary Desktop and interactive TUI do not. The result is an Auto-labelled session executing host Bash without the external harness that supposedly owns isolation.

External sessions must be rejected by ordinary interactive surfaces unless an explicit external-isolation owner is injected. External must also never be presented as Auto.

Additional correctness gaps

4. [P2] Deep Research can request and receive write or network expansion

Deep Research starts with a managed read-only profile, but Desktop still includes the complete builtin surface and unconditionally exposes request_sandbox_boundary:

Storage applies an approved expansion to any managed profile, including read-only:

I reproduced approval of a network expansion on a Deep Research session. The resulting profile was still named read-only, but its network state was enabled.

The Deep Research surface should omit mutation tools and the boundary-request tool, and its internal read-only boundary must not be expandable into write or process-network authority.

5. [P2] Child boundary persistence is fixed, but filesystem execution does not fully inherit Bypass or External

The parent boundary is now persisted into the child correctly. However, the child header still uses the Agent definition’s legacy permission mode, and the filesystem worker only consumes managed boundaries:

For an inherited Bypass or External boundary, filesystem execution falls back to the child definition’s legacy profile. The same child can therefore run Bash according to the inherited boundary while Read/Write/Edit follow a different authority.

Boundary handling in the filesystem client should be exhaustive: managed, bypass, and external must each have explicit semantics, with no fallback to permissionMode.

6. [P2] Non-interactive Auto can still return exit code 0 after an unresolved boundary failure

maka run does not register the boundary-request tool. It marks the command as failed only after receiving a sandbox_boundary_request event:

A filesystem tool can instead return sandbox_boundary_required as an ordinary structured tool failure. If the model then produces a normal final answer explaining that it could not complete the task, the invocation remains completed and maka run returns 0.

An unresolved boundary requirement must become a terminal non-interactive invocation outcome, independently of whether a request event was published.

7. [P2] A session bundle does not read its header and boundary from one SQLite snapshot

The bundle exporter writes selected session metadata and the selected boundary through two independent exporter calls:

A concurrent Auto/Bypass transition between those reads can export a header from one revision and a boundary from another. Import then accepts both as the new genesis state.

Storage should provide one read transaction that returns an immutable portable { header, boundary } snapshot before either transfer file is written.

Implementation-quality concern

The Runtime public boundary contract still permits the authoritative reader to be absent:

All current first-party production call sites appear to provide the reader, so I am not treating this as a separate exploit. However, the public API still silently reconstructs authority from header.permissionMode, which preserves the dual-authority fallback that this PR claims to remove.

The boundary reader should be required. Interactive expansion support can be represented separately as an explicit enabled/disabled capability.

There are also several source-regex and collaborator-call tests that lock implementation shape rather than public behavior. I do not use those as the primary basis for this review, but they should be replaced with behavioral coverage while these paths are being corrected.

Validation

On final head d481739:

  • npm run build:test passed.
  • Linux sandbox smoke passed, 7/7.
  • Linux filesystem-worker smoke passed, 2/2.
  • SQLite session metadata tests passed, 30/30.
  • git diff --check a454b9a..d481739 passed.
  • GitHub typecheck, test, and e2e checks are green.

The green suite validates the supported sandbox path, but it does not cover the fail-open worker-unavailable path or the cross-surface inconsistencies above.

简体中文

审查结论

Request changes。

我基于 #1564 的已接受契约与本 PR body 声明的保证,对最终 head d481739 进行了审查。SQLite transition、Prompt settlement、--yolo 保护、boundary 持久化和 Linux sandbox 测试都是有价值的改进,但若干执行路径仍违反这次改动的核心不变量。

最新 rebase 与最终的 d481739 cleanup commit 没有改变下述 sandbox 语义。

本次审查采用的契约

已接受的 #1564 契约要求:

  • 每个 session 只有一个 authoritative、session-scoped ExecutionBoundary
  • enforcement 不可用时,managed execution 必须 fail closed;
  • process network 与 filesystem boundary 必须具有精确且可达的 expansion 流程;
  • External execution 只能在存在显式 external isolation owner 时使用;
  • Deep Research 必须保持内部 managed read-only;
  • 子 Agent 必须继承父 session boundary;
  • 非交互 Auto 遇到无法解决且不可避免的 boundary requirement 时必须非零退出;
  • session bundle 必须恢复 authoritative boundary。

Issue 讨论中关于默认启用 network、自动退化到 Bypass,以及把用户给出的路径视为隐式授权的替代提案已经被明确拒绝。以下 findings 以已接受的 issue body 为准,不采用这些替代提案。

阻塞问题

1. [P1] Filesystem worker 不可用时,managed filesystem tool 会 fail open

当平台无法提供内置 worker sandbox 时,Desktop 与 CLI 会有条件地省略 filesystem worker。buildBuiltinTools 随后退回 createLocalWorkspaceExecutor,导致 Write/Edit/Read 在 host 上执行,而不是拒绝 managed execution。

相关路径:

我在最终 head 上完成了复现:未提供 worker 时,explore/read-only boundary 下的 Write 成功创建了文件。

Managed execution 必须在进入 host executor 前返回 enforcement-unavailable failure。Host 路径只能由显式 Bypass 或 harness-owned External boundary 访问。

2. [P1] 首次 process-network expansion 没有合法的请求路径

Auto 默认限制 process network,但 Bash 没有声明 network requirement 的字段。命令被拒绝时只返回可能的 sandbox-denial signal,不包含 sandbox_boundary_required 或具体 network expansion:

Runtime guidance 同时要求 Agent 不得推断 expansion,且只有在工具返回精确 expansion 后才能请求:

我复现了带有 sandboxType: linuxEPERM network denial,但 failure 中没有 required expansion。因此 npm installgit pullcurl 等命令无法进入 #1564 要求的 session-level network approval 流程。

这里需要一个声明式且本身不授予权限的 process-network requirement,或同样可靠的 backend signal,以便在不解析 command text 的情况下生成精确 expansion。

3. [P1] External session 可以在 Desktop/TUI 中以 Auto 恢复,同时 Bash 不受 Maka sandbox 约束

导入的 session bundle 可以恢复 External boundary。Bash 将 Bypass 和 External 都视为跳过 Maka sandbox 的指令:

Desktop 把所有非 Bypass boundary 映射为 Auto,而 TUI session switching 继续投影 legacy permissionMode

maka run 已经正确拒绝该 resume 路径,但普通 Desktop 与交互式 TUI 没有拒绝。最终结果是:一个标记为 Auto 的 session 在缺少原定 external harness 的情况下执行 host Bash。

除非注入显式 external-isolation owner,否则普通交互式 surface 必须拒绝 External session。External 也绝不能显示为 Auto。

其他正确性缺口

4. [P2] Deep Research 可以请求并获得 write 或 network expansion

Deep Research 从 managed read-only profile 开始,但 Desktop 仍包含完整 builtin surface,并无条件暴露 request_sandbox_boundary

Storage 会把已批准的 expansion 应用到任意 managed profile,包括 read-only:

我复现了 Deep Research session 的 network expansion approval。结果 profile 仍名为 read-only,但 network state 已变为 enabled

Deep Research surface 应移除 mutation tool 与 boundary-request tool,其内部 read-only boundary 也不应扩张为 write 或 process-network authority。

5. [P2] Child boundary 已正确持久化,但 filesystem execution 没有完整继承 Bypass 或 External

Parent boundary 现在已经能正确持久化到 child。但 child header 仍使用 Agent definition 的 legacy permission mode,而 filesystem worker 只消费 managed boundary:

对于继承的 Bypass 或 External boundary,filesystem execution 会退回 child definition 的 legacy profile。同一个 child 因而可能让 Bash 遵循 inherited boundary,却让 Read/Write/Edit 遵循另一套 authority。

Filesystem client 应穷举处理 managed、bypass 与 external,不能再退回 permissionMode

6. [P2] 非交互 Auto 在 boundary failure 未解决后仍可能返回退出码 0

maka run 不注册 boundary-request tool。它只有在收到 sandbox_boundary_request event 后才把命令标记为失败:

Filesystem tool 也可能只把 sandbox_boundary_required 作为普通 structured tool failure 返回。如果 model 随后正常输出无法完成任务的说明,invocation 仍是 completed,maka run 最终返回 0。

未解决的 boundary requirement 必须成为非交互 invocation 的 terminal failure,不能依赖是否发布了 request event。

7. [P2] Session bundle 没有从同一个 SQLite snapshot 读取 header 与 boundary

Bundle exporter 通过两个独立 exporter 调用写入 selected session metadata 和 selected boundary:

如果两次读取之间发生并发 Auto/Bypass transition,export 可能得到一个 revision 的 header 和另一个 revision 的 boundary。Import 随后会把两者共同接受为新的 genesis state。

Storage 应在一个 read transaction 内返回不可变的 portable { header, boundary } snapshot,然后再写两个 transfer file。

实现质量问题

Runtime 的 public boundary contract 仍允许 authoritative reader 缺失:

当前 first-party production call site 看起来都提供了 reader,因此我没有把它作为独立 exploit。但 public API 仍会从 header.permissionMode 静默重建 authority,保留了本 PR 声称要删除的 dual-authority fallback。

Boundary reader 应成为 required dependency。Interactive expansion support 可以单独表示为显式的 enabled/disabled capability。

此外,当前还有若干 source-regex 与 collaborator-call test,它们锁定 implementation shape,而不是验证 public behavior。我没有把这些测试作为本次 Request changes 的主要依据,但在修复上述路径时应将其替换为 behavioral coverage。

验证

最终 head d481739

  • npm run build:test 通过。
  • Linux sandbox smoke 通过,7/7。
  • Linux filesystem-worker smoke 通过,2/2。
  • SQLite session metadata tests 通过,30/30。
  • git diff --check a454b9a..d481739 通过。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

当前绿色测试覆盖了受支持的 sandbox 路径,但没有覆盖上述 worker-unavailable fail-open 路径与跨 surface 不一致。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

Thank you for the detailed review. I reproduced the reported paths and updated the PR to head 7abc0b9de.

All seven findings have now been addressed:

  1. Managed filesystem fail-open — fixed in 48ca2f864. Managed Read/Write/Edit now fail closed when the filesystem sandbox is unavailable; the host executor is reserved for explicit Bypass or External authority.

  2. Unreachable first process-network expansion — fixed in 05585da92. Bash now declares a non-authorizing sandbox capability requirement, allowing the runtime to produce an exact network expansion without parsing command text.

  3. External sessions on local interactive surfaces — fixed across 7823ab5d4 and 7abc0b9de. TUI rejects resuming External sessions without their owning harness. Desktop may display imported External history, but it is non-interactive: the composer and permission-mode controls are unavailable, permission commands are omitted, and External is never presented as Auto. Boundary loading also fails closed so Auto cannot flash before the authority snapshot arrives.

  4. Deep Research expansion and mutation surface — fixed in 3d347d48d, with the read-only tool-surface contract strengthened in c384056c5. Deep Research no longer receives mutation or boundary-expansion tools.

  5. Child boundary inheritance — fixed in 62581d26f and f04db4bec. Child admission and filesystem execution now use the inherited ExecutionBoundary explicitly, with managed, bypass, and external paths handled deliberately and child tool surfaces defined by explicit allowlists.

  6. Non-interactive unresolved boundary returning success — fixed in 093d9fad2. maka run now exits nonzero for an unresolved boundary requirement whether it appears as a request event or a structured tool failure.

  7. Non-atomic bundle boundary snapshot — fixed in 1715039e9. Session header and execution boundary are now read from one storage transaction before transfer files are written.

The implementation-quality concern was also addressed. 581f73ec5 removed the legacy boundary fallback, and fa4314bfe now makes readExecutionBoundary a required Runtime/AiSdkBackend dependency. Missing authority is rejected instead of reconstructing External or managed authority from legacy permissionMode. Tests that intentionally exercise an externally isolated raw runtime now opt into that authority explicitly.

For the Desktop follow-up, 7abc0b9de adds behavioral coverage for managed, bypass, loading, and external boundary projections, plus command-surface coverage. I did not broaden this follow-up into a rewrite of unrelated source-contract tests.

Validation on 7abc0b9de:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • full npm run test:dist across all workspaces
  • Runtime: 2,697 passed, 9 skipped, 0 failed
  • Desktop: 2,968 passed, 0 failed
  • GitHub typecheck, test, and e2e: all green

Could you please re-review the current head?

简体中文

感谢这次详细审查。我复现了报告中的路径,并已把 PR 更新到 head 7abc0b9de

七项 findings 现已全部处理:

  1. Managed filesystem fail-open — 已在 48ca2f864 修复。Filesystem sandbox 不可用时,managed Read/Write/Edit 现在会 fail closed;host executor 只供显式 Bypass 或 External authority 使用。

  2. 首次 process-network expansion 不可达 — 已在 05585da92 修复。Bash 现在声明一个本身不授予权限的 sandbox capability requirement,使 Runtime 无需解析 command text 就能生成精确的 network expansion。

  3. External session 被本地交互 surface 执行 — 已通过 7823ab5d47abc0b9de 修复。TUI 会拒绝在缺少所属 harness 时恢复 External session。Desktop 可以查看导入的 External 历史,但保持不可交互:composer 和 permission-mode control 不可用,permission command 不会出现,External 也绝不会显示为 Auto。Boundary 加载阶段同样 fail closed,避免 authority snapshot 到达前短暂显示 Auto。

  4. Deep Research expansion 与 mutation surface — 已在 3d347d48d 修复,并由 c384056c5 加强 read-only tool-surface 契约。Deep Research 不再获得 mutation 或 boundary-expansion tool。

  5. Child boundary inheritance — 已在 62581d26ff04db4bec 修复。Child admission 与 filesystem execution 现在显式使用继承的 ExecutionBoundary,managed、bypass、external 均有明确语义,child tool surface 由显式 allowlist 定义。

  6. 非交互 unresolved boundary 错误返回成功 — 已在 093d9fad2 修复。无论 boundary requirement 来自 request event 还是 structured tool failure,maka run 都会非零退出。

  7. Bundle boundary snapshot 非原子 — 已在 1715039e9 修复。Session header 与 execution boundary 现在会在同一个 storage transaction 中读取,然后才写入 transfer files。

实现质量问题也已处理。581f73ec5 删除了 legacy boundary fallback,fa4314bfe 则将 readExecutionBoundary 设为 Runtime/AiSdkBackend 的 required dependency。缺少 authority 时现在会直接拒绝,不再从 legacy permissionMode 重建 External 或 managed authority。需要直接测试 externally isolated raw runtime 的测试也会显式选择该 authority。

Desktop follow-up 7abc0b9de 增加了 managed、bypass、loading、external boundary projection 的行为测试,以及 command surface 测试。此次 follow-up 没有盲目扩大到重写无关的 source-contract test。

7abc0b9de 上的验证结果:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • 全 workspace npm run test:dist
  • Runtime:2,697 通过,9 跳过,0 失败
  • Desktop:2,968 通过,0 失败
  • GitHub typecheckteste2e:全部绿色

能否请你基于当前 head 再 review 一次?

@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed head 7abc0b9de and reran the relevant targeted tests.

Re-review outcome

The following findings are resolved:

  1. Managed filesystem execution now fails closed when the worker sandbox is unavailable.
  2. Bash can declare an exact process-network boundary requirement without parsing command text.
  3. External sessions are rejected by TUI and remain non-interactive in Desktop.
  4. Deep Research now receives a read-only tool surface without boundary-expansion tools.
  5. Non-interactive unresolved boundary failures now produce a nonzero exit.
  6. Session bundle metadata and boundary are read from one SQLite authority snapshot.
  7. readExecutionBoundary is now required, and the Runtime legacy boundary fallback has been removed.

One finding remains open.

[P2] Child filesystem execution still does not inherit Bypass or External semantics

The parent ExecutionBoundary is persisted into the child, but ordinary child creation still stores the Agent definition’s legacy permission mode:

The filesystem worker only consumes the supplied boundary when its kind is managed. For Bypass or External, it falls back to permissionProfile or the child’s legacy mode:

Bash, by contrast, explicitly skips the Maka sandbox for the inherited Bypass or External boundary:

I reproduced the remaining mismatch on 7abc0b9de by executing an outside-workspace filesystem write with a Bypass or External boundary and a legacy child mode:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

The worker process was never launched. The operation was rejected by the legacy profile selected before sandbox execution.

The explicit child tool allowlists correctly constrain which tools a child receives, but they do not make those tools use the inherited boundary. An implementation child can therefore run Bash according to inherited Bypass/External authority while Read/Write/Edit continue to use a different filesystem authority.

Please make filesystem authority selection exhaustive over all ExecutionBoundary kinds. Once an authoritative boundary is supplied, the filesystem client should not fall back to permissionMode. A regression test should exercise a real inherited child Bypass/External boundary through the builtin filesystem tool path.

Validation

On 7abc0b9de:

  • npm run build:test passed.
  • Runtime targeted tests passed, 100/100.
  • CLI targeted tests passed, 72/72.
  • Storage targeted tests passed, 60/60.
  • Desktop targeted tests passed, 13/13.
  • Linux sandbox and filesystem-worker smoke tests passed, 9/9.
  • GitHub typecheck, test, and e2e checks are green.

I did not find another blocker in the follow-up scope. The previous findings can remain resolved; only the child filesystem-boundary finding remains open.

简体中文

@Astro-Han

我基于 head 7abc0b9de 完成了 re-review,并重新运行了相关定向测试。

Re-review 结论

以下 findings 已确认 resolved:

  1. Filesystem worker sandbox 不可用时,managed filesystem execution 现在会 fail closed。
  2. Bash 现在可以在不解析 command text 的情况下声明精确的 process-network boundary requirement。
  3. TUI 会拒绝 External session,Desktop 中的 External session 保持不可交互。
  4. Deep Research 现在只获得 read-only tool surface,不再获得 boundary-expansion tool。
  5. 非交互 unresolved boundary failure 现在会产生非零退出码。
  6. Session bundle metadata 与 boundary 现在从同一个 SQLite authority snapshot 读取。
  7. readExecutionBoundary 已成为 required dependency,Runtime legacy boundary fallback 也已删除。

仍有一项 finding 未关闭。

[P2] Child filesystem execution 仍未继承 Bypass 或 External 语义

Parent ExecutionBoundary 已经持久化到 child,但普通 child 创建仍会把 Agent definition 的 legacy permission mode 写入 header:

Filesystem worker 只有在 boundary kind 为 managed 时才消费传入的 boundary。对于 Bypass 或 External,它仍会退回 permissionProfile 或 child legacy mode

Bash 则会针对 inherited Bypass 或 External boundary 显式跳过 Maka sandbox:

我在 7abc0b9de 上使用 Bypass/External boundary 与 legacy child mode 执行 workspace 外 filesystem write,仍能复现该不一致:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

Worker process 没有启动。操作在 sandbox execution 之前就被 legacy profile 拒绝。

显式 child tool allowlist 正确限制了 child 可以获得哪些工具,但没有让这些工具使用 inherited boundary。因此 implementation child 仍可能让 Bash 遵循 inherited Bypass/External authority,而 Read/Write/Edit 使用另一套 filesystem authority。

请对所有 ExecutionBoundary kind 做穷举的 filesystem authority selection。一旦提供 authoritative boundary,filesystem client 就不应再退回 permissionMode。Regression test 应通过 builtin filesystem tool 路径,覆盖真实 inherited child Bypass/External boundary。

验证

7abc0b9de 上:

  • npm run build:test 通过。
  • Runtime 定向测试通过,100/100。
  • CLI 定向测试通过,72/72。
  • Storage 定向测试通过,60/60。
  • Desktop 定向测试通过,13/13。
  • Linux sandbox 与 filesystem-worker smoke tests 通过,9/9。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

在本次 follow-up 范围内没有发现其他 blocker。此前其余 findings 可以保持 resolved;目前只剩 child filesystem-boundary finding 未关闭。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

@M4n5ter

Thank you. I addressed the remaining child filesystem-boundary finding. The current head is 3f5443b7f.

The root cause was that the filesystem worker boundary was not explicit enough: it is a managed-only enforcement path, while Bypass and External execution must never be projected into it or reconstructed from a legacy child mode.

The fix now covers both layers:

  1. bf370bd1a makes builtin filesystem dispatch depend on the authoritative ExecutionBoundary before any worker call:

    • Managed routes through the filesystem worker and fails closed when enforcement is unavailable.
    • Bypass and External route through the executor supplied by their owning surface.
    • Neither path consults the child’s legacy permissionMode.
  2. 3f5443b7f closes the lower-level API ambiguity:

    • FilesystemWorkerClient now rejects any supplied Bypass or External boundary.
    • Once an authoritative boundary is supplied, the client can no longer fall back to permissionProfile or mode.

The regression coverage reproduces the inherited-child shape directly through builtin Write: legacy permissionMode: explore combined with authoritative Bypass and External boundaries. Both use the non-worker path, while direct attempts to pass either boundary into FilesystemWorkerClient fail before validation or process launch.

Fresh-eye validation also added bounded hardening around boundary narrowing, stale linked-child resume, External admission, descendant non-interactive failures, exact-write grant isolation, authority round-trips, and prompt response races. These remain separate atomic commits and do not reintroduce the generic permission or legacy mode paths.

Validation on 3f5443b7f:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • full serial npm run test:dist across all workspaces
  • Runtime after the final worker-client change: 2,706 passed, 9 skipped, 0 failed
  • Runtime Host: 303 passed, 0 failed
  • Desktop: 2,970 passed, 0 failed
  • targeted builtin filesystem-worker and client tests: 20 passed, 0 failed

Could you please re-review the current head?

简体中文

@M4n5ter

感谢。我已经处理了最后一项 child filesystem-boundary finding。当前 head 为 3f5443b7f

根因是 filesystem worker 的职责边界不够明确:它只应是 Managed 的 enforcement path;Bypass 与 External execution 既不应进入 worker,也不能从 legacy child mode 重建权限。

修复现在覆盖两层:

  1. bf370bd1a 让 builtin filesystem dispatch 在调用 worker 前直接依据权威 ExecutionBoundary 路由:

    • Managed 必须走 filesystem worker;enforcement 不可用时 fail closed。
    • Bypass 与 External 走所属 surface 注入的 executor。
    • 两条路径都不再查询 child 的 legacy permissionMode
  2. 3f5443b7f 关闭了底层 API 的歧义:

    • FilesystemWorkerClient 现在会拒绝任何传入的 Bypass 或 External boundary。
    • 一旦提供权威 boundary,client 就不能再回退到 permissionProfilemode

回归测试通过 builtin Write 直接复现 inherited-child 的组合:legacy permissionMode: explore 加权威 Bypass/External boundary。两者都会走非 worker 路径;如果直接把任一 boundary 传给 FilesystemWorkerClient,则会在 validation 或进程启动前 fail closed。

Fresh-eye 验证还以有限范围补强了 boundary narrowing、stale linked-child resume、External admission、非交互后代失败、exact-write grant 隔离、authority round-trip 和 prompt response race。它们都保留为独立原子提交,也没有重新引入 generic permission 或 legacy mode 路径。

3f5443b7f 上的验证:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • 全 workspace 串行 npm run test:dist
  • 最后一项 worker-client 修复后的 Runtime:2,706 通过,9 跳过,0 失败
  • Runtime Host:303 通过,0 失败
  • Desktop:2,970 通过,0 失败
  • builtin filesystem-worker 与 client 定向测试:20 通过,0 失败

能否请你基于当前 head 再 review 一次?

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 3f5443b to c4a7062CompareJuly 29, 2026 08:43
@M4n5ter

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed the latest head c4a7062c9. The rebase preserved the 13 follow-up patches; the new final commit only reconciles an AI-provider test fixture.

Re-review outcome

The previously reported child filesystem-boundary mismatch is resolved. Builtin filesystem dispatch now follows the authoritative boundary, and the targeted builtin/client tests pass 20/20.

Request changes. Three correctness blockers and four additional gaps remain.

Blocking correctness findings

1. [P1] A missing exact-write grant still blocks unrelated Bash commands on real Linux

prepareLinuxBashExactWriteTargets now prepares only exact paths declared by the current required_boundary, but the complete durable profile is still passed to bubblewrap:

Every exact-write entry in that profile remains a bind-mount source. If an undeclared exact target or its parent no longer exists, bubblewrap fails before executing the command.

I reproduced this with an unrelated command:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

The added unit test does not catch this because it uses a fake available sandbox manager and never executes the generated bubblewrap command.

This is also the current required-CI failure: Linux sandbox smoke fails 6/7 with the same missing-source error.

The per-invocation Linux mount plan should omit absent undeclared exact entries while safely preparing an exact target that the current invocation declares. This needs a real bubblewrap smoke test for both cases.

2. [P1] Legacy permissionCeiling prevents default Auto sessions from creating executable children

A normal new session still defaults to legacy permissionMode: ask, while Web Research and Implementation definitions use execute. Child creation therefore stores permissionMode: execute with permissionCeiling: ask:

Current-header normalization still treats that legacy ceiling as live authority:

I reproduced the resulting persistence failure:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

This happens before the inherited ExecutionBoundary can govern the child. permissionCeiling should be limited to legacy decoding/migration, not written or enforced for current child sessions. A SQLite-backed child-creation behavior test should cover an Implementation child spawned from the default Auto session.

3. [P1] Narrowing a parent boundary does not revoke descendant background processes

A child Bash run is registered under the child session ID:

The parent boundary transition terminates only the parent session’s shell runs:

A foreground child can start background Bash, return, and leave the process alive. The parent can then narrow from Bypass to Auto, or Auto to Explore, while that descendant process continues with its old authority. The stale-child resume guard prevents a future resume but does not revoke already-live processes.

Boundary narrowing needs lineage-wide revocation of descendant shell runs and backend generations before committing the transition, with regression coverage for a completed child turn that leaves background Bash running.

Additional correctness gap

4. [P2] An Explore-origin session cannot return from Bypass to Auto

For an Explore-origin session, genesis is the managed read-only profile. After switching to Bypass, restoration searches only for a previous non-read-only managed profile:

I reproduced:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

The transition should be total for supported UI states. If Explore sessions may enter Bypass, a missing Auto history should restore the canonical Auto genesis profile. If they must remain read-only, Bypass should be rejected and hidden before the transition.

Maintainability findings

5. [P2] Sandbox containment semantics are duplicated inside SessionManager

The follow-up adds approximately 70 lines of profile, access, path, deny, and protected-metadata containment logic to an already very large runtime coordinator:

Boundary containment is a core contract and will drift if Runtime owns a second implementation. Please expose one canonical Core helper and keep SessionManager as a caller.

6. [P2] The public legacy snapshot exporter can silently omit authoritative boundaries

exportLegacySessionTreeSnapshot accepts required records but an optional boundary map, and silently skips the boundary transfer file when an entry is absent:

The production wrapper currently supplies the map, but the exported public helper still permits a boundary-less session export. Its input should carry paired authority snapshots and require one boundary for every selected session.

7. [P2] The new External-admission regression test verifies source layout, not behavior

The test reads main.ts and uses regular expressions to require a specific helper name, handler layout, and call text:

It can pass without proving that IPC admission rejects External execution, and harmless refactoring can break it. Please replace it with an IPC behavior harness covering compact, resume, regenerate, and plan approval, asserting that runtime execution is not reached.

Validation

On c4a7062c9:

  • npm run build:test passed.
  • Child filesystem builtin/client tests passed, 20/20.
  • The default-Auto executable-child header was rejected in a direct current-header normalization reproduction.
  • Explore → Bypass → Auto failed in an in-memory SQLite reproduction.
  • An unrelated true command failed under real bubblewrap when the profile contained a missing exact-write grant.
  • Local required Linux sandbox smoke failed, 6/7.
  • GitHub typecheck and e2e are green; test is red on the same Linux smoke failure.
简体中文

@Astro-Han

我基于最新 head c4a7062c9 完成了 re-review。Rebase 保留了 13 个 follow-up patch;新增的最后一个 commit 只调整了 AI provider test fixture。

Re-review 结论

此前未关闭的 child filesystem-boundary 不一致已经解决。Builtin filesystem dispatch 现在遵循 authoritative boundary,相关 builtin/client 定向测试 20/20 通过。

仍需 Request changes。目前还有三项 correctness blocker 和四项其它问题。

阻塞性 correctness findings

1. [P1] 失效的 exact-write grant 在真实 Linux 上仍会阻断无关 Bash 命令

prepareLinuxBashExactWriteTargets 现在只准备当前 required_boundary 声明的 exact path,但完整的持久化 profile 仍会传给 bubblewrap:

Profile 中的每个 exact-write entry 仍然会成为 bind-mount source。如果一个未被本次调用声明的 exact target 或其 parent 已不存在,bubblewrap 会在执行 command 前失败。

我使用一条完全无关的命令复现了该问题:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

新增的 unit test 使用 fake available sandbox manager,并未执行生成的 bubblewrap command,因此无法覆盖真实行为。

这也是当前 required CI 的失败原因:Linux sandbox smoke 以相同的 missing-source 错误失败,结果为 6/7。

Linux 每次调用的 mount plan 应忽略不存在且未被当前调用声明的 exact entry;如果当前调用显式声明 exact target,则应安全地准备它。两条路径都需要真实 bubblewrap smoke coverage。

2. [P1] Legacy permissionCeiling 会阻止默认 Auto session 创建 executable child

普通新 session 的 legacy permissionMode 默认仍为 ask,而 Web Research 与 Implementation definition 使用 execute。Child 创建因此会同时写入 permissionMode: executepermissionCeiling: ask

Current-header normalization 仍把 legacy ceiling 当作 live authority:

我复现到的持久化结果为:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

失败发生在 inherited ExecutionBoundary 能够治理 child 之前。permissionCeiling 应仅用于 legacy decode/migration,不应继续写入或验证 current child session。需要通过真实 SQLite child-creation 行为测试覆盖默认 Auto session 创建 Implementation child 的路径。

3. [P1] 收窄 parent boundary 不会撤销 descendant background process

Child Bash run 会记录在 child session ID 下:

Parent boundary transition 只终止 parent session 自身的 shell run:

Foreground child 可以启动 background Bash 后返回,但让进程继续运行。随后 parent 可以从 Bypass 收窄到 Auto,或从 Auto 收窄到 Explore;descendant process 仍保留旧 authority。Stale-child resume guard 只能阻止未来 resume,无法撤销已经存活的进程。

Boundary narrowing 应在提交 transition 前,按 session lineage 撤销所有 descendant shell run 与 backend generation,并增加“child turn 已结束但 background Bash 仍在运行”的 regression coverage。

其它 correctness gap

4. [P2] Explore-origin session 无法从 Bypass 返回 Auto

Explore-origin session 的 genesis 是 managed read-only profile。切换到 Bypass 后,恢复逻辑只查找历史中的 non-read-only managed profile:

我的复现结果为:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

所有受支持的 UI 状态都应拥有完整 transition。如果 Explore session 可以进入 Bypass,那么缺少 Auto history 时应恢复 canonical Auto genesis profile;如果它必须始终保持 read-only,则应在 transition 之前拒绝并隐藏 Bypass。

可维护性 findings

5. [P2] Sandbox containment 语义被重复实现在 SessionManager

Follow-up 在已经非常庞大的 runtime coordinator 中增加了约 70 行 profile、access、path、deny 与 protected-metadata containment 逻辑:

Boundary containment 属于 Core contract。Runtime 保留第二套实现会产生语义漂移。建议在 Core 暴露一个 canonical helper,让 SessionManager 只负责调用。

6. [P2] Public legacy snapshot exporter 可以静默遗漏 authoritative boundary

exportLegacySessionTreeSnapshot 要求提供 records,却把 boundary map 设为 optional;如果某个 entry 不存在,就会静默跳过 boundary transfer file:

当前 production wrapper 的确提供了 map,但导出的 public helper 仍允许生成缺失 boundary 的 session export。其输入应改为成对的 authority snapshot,并要求每个被选择的 session 都有 boundary。

7. [P2] 新增的 External-admission regression test 验证 source layout,而不是行为

该测试读取 main.ts,再用正则要求特定 helper 名称、handler 布局和调用文本:

它无法证明 IPC admission 确实会拒绝 External execution,同时正常重构也会使测试破裂。应替换为 IPC behavior harness,覆盖 compact、resume、regenerate 与 plan approval,并断言 runtime execution 未被调用。

验证

c4a7062c9 上:

  • npm run build:test 通过。
  • Child filesystem builtin/client tests 20/20 通过。
  • Direct current-header normalization 复现到默认 Auto executable-child header 被拒绝。
  • In-memory SQLite 复现到 Explore → Bypass → Auto 失败。
  • 在真实 bubblewrap 下,profile 含有失效 exact-write grant 时,无关的 true command 仍会失败。
  • 本地 required Linux sandbox smoke 失败,6/7。
  • GitHub typechecke2e 通过;test 因相同 Linux smoke 错误失败。

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch 2 times, most recently from 4c0af93 to d01db12CompareJuly 29, 2026 10:43
@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 58fdec7 to 6b82f24CompareJuly 29, 2026 11:52
@Astro-Han
Astro-Han merged commit 0fe34a7 into mainJul 29, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/1564-session-sandbox-boundary branch July 29, 2026 12:00
Astro-Han added a commit that referenced this pull request Jul 29, 2026
#1581 replaced tool permissions with session sandbox boundaries and removed
`PermissionEngine` from `@maka/runtime`, but left this test importing it and
passing a `permissionEngine` dependency that the session-stream deps type no
longer has. `main` has been red since: `tsc -p tsconfig.main.json` fails with
TS2305, which takes `build:main` down and with it the typecheck, test, and e2e
jobs on every branch.
Nothing in production takes a `permissionEngine` any more, and the test's
subject is usage readiness, so the import and the dependency go. No behavioural
change and no replacement needed.
Sign up for freeto 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.

feat: replace per-tool approvals with sandbox boundaries

2 participants

@Astro-Han@M4n5ter
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: replace tool permissions with session sandbox boundaries - #1581

Merged
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary
Jul 29, 2026
Merged

feat: replace tool permissions with session sandbox boundaries#1581
Astro-Han merged 162 commits into
mainfrom
feat/1564-session-sandbox-boundary

Conversation

@Astro-Han

@Astro-HanAstro-Han commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace additional permissions, one-call sandbox escalation, and the live generic tool-approval path with one revisioned, session-scoped ExecutionBoundary authority.
  • Persist genesis boundaries, immutable expansion requests, and applied revisions in the SQLite session metadata store. Approval and boundary advancement commit atomically; stale, duplicate, and concurrently decided requests settle deterministically.
  • Keep the expansion schema no broader than the product needs today: exact/subtree filesystem read/write entries plus session network enablement. Tools report exact sandbox_boundary_required deltas or requires_bypass; Bash diagnostics never parse commands or invent authority.
  • Wire the boundary lifecycle end to end through core, storage, runtime, Runtime Host, session bundles, Desktop/shared UI, TUI, headless/Harbor, and non-interactive CLI. Desktop and TUI expose Auto/Bypass, boundary prompts take over the composer, and Bypass requires an explicit second confirmation.
  • Remove the superseded PermissionEngine matrix, grant ingress, generic permission prompts, and legacy live escalation executors in the same PR so no dual-authority intermediate state ships. Historical codecs and settled audit history remain readable; OS Permission Center behavior is unchanged.

Closes#1564

Verification

  • npm run build — passed across all workspaces.
  • npm run test:dist — passed the complete repository suite with the workspace runner in serial mode, including script contracts (176/176), storage (733 passed, 1 skipped), Runtime (2675 passed, 9 skipped), Runtime Host (212/212), and Desktop (2964/2964).
  • npm run format:check — passed, 1221 files checked.
  • npm run lint — passed, 2304 files checked.
  • npm run typecheck — passed across all workspaces.
  • node --test packages/runtime/dist/__tests__/macos-seatbelt-smoke.test.js packages/runtime/dist/__tests__/filesystem-worker-smoke.test.js — passed (9/9), including exact outside-path expansion and restricted network behavior.
  • npm run e2e -w @maka/desktop -- e2e/sandbox-boundary-takeover.spec.ts — passed (1/1), covering the visible Desktop composer takeover and approval journey.
  • The all-workspace parallel npm test command intermittently exhausted a Runtime Host test's local timing window under machine load. That package passed independently (212/212), and the complete serial repository run above passed; this PR does not broaden into unrelated test-harness timing changes.

Migration and breaking change

  • Legacy ask and execute sessions enter the managed workspace-write boundary; explore enters managed read-only; bypass remains bypass. First access durably records revision 0 without rewriting settled historical records.
  • Pending legacy permission interactions close with host_restarted during recovery because their live continuation authority cannot survive the upgrade.
  • Interactive surfaces now expose only Auto and Bypass. Removed permission modes and per-tool grant flags fail during CLI argument validation.
  • maka run defaults to Auto and cannot interactively expand a boundary, so it fails closed when expansion is requested. Only explicit --yolo creates or resumes a bypass session.
  • Headless/Harbor sessions explicitly use the external boundary; imports and exports preserve the authoritative boundary even though the SQLite database itself is not bundled.

Review focus

  • The SQLite transaction boundary around request settlement and boundary revision advancement, including cross-connection races.
  • The runtime continuation/publication barrier when a sandbox boundary or user question is pending, including durable denial when a turn closes.
  • The cross-surface fail-closed behavior for ordinary expansion requests versus requires_bypass.
  • The branch contains 105 small, reversible commits ordered from contracts and storage through runtime, surfaces, legacy-path removal, and regression coverage.

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 6f15924 to d481739CompareJuly 29, 2026 01:50
@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

Review outcome

Request changes.

I reviewed the final PR head d481739 against the accepted contract in #1564 and the guarantees stated in this PR body. The SQLite transition work, prompt settlement, --yolo protection, boundary persistence, and Linux sandbox tests are meaningful improvements, but several execution paths still violate the central invariants of this change.

The latest rebase and the final d481739 cleanup commit do not change the sandbox semantics described below.

Contract used for this review

The accepted #1564 contract requires:

  • one authoritative, session-scoped ExecutionBoundary;
  • managed execution to fail closed when enforcement is unavailable;
  • an exact, reachable expansion flow for process network and filesystem boundaries;
  • External execution only when an explicit external isolation owner exists;
  • Deep Research to remain internally managed and read-only;
  • child Agents to inherit the parent boundary;
  • non-interactive Auto to exit nonzero when an unavoidable boundary requirement cannot be resolved; and
  • session bundles to restore the authoritative boundary.

The alternative proposals to enable network by default, automatically fall through to Bypass, or treat user-provided paths as implicit authorization were explicitly rejected in the issue discussion. These findings are evaluated against the accepted issue body, not those alternatives.

Blocking findings

1. [P1] Managed filesystem tools fail open when the filesystem worker is unavailable

Desktop and CLI conditionally omit the filesystem worker when the platform cannot provide the built-in worker sandbox. buildBuiltinTools then falls back to createLocalWorkspaceExecutor, and Write/Edit/Read execute on the host instead of rejecting managed execution.

Relevant paths:

I reproduced this on the final head: a Write call under an explore/read-only boundary successfully created a file when no worker was supplied.

Managed execution must return an enforcement-unavailable failure before reaching the host executor. The host path should only be reachable for an explicit Bypass or harness-owned External boundary.

2. [P1] The first process-network expansion has no valid request path

Auto starts with restricted process network, but Bash has no declarative network requirement. A denied command returns only a likely sandbox-denial signal, without sandbox_boundary_required or a concrete network expansion:

Runtime guidance simultaneously states that the Agent must not infer an expansion and may request one only after a tool returns an exact expansion:

I reproduced an EPERM network denial with sandboxType: linux; the failure contained no required expansion. Commands such as npm install, git pull, and curl therefore cannot reach the session-level network approval flow required by #1564.

This needs a declarative, non-authorizing process-network requirement or an equally reliable backend signal that can produce the exact expansion without parsing command text.

3. [P1] An External session can resume in Desktop/TUI as Auto while Bash runs without a Maka sandbox

Imported session bundles can restore an External boundary. Bash treats both Bypass and External as instructions to skip the Maka sandbox:

Desktop maps every non-Bypass boundary to Auto, while TUI session switching continues to project the legacy permissionMode:

maka run correctly rejects this resume path, but ordinary Desktop and interactive TUI do not. The result is an Auto-labelled session executing host Bash without the external harness that supposedly owns isolation.

External sessions must be rejected by ordinary interactive surfaces unless an explicit external-isolation owner is injected. External must also never be presented as Auto.

Additional correctness gaps

4. [P2] Deep Research can request and receive write or network expansion

Deep Research starts with a managed read-only profile, but Desktop still includes the complete builtin surface and unconditionally exposes request_sandbox_boundary:

Storage applies an approved expansion to any managed profile, including read-only:

I reproduced approval of a network expansion on a Deep Research session. The resulting profile was still named read-only, but its network state was enabled.

The Deep Research surface should omit mutation tools and the boundary-request tool, and its internal read-only boundary must not be expandable into write or process-network authority.

5. [P2] Child boundary persistence is fixed, but filesystem execution does not fully inherit Bypass or External

The parent boundary is now persisted into the child correctly. However, the child header still uses the Agent definition’s legacy permission mode, and the filesystem worker only consumes managed boundaries:

For an inherited Bypass or External boundary, filesystem execution falls back to the child definition’s legacy profile. The same child can therefore run Bash according to the inherited boundary while Read/Write/Edit follow a different authority.

Boundary handling in the filesystem client should be exhaustive: managed, bypass, and external must each have explicit semantics, with no fallback to permissionMode.

6. [P2] Non-interactive Auto can still return exit code 0 after an unresolved boundary failure

maka run does not register the boundary-request tool. It marks the command as failed only after receiving a sandbox_boundary_request event:

A filesystem tool can instead return sandbox_boundary_required as an ordinary structured tool failure. If the model then produces a normal final answer explaining that it could not complete the task, the invocation remains completed and maka run returns 0.

An unresolved boundary requirement must become a terminal non-interactive invocation outcome, independently of whether a request event was published.

7. [P2] A session bundle does not read its header and boundary from one SQLite snapshot

The bundle exporter writes selected session metadata and the selected boundary through two independent exporter calls:

A concurrent Auto/Bypass transition between those reads can export a header from one revision and a boundary from another. Import then accepts both as the new genesis state.

Storage should provide one read transaction that returns an immutable portable { header, boundary } snapshot before either transfer file is written.

Implementation-quality concern

The Runtime public boundary contract still permits the authoritative reader to be absent:

All current first-party production call sites appear to provide the reader, so I am not treating this as a separate exploit. However, the public API still silently reconstructs authority from header.permissionMode, which preserves the dual-authority fallback that this PR claims to remove.

The boundary reader should be required. Interactive expansion support can be represented separately as an explicit enabled/disabled capability.

There are also several source-regex and collaborator-call tests that lock implementation shape rather than public behavior. I do not use those as the primary basis for this review, but they should be replaced with behavioral coverage while these paths are being corrected.

Validation

On final head d481739:

  • npm run build:test passed.
  • Linux sandbox smoke passed, 7/7.
  • Linux filesystem-worker smoke passed, 2/2.
  • SQLite session metadata tests passed, 30/30.
  • git diff --check a454b9a..d481739 passed.
  • GitHub typecheck, test, and e2e checks are green.

The green suite validates the supported sandbox path, but it does not cover the fail-open worker-unavailable path or the cross-surface inconsistencies above.

简体中文

审查结论

Request changes。

我基于 #1564 的已接受契约与本 PR body 声明的保证,对最终 head d481739 进行了审查。SQLite transition、Prompt settlement、--yolo 保护、boundary 持久化和 Linux sandbox 测试都是有价值的改进,但若干执行路径仍违反这次改动的核心不变量。

最新 rebase 与最终的 d481739 cleanup commit 没有改变下述 sandbox 语义。

本次审查采用的契约

已接受的 #1564 契约要求:

  • 每个 session 只有一个 authoritative、session-scoped ExecutionBoundary
  • enforcement 不可用时,managed execution 必须 fail closed;
  • process network 与 filesystem boundary 必须具有精确且可达的 expansion 流程;
  • External execution 只能在存在显式 external isolation owner 时使用;
  • Deep Research 必须保持内部 managed read-only;
  • 子 Agent 必须继承父 session boundary;
  • 非交互 Auto 遇到无法解决且不可避免的 boundary requirement 时必须非零退出;
  • session bundle 必须恢复 authoritative boundary。

Issue 讨论中关于默认启用 network、自动退化到 Bypass,以及把用户给出的路径视为隐式授权的替代提案已经被明确拒绝。以下 findings 以已接受的 issue body 为准,不采用这些替代提案。

阻塞问题

1. [P1] Filesystem worker 不可用时,managed filesystem tool 会 fail open

当平台无法提供内置 worker sandbox 时,Desktop 与 CLI 会有条件地省略 filesystem worker。buildBuiltinTools 随后退回 createLocalWorkspaceExecutor,导致 Write/Edit/Read 在 host 上执行,而不是拒绝 managed execution。

相关路径:

我在最终 head 上完成了复现:未提供 worker 时,explore/read-only boundary 下的 Write 成功创建了文件。

Managed execution 必须在进入 host executor 前返回 enforcement-unavailable failure。Host 路径只能由显式 Bypass 或 harness-owned External boundary 访问。

2. [P1] 首次 process-network expansion 没有合法的请求路径

Auto 默认限制 process network,但 Bash 没有声明 network requirement 的字段。命令被拒绝时只返回可能的 sandbox-denial signal,不包含 sandbox_boundary_required 或具体 network expansion:

Runtime guidance 同时要求 Agent 不得推断 expansion,且只有在工具返回精确 expansion 后才能请求:

我复现了带有 sandboxType: linuxEPERM network denial,但 failure 中没有 required expansion。因此 npm installgit pullcurl 等命令无法进入 #1564 要求的 session-level network approval 流程。

这里需要一个声明式且本身不授予权限的 process-network requirement,或同样可靠的 backend signal,以便在不解析 command text 的情况下生成精确 expansion。

3. [P1] External session 可以在 Desktop/TUI 中以 Auto 恢复,同时 Bash 不受 Maka sandbox 约束

导入的 session bundle 可以恢复 External boundary。Bash 将 Bypass 和 External 都视为跳过 Maka sandbox 的指令:

Desktop 把所有非 Bypass boundary 映射为 Auto,而 TUI session switching 继续投影 legacy permissionMode

maka run 已经正确拒绝该 resume 路径,但普通 Desktop 与交互式 TUI 没有拒绝。最终结果是:一个标记为 Auto 的 session 在缺少原定 external harness 的情况下执行 host Bash。

除非注入显式 external-isolation owner,否则普通交互式 surface 必须拒绝 External session。External 也绝不能显示为 Auto。

其他正确性缺口

4. [P2] Deep Research 可以请求并获得 write 或 network expansion

Deep Research 从 managed read-only profile 开始,但 Desktop 仍包含完整 builtin surface,并无条件暴露 request_sandbox_boundary

Storage 会把已批准的 expansion 应用到任意 managed profile,包括 read-only:

我复现了 Deep Research session 的 network expansion approval。结果 profile 仍名为 read-only,但 network state 已变为 enabled

Deep Research surface 应移除 mutation tool 与 boundary-request tool,其内部 read-only boundary 也不应扩张为 write 或 process-network authority。

5. [P2] Child boundary 已正确持久化,但 filesystem execution 没有完整继承 Bypass 或 External

Parent boundary 现在已经能正确持久化到 child。但 child header 仍使用 Agent definition 的 legacy permission mode,而 filesystem worker 只消费 managed boundary:

对于继承的 Bypass 或 External boundary,filesystem execution 会退回 child definition 的 legacy profile。同一个 child 因而可能让 Bash 遵循 inherited boundary,却让 Read/Write/Edit 遵循另一套 authority。

Filesystem client 应穷举处理 managed、bypass 与 external,不能再退回 permissionMode

6. [P2] 非交互 Auto 在 boundary failure 未解决后仍可能返回退出码 0

maka run 不注册 boundary-request tool。它只有在收到 sandbox_boundary_request event 后才把命令标记为失败:

Filesystem tool 也可能只把 sandbox_boundary_required 作为普通 structured tool failure 返回。如果 model 随后正常输出无法完成任务的说明,invocation 仍是 completed,maka run 最终返回 0。

未解决的 boundary requirement 必须成为非交互 invocation 的 terminal failure,不能依赖是否发布了 request event。

7. [P2] Session bundle 没有从同一个 SQLite snapshot 读取 header 与 boundary

Bundle exporter 通过两个独立 exporter 调用写入 selected session metadata 和 selected boundary:

如果两次读取之间发生并发 Auto/Bypass transition,export 可能得到一个 revision 的 header 和另一个 revision 的 boundary。Import 随后会把两者共同接受为新的 genesis state。

Storage 应在一个 read transaction 内返回不可变的 portable { header, boundary } snapshot,然后再写两个 transfer file。

实现质量问题

Runtime 的 public boundary contract 仍允许 authoritative reader 缺失:

当前 first-party production call site 看起来都提供了 reader,因此我没有把它作为独立 exploit。但 public API 仍会从 header.permissionMode 静默重建 authority,保留了本 PR 声称要删除的 dual-authority fallback。

Boundary reader 应成为 required dependency。Interactive expansion support 可以单独表示为显式的 enabled/disabled capability。

此外,当前还有若干 source-regex 与 collaborator-call test,它们锁定 implementation shape,而不是验证 public behavior。我没有把这些测试作为本次 Request changes 的主要依据,但在修复上述路径时应将其替换为 behavioral coverage。

验证

最终 head d481739

  • npm run build:test 通过。
  • Linux sandbox smoke 通过,7/7。
  • Linux filesystem-worker smoke 通过,2/2。
  • SQLite session metadata tests 通过,30/30。
  • git diff --check a454b9a..d481739 通过。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

当前绿色测试覆盖了受支持的 sandbox 路径,但没有覆盖上述 worker-unavailable fail-open 路径与跨 surface 不一致。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

Thank you for the detailed review. I reproduced the reported paths and updated the PR to head 7abc0b9de.

All seven findings have now been addressed:

  1. Managed filesystem fail-open — fixed in 48ca2f864. Managed Read/Write/Edit now fail closed when the filesystem sandbox is unavailable; the host executor is reserved for explicit Bypass or External authority.

  2. Unreachable first process-network expansion — fixed in 05585da92. Bash now declares a non-authorizing sandbox capability requirement, allowing the runtime to produce an exact network expansion without parsing command text.

  3. External sessions on local interactive surfaces — fixed across 7823ab5d4 and 7abc0b9de. TUI rejects resuming External sessions without their owning harness. Desktop may display imported External history, but it is non-interactive: the composer and permission-mode controls are unavailable, permission commands are omitted, and External is never presented as Auto. Boundary loading also fails closed so Auto cannot flash before the authority snapshot arrives.

  4. Deep Research expansion and mutation surface — fixed in 3d347d48d, with the read-only tool-surface contract strengthened in c384056c5. Deep Research no longer receives mutation or boundary-expansion tools.

  5. Child boundary inheritance — fixed in 62581d26f and f04db4bec. Child admission and filesystem execution now use the inherited ExecutionBoundary explicitly, with managed, bypass, and external paths handled deliberately and child tool surfaces defined by explicit allowlists.

  6. Non-interactive unresolved boundary returning success — fixed in 093d9fad2. maka run now exits nonzero for an unresolved boundary requirement whether it appears as a request event or a structured tool failure.

  7. Non-atomic bundle boundary snapshot — fixed in 1715039e9. Session header and execution boundary are now read from one storage transaction before transfer files are written.

The implementation-quality concern was also addressed. 581f73ec5 removed the legacy boundary fallback, and fa4314bfe now makes readExecutionBoundary a required Runtime/AiSdkBackend dependency. Missing authority is rejected instead of reconstructing External or managed authority from legacy permissionMode. Tests that intentionally exercise an externally isolated raw runtime now opt into that authority explicitly.

For the Desktop follow-up, 7abc0b9de adds behavioral coverage for managed, bypass, loading, and external boundary projections, plus command-surface coverage. I did not broaden this follow-up into a rewrite of unrelated source-contract tests.

Validation on 7abc0b9de:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • full npm run test:dist across all workspaces
  • Runtime: 2,697 passed, 9 skipped, 0 failed
  • Desktop: 2,968 passed, 0 failed
  • GitHub typecheck, test, and e2e: all green

Could you please re-review the current head?

简体中文

感谢这次详细审查。我复现了报告中的路径,并已把 PR 更新到 head 7abc0b9de

七项 findings 现已全部处理:

  1. Managed filesystem fail-open — 已在 48ca2f864 修复。Filesystem sandbox 不可用时,managed Read/Write/Edit 现在会 fail closed;host executor 只供显式 Bypass 或 External authority 使用。

  2. 首次 process-network expansion 不可达 — 已在 05585da92 修复。Bash 现在声明一个本身不授予权限的 sandbox capability requirement,使 Runtime 无需解析 command text 就能生成精确的 network expansion。

  3. External session 被本地交互 surface 执行 — 已通过 7823ab5d47abc0b9de 修复。TUI 会拒绝在缺少所属 harness 时恢复 External session。Desktop 可以查看导入的 External 历史,但保持不可交互:composer 和 permission-mode control 不可用,permission command 不会出现,External 也绝不会显示为 Auto。Boundary 加载阶段同样 fail closed,避免 authority snapshot 到达前短暂显示 Auto。

  4. Deep Research expansion 与 mutation surface — 已在 3d347d48d 修复,并由 c384056c5 加强 read-only tool-surface 契约。Deep Research 不再获得 mutation 或 boundary-expansion tool。

  5. Child boundary inheritance — 已在 62581d26ff04db4bec 修复。Child admission 与 filesystem execution 现在显式使用继承的 ExecutionBoundary,managed、bypass、external 均有明确语义,child tool surface 由显式 allowlist 定义。

  6. 非交互 unresolved boundary 错误返回成功 — 已在 093d9fad2 修复。无论 boundary requirement 来自 request event 还是 structured tool failure,maka run 都会非零退出。

  7. Bundle boundary snapshot 非原子 — 已在 1715039e9 修复。Session header 与 execution boundary 现在会在同一个 storage transaction 中读取,然后才写入 transfer files。

实现质量问题也已处理。581f73ec5 删除了 legacy boundary fallback,fa4314bfe 则将 readExecutionBoundary 设为 Runtime/AiSdkBackend 的 required dependency。缺少 authority 时现在会直接拒绝,不再从 legacy permissionMode 重建 External 或 managed authority。需要直接测试 externally isolated raw runtime 的测试也会显式选择该 authority。

Desktop follow-up 7abc0b9de 增加了 managed、bypass、loading、external boundary projection 的行为测试,以及 command surface 测试。此次 follow-up 没有盲目扩大到重写无关的 source-contract test。

7abc0b9de 上的验证结果:

  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • 全 workspace npm run test:dist
  • Runtime:2,697 通过,9 跳过,0 失败
  • Desktop:2,968 通过,0 失败
  • GitHub typecheckteste2e:全部绿色

能否请你基于当前 head 再 review 一次?

@M4n5ter

M4n5ter commented Jul 29, 2026

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed head 7abc0b9de and reran the relevant targeted tests.

Re-review outcome

The following findings are resolved:

  1. Managed filesystem execution now fails closed when the worker sandbox is unavailable.
  2. Bash can declare an exact process-network boundary requirement without parsing command text.
  3. External sessions are rejected by TUI and remain non-interactive in Desktop.
  4. Deep Research now receives a read-only tool surface without boundary-expansion tools.
  5. Non-interactive unresolved boundary failures now produce a nonzero exit.
  6. Session bundle metadata and boundary are read from one SQLite authority snapshot.
  7. readExecutionBoundary is now required, and the Runtime legacy boundary fallback has been removed.

One finding remains open.

[P2] Child filesystem execution still does not inherit Bypass or External semantics

The parent ExecutionBoundary is persisted into the child, but ordinary child creation still stores the Agent definition’s legacy permission mode:

The filesystem worker only consumes the supplied boundary when its kind is managed. For Bypass or External, it falls back to permissionProfile or the child’s legacy mode:

Bash, by contrast, explicitly skips the Maka sandbox for the inherited Bypass or External boundary:

I reproduced the remaining mismatch on 7abc0b9de by executing an outside-workspace filesystem write with a Bypass or External boundary and a legacy child mode:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

The worker process was never launched. The operation was rejected by the legacy profile selected before sandbox execution.

The explicit child tool allowlists correctly constrain which tools a child receives, but they do not make those tools use the inherited boundary. An implementation child can therefore run Bash according to inherited Bypass/External authority while Read/Write/Edit continue to use a different filesystem authority.

Please make filesystem authority selection exhaustive over all ExecutionBoundary kinds. Once an authoritative boundary is supplied, the filesystem client should not fall back to permissionMode. A regression test should exercise a real inherited child Bypass/External boundary through the builtin filesystem tool path.

Validation

On 7abc0b9de:

  • npm run build:test passed.
  • Runtime targeted tests passed, 100/100.
  • CLI targeted tests passed, 72/72.
  • Storage targeted tests passed, 60/60.
  • Desktop targeted tests passed, 13/13.
  • Linux sandbox and filesystem-worker smoke tests passed, 9/9.
  • GitHub typecheck, test, and e2e checks are green.

I did not find another blocker in the follow-up scope. The previous findings can remain resolved; only the child filesystem-boundary finding remains open.

简体中文

@Astro-Han

我基于 head 7abc0b9de 完成了 re-review,并重新运行了相关定向测试。

Re-review 结论

以下 findings 已确认 resolved:

  1. Filesystem worker sandbox 不可用时,managed filesystem execution 现在会 fail closed。
  2. Bash 现在可以在不解析 command text 的情况下声明精确的 process-network boundary requirement。
  3. TUI 会拒绝 External session,Desktop 中的 External session 保持不可交互。
  4. Deep Research 现在只获得 read-only tool surface,不再获得 boundary-expansion tool。
  5. 非交互 unresolved boundary failure 现在会产生非零退出码。
  6. Session bundle metadata 与 boundary 现在从同一个 SQLite authority snapshot 读取。
  7. readExecutionBoundary 已成为 required dependency,Runtime legacy boundary fallback 也已删除。

仍有一项 finding 未关闭。

[P2] Child filesystem execution 仍未继承 Bypass 或 External 语义

Parent ExecutionBoundary 已经持久化到 child,但普通 child 创建仍会把 Agent definition 的 legacy permission mode 写入 header:

Filesystem worker 只有在 boundary kind 为 managed 时才消费传入的 boundary。对于 Bypass 或 External,它仍会退回 permissionProfile 或 child legacy mode

Bash 则会针对 inherited Bypass 或 External boundary 显式跳过 Maka sandbox:

我在 7abc0b9de 上使用 Bypass/External boundary 与 legacy child mode 执行 workspace 外 filesystem write,仍能复现该不一致:

{"kind":"bypass","reason":"path_denied","stage":"validation","calls":0}
{"kind":"external","reason":"path_denied","stage":"validation","calls":0}

Worker process 没有启动。操作在 sandbox execution 之前就被 legacy profile 拒绝。

显式 child tool allowlist 正确限制了 child 可以获得哪些工具,但没有让这些工具使用 inherited boundary。因此 implementation child 仍可能让 Bash 遵循 inherited Bypass/External authority,而 Read/Write/Edit 使用另一套 filesystem authority。

请对所有 ExecutionBoundary kind 做穷举的 filesystem authority selection。一旦提供 authoritative boundary,filesystem client 就不应再退回 permissionMode。Regression test 应通过 builtin filesystem tool 路径,覆盖真实 inherited child Bypass/External boundary。

验证

7abc0b9de 上:

  • npm run build:test 通过。
  • Runtime 定向测试通过,100/100。
  • CLI 定向测试通过,72/72。
  • Storage 定向测试通过,60/60。
  • Desktop 定向测试通过,13/13。
  • Linux sandbox 与 filesystem-worker smoke tests 通过,9/9。
  • GitHub typecheck、test 与 e2e checks 均为绿色。

在本次 follow-up 范围内没有发现其他 blocker。此前其余 findings 可以保持 resolved;目前只剩 child filesystem-boundary finding 未关闭。

@Astro-Han

Copy link
Copy Markdown
ContributorAuthor
English

@M4n5ter

Thank you. I addressed the remaining child filesystem-boundary finding. The current head is 3f5443b7f.

The root cause was that the filesystem worker boundary was not explicit enough: it is a managed-only enforcement path, while Bypass and External execution must never be projected into it or reconstructed from a legacy child mode.

The fix now covers both layers:

  1. bf370bd1a makes builtin filesystem dispatch depend on the authoritative ExecutionBoundary before any worker call:

    • Managed routes through the filesystem worker and fails closed when enforcement is unavailable.
    • Bypass and External route through the executor supplied by their owning surface.
    • Neither path consults the child’s legacy permissionMode.
  2. 3f5443b7f closes the lower-level API ambiguity:

    • FilesystemWorkerClient now rejects any supplied Bypass or External boundary.
    • Once an authoritative boundary is supplied, the client can no longer fall back to permissionProfile or mode.

The regression coverage reproduces the inherited-child shape directly through builtin Write: legacy permissionMode: explore combined with authoritative Bypass and External boundaries. Both use the non-worker path, while direct attempts to pass either boundary into FilesystemWorkerClient fail before validation or process launch.

Fresh-eye validation also added bounded hardening around boundary narrowing, stale linked-child resume, External admission, descendant non-interactive failures, exact-write grant isolation, authority round-trips, and prompt response races. These remain separate atomic commits and do not reintroduce the generic permission or legacy mode paths.

Validation on 3f5443b7f:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • full serial npm run test:dist across all workspaces
  • Runtime after the final worker-client change: 2,706 passed, 9 skipped, 0 failed
  • Runtime Host: 303 passed, 0 failed
  • Desktop: 2,970 passed, 0 failed
  • targeted builtin filesystem-worker and client tests: 20 passed, 0 failed

Could you please re-review the current head?

简体中文

@M4n5ter

感谢。我已经处理了最后一项 child filesystem-boundary finding。当前 head 为 3f5443b7f

根因是 filesystem worker 的职责边界不够明确:它只应是 Managed 的 enforcement path;Bypass 与 External execution 既不应进入 worker,也不能从 legacy child mode 重建权限。

修复现在覆盖两层:

  1. bf370bd1a 让 builtin filesystem dispatch 在调用 worker 前直接依据权威 ExecutionBoundary 路由:

    • Managed 必须走 filesystem worker;enforcement 不可用时 fail closed。
    • Bypass 与 External 走所属 surface 注入的 executor。
    • 两条路径都不再查询 child 的 legacy permissionMode
  2. 3f5443b7f 关闭了底层 API 的歧义:

    • FilesystemWorkerClient 现在会拒绝任何传入的 Bypass 或 External boundary。
    • 一旦提供权威 boundary,client 就不能再回退到 permissionProfilemode

回归测试通过 builtin Write 直接复现 inherited-child 的组合:legacy permissionMode: explore 加权威 Bypass/External boundary。两者都会走非 worker 路径;如果直接把任一 boundary 传给 FilesystemWorkerClient,则会在 validation 或进程启动前 fail closed。

Fresh-eye 验证还以有限范围补强了 boundary narrowing、stale linked-child resume、External admission、非交互后代失败、exact-write grant 隔离、authority round-trip 和 prompt response race。它们都保留为独立原子提交,也没有重新引入 generic permission 或 legacy mode 路径。

3f5443b7f 上的验证:

  • npm run build
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • 全 workspace 串行 npm run test:dist
  • 最后一项 worker-client 修复后的 Runtime:2,706 通过,9 跳过,0 失败
  • Runtime Host:303 通过,0 失败
  • Desktop:2,970 通过,0 失败
  • builtin filesystem-worker 与 client 定向测试:20 通过,0 失败

能否请你基于当前 head 再 review 一次?

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 3f5443b to c4a7062CompareJuly 29, 2026 08:43
@M4n5ter

Copy link
Copy Markdown
Member
English

@Astro-Han

I re-reviewed the latest head c4a7062c9. The rebase preserved the 13 follow-up patches; the new final commit only reconciles an AI-provider test fixture.

Re-review outcome

The previously reported child filesystem-boundary mismatch is resolved. Builtin filesystem dispatch now follows the authoritative boundary, and the targeted builtin/client tests pass 20/20.

Request changes. Three correctness blockers and four additional gaps remain.

Blocking correctness findings

1. [P1] A missing exact-write grant still blocks unrelated Bash commands on real Linux

prepareLinuxBashExactWriteTargets now prepares only exact paths declared by the current required_boundary, but the complete durable profile is still passed to bubblewrap:

Every exact-write entry in that profile remains a bind-mount source. If an undeclared exact target or its parent no longer exists, bubblewrap fails before executing the command.

I reproduced this with an unrelated command:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

The added unit test does not catch this because it uses a fake available sandbox manager and never executes the generated bubblewrap command.

This is also the current required-CI failure: Linux sandbox smoke fails 6/7 with the same missing-source error.

The per-invocation Linux mount plan should omit absent undeclared exact entries while safely preparing an exact target that the current invocation declares. This needs a real bubblewrap smoke test for both cases.

2. [P1] Legacy permissionCeiling prevents default Auto sessions from creating executable children

A normal new session still defaults to legacy permissionMode: ask, while Web Research and Implementation definitions use execute. Child creation therefore stores permissionMode: execute with permissionCeiling: ask:

Current-header normalization still treats that legacy ceiling as live authority:

I reproduced the resulting persistence failure:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

This happens before the inherited ExecutionBoundary can govern the child. permissionCeiling should be limited to legacy decoding/migration, not written or enforced for current child sessions. A SQLite-backed child-creation behavior test should cover an Implementation child spawned from the default Auto session.

3. [P1] Narrowing a parent boundary does not revoke descendant background processes

A child Bash run is registered under the child session ID:

The parent boundary transition terminates only the parent session’s shell runs:

A foreground child can start background Bash, return, and leave the process alive. The parent can then narrow from Bypass to Auto, or Auto to Explore, while that descendant process continues with its old authority. The stale-child resume guard prevents a future resume but does not revoke already-live processes.

Boundary narrowing needs lineage-wide revocation of descendant shell runs and backend generations before committing the transition, with regression coverage for a completed child turn that leaves background Bash running.

Additional correctness gap

4. [P2] An Explore-origin session cannot return from Bypass to Auto

For an Explore-origin session, genesis is the managed read-only profile. After switching to Bypass, restoration searches only for a previous non-read-only managed profile:

I reproduced:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

The transition should be total for supported UI states. If Explore sessions may enter Bypass, a missing Auto history should restore the canonical Auto genesis profile. If they must remain read-only, Bypass should be rejected and hidden before the transition.

Maintainability findings

5. [P2] Sandbox containment semantics are duplicated inside SessionManager

The follow-up adds approximately 70 lines of profile, access, path, deny, and protected-metadata containment logic to an already very large runtime coordinator:

Boundary containment is a core contract and will drift if Runtime owns a second implementation. Please expose one canonical Core helper and keep SessionManager as a caller.

6. [P2] The public legacy snapshot exporter can silently omit authoritative boundaries

exportLegacySessionTreeSnapshot accepts required records but an optional boundary map, and silently skips the boundary transfer file when an entry is absent:

The production wrapper currently supplies the map, but the exported public helper still permits a boundary-less session export. Its input should carry paired authority snapshots and require one boundary for every selected session.

7. [P2] The new External-admission regression test verifies source layout, not behavior

The test reads main.ts and uses regular expressions to require a specific helper name, handler layout, and call text:

It can pass without proving that IPC admission rejects External execution, and harmless refactoring can break it. Please replace it with an IPC behavior harness covering compact, resume, regenerate, and plan approval, asserting that runtime execution is not reached.

Validation

On c4a7062c9:

  • npm run build:test passed.
  • Child filesystem builtin/client tests passed, 20/20.
  • The default-Auto executable-child header was rejected in a direct current-header normalization reproduction.
  • Explore → Bypass → Auto failed in an in-memory SQLite reproduction.
  • An unrelated true command failed under real bubblewrap when the profile contained a missing exact-write grant.
  • Local required Linux sandbox smoke failed, 6/7.
  • GitHub typecheck and e2e are green; test is red on the same Linux smoke failure.
简体中文

@Astro-Han

我基于最新 head c4a7062c9 完成了 re-review。Rebase 保留了 13 个 follow-up patch;新增的最后一个 commit 只调整了 AI provider test fixture。

Re-review 结论

此前未关闭的 child filesystem-boundary 不一致已经解决。Builtin filesystem dispatch 现在遵循 authoritative boundary,相关 builtin/client 定向测试 20/20 通过。

仍需 Request changes。目前还有三项 correctness blocker 和四项其它问题。

阻塞性 correctness findings

1. [P1] 失效的 exact-write grant 在真实 Linux 上仍会阻断无关 Bash 命令

prepareLinuxBashExactWriteTargets 现在只准备当前 required_boundary 声明的 exact path,但完整的持久化 profile 仍会传给 bubblewrap:

Profile 中的每个 exact-write entry 仍然会成为 bind-mount source。如果一个未被本次调用声明的 exact target 或其 parent 已不存在,bubblewrap 会在执行 command 前失败。

我使用一条完全无关的命令复现了该问题:

{"command":"true","result":"failed","stderr":"bwrap: Can't find source path .../removed-parent/stale.txt: No such file or directory"}

新增的 unit test 使用 fake available sandbox manager,并未执行生成的 bubblewrap command,因此无法覆盖真实行为。

这也是当前 required CI 的失败原因:Linux sandbox smoke 以相同的 missing-source 错误失败,结果为 6/7。

Linux 每次调用的 mount plan 应忽略不存在且未被当前调用声明的 exact entry;如果当前调用显式声明 exact target,则应安全地准备它。两条路径都需要真实 bubblewrap smoke coverage。

2. [P1] Legacy permissionCeiling 会阻止默认 Auto session 创建 executable child

普通新 session 的 legacy permissionMode 默认仍为 ask,而 Web Research 与 Implementation definition 使用 execute。Child 创建因此会同时写入 permissionMode: executepermissionCeiling: ask

Current-header normalization 仍把 legacy ceiling 当作 live authority:

我复现到的持久化结果为:

{"result":"rejected","message":"Invalid session header for session child-session: malformed fields"}

失败发生在 inherited ExecutionBoundary 能够治理 child 之前。permissionCeiling 应仅用于 legacy decode/migration,不应继续写入或验证 current child session。需要通过真实 SQLite child-creation 行为测试覆盖默认 Auto session 创建 Implementation child 的路径。

3. [P1] 收窄 parent boundary 不会撤销 descendant background process

Child Bash run 会记录在 child session ID 下:

Parent boundary transition 只终止 parent session 自身的 shell run:

Foreground child 可以启动 background Bash 后返回,但让进程继续运行。随后 parent 可以从 Bypass 收窄到 Auto,或从 Auto 收窄到 Explore;descendant process 仍保留旧 authority。Stale-child resume guard 只能阻止未来 resume,无法撤销已经存活的进程。

Boundary narrowing 应在提交 transition 前,按 session lineage 撤销所有 descendant shell run 与 backend generation,并增加“child turn 已结束但 background Bash 仍在运行”的 regression coverage。

其它 correctness gap

4. [P2] Explore-origin session 无法从 Bypass 返回 Auto

Explore-origin session 的 genesis 是 managed read-only profile。切换到 Bypass 后,恢复逻辑只查找历史中的 non-read-only managed profile:

我的复现结果为:

{"initial":"managed/read-only","next":"bypass","restoreError":"Managed sandbox boundary history is missing: session-1"}

所有受支持的 UI 状态都应拥有完整 transition。如果 Explore session 可以进入 Bypass,那么缺少 Auto history 时应恢复 canonical Auto genesis profile;如果它必须始终保持 read-only,则应在 transition 之前拒绝并隐藏 Bypass。

可维护性 findings

5. [P2] Sandbox containment 语义被重复实现在 SessionManager

Follow-up 在已经非常庞大的 runtime coordinator 中增加了约 70 行 profile、access、path、deny 与 protected-metadata containment 逻辑:

Boundary containment 属于 Core contract。Runtime 保留第二套实现会产生语义漂移。建议在 Core 暴露一个 canonical helper,让 SessionManager 只负责调用。

6. [P2] Public legacy snapshot exporter 可以静默遗漏 authoritative boundary

exportLegacySessionTreeSnapshot 要求提供 records,却把 boundary map 设为 optional;如果某个 entry 不存在,就会静默跳过 boundary transfer file:

当前 production wrapper 的确提供了 map,但导出的 public helper 仍允许生成缺失 boundary 的 session export。其输入应改为成对的 authority snapshot,并要求每个被选择的 session 都有 boundary。

7. [P2] 新增的 External-admission regression test 验证 source layout,而不是行为

该测试读取 main.ts,再用正则要求特定 helper 名称、handler 布局和调用文本:

它无法证明 IPC admission 确实会拒绝 External execution,同时正常重构也会使测试破裂。应替换为 IPC behavior harness,覆盖 compact、resume、regenerate 与 plan approval,并断言 runtime execution 未被调用。

验证

c4a7062c9 上:

  • npm run build:test 通过。
  • Child filesystem builtin/client tests 20/20 通过。
  • Direct current-header normalization 复现到默认 Auto executable-child header 被拒绝。
  • In-memory SQLite 复现到 Explore → Bypass → Auto 失败。
  • 在真实 bubblewrap 下,profile 含有失效 exact-write grant 时,无关的 true command 仍会失败。
  • 本地 required Linux sandbox smoke 失败,6/7。
  • GitHub typechecke2e 通过;test 因相同 Linux smoke 错误失败。

@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch 2 times, most recently from 4c0af93 to d01db12CompareJuly 29, 2026 10:43
@Astro-Han
Astro-Hanforce-pushed the feat/1564-session-sandbox-boundary branch from 58fdec7 to 6b82f24CompareJuly 29, 2026 11:52
@Astro-Han
Astro-Han merged commit 0fe34a7 into mainJul 29, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the feat/1564-session-sandbox-boundary branch July 29, 2026 12:00
Astro-Han added a commit that referenced this pull request Jul 29, 2026
#1581 replaced tool permissions with session sandbox boundaries and removed
`PermissionEngine` from `@maka/runtime`, but left this test importing it and
passing a `permissionEngine` dependency that the session-stream deps type no
longer has. `main` has been red since: `tsc -p tsconfig.main.json` fails with
TS2305, which takes `build:main` down and with it the typecheck, test, and e2e
jobs on every branch.
Nothing in production takes a `permissionEngine` any more, and the test's
subject is usage readiness, so the import and the dependency go. No behavioural
change and no replacement needed.
Sign up for freeto 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.

feat: replace per-tool approvals with sandbox boundaries

2 participants

@Astro-Han@M4n5ter