Skip to content

feat(sandbox): macOS seatbelt strategy for the Bash tool#120

Merged
emal-avala merged 3 commits intomainfrom
feat/sandbox-seatbelt-bash
Apr 15, 2026
Merged

feat(sandbox): macOS seatbelt strategy for the Bash tool#120
emal-avala merged 3 commits intomainfrom
feat/sandbox-seatbelt-bash

Conversation

@emal-avala
Copy link
Copy Markdown
Member

First vertical slice of ROADMAP §7.4 Process-Level Sandboxing — the top Critical v1.1 item. Adds real OS-level isolation to the Bash tool on macOS so that even a compromised agent cannot write outside the project directory or read credential files.

Summary

  • New `crates/lib/src/sandbox/` module: `SandboxStrategy` trait + `NoopStrategy` + `SandboxPolicy` + macOS Seatbelt implementation
  • `SandboxConfig` added to `ConfigSchema` — disabled by default while Linux and Windows strategies land, so we do not ship asymmetric platform security
  • `SandboxExecutor` threaded through `ToolContext`; `tools/bash.rs` wraps its tokio `Command` before `.spawn()`
  • Honors tool-call-level `dangerouslyDisableSandbox`, gated on `security.disable_bypass_permissions`
  • `--no-sandbox` CLI flag (also gated on `disable_bypass_permissions`)
  • `/sandbox` slash command printing the active strategy and resolved policy
  • SBPL profile: `(deny default)`, broad reads, project-dir writes, explicit allow list, forbidden-path deny-reads, optional network
  • Canonical-path resolution for subpath rules so `/var ↔ /private/var` symlink redirection does not break project-dir writes
  • Unit tests (17): policy tilde expansion, strategy picker, SBPL generation (7 assertions), disabled executor
  • Integration tests (4): disabled pass-through, no-ctx pass-through, seatbelt blocks `/etc` writes, seatbelt allows in-project writes (macOS-gated)

Deferred to follow-up PRs

  • Linux `bwrap` strategy
  • Windows Low Integrity strategy
  • Secret file masking (`.env`, `*.pem` → `/dev/null`)
  • Per-tool sandbox overrides
  • `agent.rs` subagent and PowerShell tool wrapping
  • Default flip to `enabled: true` (happens once all three platforms are in)

Test plan

  • `cargo check --all-targets` clean
  • `cargo clippy --all-targets -- -D warnings` clean
  • `cargo fmt --all -- --check` clean
  • `cargo test --all-targets` — full suite green (includes 17 new sandbox unit tests and 4 new sandbox integration tests)
  • Manual verification that `seatbelt_blocks_writes_outside_project_dir` actually blocks `echo > /etc/...` and `seatbelt_allows_writes_inside_project_dir` lets in-project writes through

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

First vertical slice of ROADMAP §7.4 Process-Level Sandboxing. Ships
a SandboxStrategy trait with a macOS Seatbelt implementation, wires it
into the Bash tool's subprocess spawn path, and exposes a --no-sandbox
CLI flag and /sandbox slash command.

Shipped:
- crates/lib/src/sandbox/ module (trait, Noop, policy, seatbelt)
- SandboxConfig added to ConfigSchema; disabled by default while Linux
  and Windows strategies land
- SandboxExecutor threaded through ToolContext; Bash wraps its tokio
  Command via ctx.sandbox before spawn
- Honors dangerouslyDisableSandbox per-call, gated on
  security.disable_bypass_permissions
- SBPL profile: deny default, broad reads, project-dir writes plus
  explicit allow list, forbidden-path deny-reads, optional network
- Canonical-path resolution for subpath rules so /var <-> /private/var
  symlink redirection does not break project-dir writes
- --no-sandbox CLI flag (gated on disable_bypass_permissions)
- /sandbox slash command printing active strategy and resolved policy
- Unit tests (17): policy expansion, strategy picker, profile generation
- Integration tests (4): disabled pass-through, no-ctx pass-through,
  seatbelt blocks /etc writes, seatbelt allows in-project writes
  (macOS-gated)

Deferred to follow-up PRs: Linux bwrap, Windows Low Integrity, secret
file masking, per-tool overrides, agent/powershell wiring, enable-by-
default once all three platforms are in.
The two macos-only integration tests are the only consumers, so the
import is dead on Linux/Windows and clippy -D warnings rejects it.
@emal-avala emal-avala force-pushed the feat/sandbox-seatbelt-bash branch from a785a47 to 4856612 Compare April 15, 2026 08:02
Adds 20 new unit tests (17 → 37) covering strategy picker branches,
executor state combinations, SeatbeltStrategy argv/cwd/env preservation,
profile edge cases (empty lists, multiple forbidden paths, process
allow rules, system.sb import), and the from_session_config bypass
path.

Adds 5 new integration tests (4 → 9) that exercise bash.rs end to end:
per-call dangerouslyDisableSandbox honors the session bypass flag and
is ignored when security.disable_bypass_permissions is set, cwd is
preserved through the sandbox-exec wrapper, explicit allowed_write_paths
entries are honored, and broad reads of /etc/hosts remain allowed.

Also fixes a real bypass-gate gap in bash.rs: the previous wiring did
not consult disable_bypass_permissions at all. Adds
SandboxExecutor::from_session_config and from_config_with_bypass so
the gate flows through from config automatically.

Adds e2e-tests.sh section M (4 tests): [sandbox] config section parse,
--no-sandbox flag, unknown-strategy graceful fallback, macOS-gated
serve-mode real sandbox deny check.
@emal-avala emal-avala merged commit b55a528 into main Apr 15, 2026
13 of 14 checks passed
@emal-avala emal-avala deleted the feat/sandbox-seatbelt-bash branch April 15, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant