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

87 lines
4.1 KiB
Markdown

# 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.
### Related settings
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.