Files
fusion/docs/sandbox.md
Fusion Agent bfaa0f42da FN-158: enforce workspace multi-repo merge boundaries
Support workspace tasks across a shared root with scope-driven repositories and verifiable merge gates.

- Route task work through one workspace directory with per-repository acquisition and isolation.
- Add sandbox session policies and per-repository verification command handling.
- Enforce required pre-merge checks and honest merge blocking for workspace changes.
- Update workspace, workflow, and sandbox documentation and release metadata.

Files changed:
 .changeset/fn-158-workspace-single-root.md         |   7 +
 docs/sandbox.md                                    |   6 +-
 docs/workflow-steps.md                             |   6 +-
 docs/workspaces.md                                 |  12 +-
 .../core/src/__tests__/legacy-adoption.test.ts     |  15 +-
 .../src/__tests__/required-pre-merge-steps.test.ts |  25 ++++
 .../core/src/__tests__/store-bypass-review.test.ts |  24 ++-
 packages/core/src/__tests__/task-merge.test.ts     |  24 +++
 .../core/src/__tests__/worktree-layout.test.ts     |  29 ++++
 packages/core/src/db/legacy-adoption.ts            |  20 ++-
 packages/core/src/index.gate.ts                    |   4 +
 packages/core/src/index.ts                         |   4 +
 .../core/src/merge/required-pre-merge-steps.ts     |  26 ++++
 packages/core/src/merge/task-merge.ts              |  35 ++++-
 packages/core/src/store.ts                         |  59 ++++++--
 packages/core/src/task-store/lifecycle-ops.ts      |   1 +
 packages/core/src/task-store/merge-queue-ops.ts    |   5 +-
 packages/core/src/task-store/moves.ts              |  13 +-
 packages/core/src/task-store/task-artifacts-ops.ts |  11 +-
 packages/core/src/tasks/worktree-layout.ts         |  43 +++++-
 packages/core/src/types/workflow/workflow-steps.ts |   3 +-
 .../executor-workspace-session-cwd.test.ts         |  42 ++++--
 .../src/__tests__/node-worktree-isolation.test.ts  |  13 +-
 .../src/__tests__/pi-create-fn-agent.test.ts       |  16 ++
 .../engine/src/__tests__/project-engine.test.ts    |  20 ++-
 .../src/__tests__/reviewer-workspace.test.ts       |  30 +++-
 .../src/__tests__/run-verification-command.test.ts |  90 +++++++++++-
 .../__tests__/sandbox/sandbox-exec-policy.test.ts  |  16 +-
 .../src/__tests__/sandbox/session-policy.test.ts   |  45 ++++++
 .../__tests__/workspace-add-repo-midflight.test.ts |   9 ++
 .../engine/src/__tests__/workspace-e2e.test.ts     |  13 +-
 .../workspace-root-worktree-routing.test.ts        |  18 +--
 packages/engine/src/agent-tools.ts                 |  15 +-
 packages/engine/src/agents/agent-runtime.ts        |  19 +++
 .../engine/src/agents/agent-session-helpers.ts     |  15 ++
 packages/engine/src/execution/hold-release.ts      |  29 ++++
 .../engine/src/execution/run-verification-tool.ts  | 114 ++++++++++++++-
 .../create-authoritative-workflow-seams.ts         |  20 +--
 packages/engine/src/executor/deps-bags.ts          |   5 +-
 .../executor/ensure-graph-custom-node-worktree.ts  |  24 ++-
 .../executor/ensure-task-worktree-for-planning.ts  |  36 ++---
 .../engine/src/executor/execute-workflow-step.ts   |   4 +-
 .../src/executor/finalize-already-reviewed-task.ts |   6 +-
 .../src/executor/prepare-graph-node-execution.ts   |  14 +-
 .../engine/src/executor/run-graph-custom-node.ts   | 161 +++++++++++++--------
 packages/engine/src/executor/run-implementation.ts | 117 ++++++++++++---
 packages/engine/src/merge/merger-ai.ts             |  16 +-
 packages/engine/src/merger.ts                      |  20 ++-
 packages/engine/src/pi.ts                          | 150 ++++++++++++++++---
 packages/engine/src/project-engine.ts              |  10 +-
 packages/engine/src/runtimes/in-process-runtime.ts |   4 +-
 packages/engine/src/sandbox/bubblewrap-backend.ts  |  55 ++++++-
 packages/engine/src/sandbox/bubblewrap-policy.ts   |  10 +-
 packages/engine/src/sandbox/index.ts               |   1 +
 .../engine/src/sandbox/sandbox-exec-backend.ts     |  45 +++++-
 packages/engine/src/sandbox/sandbox-exec-policy.ts |  18 ++-
 packages/engine/src/sandbox/session-policy.ts      |  41 ++++++
 packages/engine/src/sandbox/types.ts               |  11 ++
 packages/engine/src/self-healing.ts                |   1 +
 packages/engine/src/triage.ts                      |  10 ++
 .../engine/src/worktree/worktree-acquisition.ts    |  53 ++++---
 61 files changed, 1393 insertions(+), 315 deletions(-)

Fusion-Task-Id: FN-158

Fusion-Task-Lineage: ba57f5a2-fa69-4210-8ea7-3d124be3deb2

Co-authored-by: Fusion <noreply@runfusion.ai>
2026-08-23 01:37:58 +00:00

4.1 KiB

Sandbox Backends

Linux bubblewrap backend

Fusion supports an opt-in Linux sandbox backend using bubblewrap (bwrap).

  • Enable with sandbox.backend = "bubblewrap"
  • Default remains native
  • If unavailable, behavior follows failureMode (fail-hard or fallback-native)

Install

  • Debian/Ubuntu: sudo apt install bubblewrap
  • Fedora: sudo dnf install bubblewrap

Policy mapping

policyToBwrapArgs() translates sandbox policy into bwrap args:

  • Writable binds (--bind): worktree path, pnpm store path, plus configured allowedWritePaths
  • Read-only binds (--ro-bind): repo root (when distinct), system runtime paths (/usr, /bin, /lib, /lib64), TLS/DNS paths, and node binary directory
  • Temporary filesystem: --tmpfs /tmp
  • Working directory: --chdir <worktreePath>
  • Network isolation: allowNetwork=false adds --unshare-net
  • Environment isolation: --clearenv plus allowlisted passthrough (PATH, HOME, USER, LANG, LC_*, NODE_*, npm_*, PNPM_*, CI, FUSION_*)

Port 4040 guard

Port 4040 is reserved for the production dashboard. Sandbox policy rejects allowedPorts containing 4040 unless allowPort4040Override=true is explicitly set.

Fusion task sessions

Task sessions resolve the backend with prompt override, project setting, then the native default. When an isolating backend is selected, the declared task boundary is its writable root; workspace tasks use their one task directory, and linked repository worktrees additionally receive the Git administration paths required for commits. The agent bash tool and streaming verification both run through that backend. The JavaScript boundary remains active underneath as portable defense in depth when the backend is native or falls back to native.

Defaults remain unchanged: sandboxing is experimental, backend defaults to native, and failureMode defaults to fail-hard because host namespace capability is not universal.

Use fusionWorktreePreset(ctx) to get the standard Fusion-friendly defaults:

  • Worktree writable
  • pnpm store writable
  • .fusion/ compatibility metadata and task artifacts are not added to writable mounts

Troubleshooting

If you see bwrap: setting up uid map: Permission denied, unprivileged user namespaces may be disabled by host policy/kernel settings. Enable user namespaces or use sandbox.backend = "native" as a fallback.

See docs/settings-reference.md for full sandbox settings schema and precedence.

macOS sandbox-exec backend

Fusion supports an opt-in macOS sandbox backend using Apple's sandbox-exec (Seatbelt).

  • Enable with sandbox.backend = "sandbox-exec"
  • Default remains native
  • If unavailable, behavior follows failureMode (fail-hard or fallback-native)

Install / availability

/usr/bin/sandbox-exec ships with macOS. If detection fails, install Xcode Command Line Tools and retry.

Policy mapping

policyToSbplProfile() translates policy into an SBPL profile:

  • Base deny policy with additive allows
  • Writable paths: worktree, pnpm store, /private/tmp, and user temp (/private/var/folders/.../T/)
  • Read paths: repo root (when needed), Node binary directory, and curated system/runtime paths (/usr, /bin, /sbin, /System, /Library, resolver/cert/hosts/services/timezone paths)
  • Network: allowNetwork=true enables outbound and local bind, allowNetwork=false denies network

Port 4040 guard

Port 4040 is always blocked in the emitted SBPL profile ((deny network-bind (local ip "*:4040"))), and policy rejects explicit 4040 allowance unless allowPort4040Override=true is set.

.fusion/ write guard

Writable paths under .fusion/ (including .fusion/project.json, retained migration inputs, and .fusion/tasks/**) are rejected by policy validation.

Troubleshooting

If commands fail with sandbox-exec: ...: Operation not permitted, expand allowedReadPaths/allowedWritePaths for required inputs/outputs.

Deprecation note

Apple marks sandbox-exec as deprecated. It remains functional for many workflows, but failureMode = "fallback-native" is the recommended hedge when host support varies.