Skip to content

[experimental] Add macos bash commands sandboxing#21538

Draft
e-n-0 wants to merge 19 commits intoanomalyco:devfrom
e-n-0:dev
Draft

[experimental] Add macos bash commands sandboxing#21538
e-n-0 wants to merge 19 commits intoanomalyco:devfrom
e-n-0:dev

Conversation

@e-n-0
Copy link
Copy Markdown

@e-n-0 e-n-0 commented Apr 8, 2026

Issue for this PR

Closes #2242

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

This PR adds opt-in macOS command sandboxing with sandbox-exec.

When sandboxing is enabled, OpenCode now resolves experimental.sandbox, applies built-in or custom presets, builds a macOS Seatbelt profile, and launches covered command paths through sandbox-exec -p <profile> ....
The core flow lives in src/sandbox/spawn.ts, src/sandbox/policy.ts, and src/sandbox/preset.ts, with integration work in src/config/config.ts, src/tool/bash.ts, src/session/prompt.ts, src/pty/index.ts, and the related launch/runtime paths.

In practice, that changes command execution like this:

  • bash tool commands and session shell commands resolve sandbox settings before spawn, enforce excluded_commands, and can ask for bash:unsandboxed before retrying outside the sandbox
  • PTY sessions apply the sandbox only to the initial shell spawn
  • if a bash or session command hits a sandbox denial and allow_unsandboxed_retry is enabled, OpenCode can ask for the separate bash:unsandboxed permission and retry without the sandbox
  • the TUI and app permission prompts now surface the new sandbox-related permission flows, including reason-specific unsandboxed messaging

Summary

  • Adds the core macOS sandboxing pieces: preset resolution, policy generation, protected roots, config wiring, and the spawn wrapper that launches sandboxed processes.
  • Covers the main execution surfaces: bash tool commands, session command execution, PTY shell startup, and the related launch/runtime paths used by those flows.
  • Adds built-in presets (default, strict, network), modes (workspace-write, read-only), extra read/write/deny roots, workspace-relative protected_roots, and excluded_commands.
  • Adds the bash:unsandboxed permission flow, updated permission UI handling, and docs/security updates across config, permissions, tools, and the sandbox threat model.

Current limits

  • macOS only (does not cover Linux or Windows)
  • experimental and opt-in
  • does not sandbox MCP servers
  • does not intercept commands typed inside an already-running PTY session
  • PTY supports sandboxed initial spawn only; there is no unsandboxed retry path for PTY

How did you verify your code works?

Automated tests:

  • Ran bun test test/tool/bash-sandbox.test.ts test/session/prompt-sandbox.test.ts test/pty/pty-session.test.ts test/sandbox/*.test.ts from packages/opencode
  • 56 tests passed across the bash tool, session command, PTY, and sandbox policy/preset/spawn flows
  • The tests cover:
    • in-project writes still work in sandbox mode
    • PTY startup stays deterministic in sandbox mode
    • sensitive home reads like ~/.ssh/secret are denied
    • read-only mode blocks workspace writes but still allows /tmp
    • preset resolution and preset-driven permission defaults
    • excluded_commands are blocked before spawn
    • reactive unsandboxed retry asks for bash:unsandboxed and succeeds when allowed
    • proactive # opencode:unsandboxed requests run unsandboxed on the first attempt
    • rejected unsandboxed requests fall back to the sandbox and preserve the denial message
    • timeout, abort, and sandbox launch failure behavior still works through the sandbox wrapper

Manual tests:

  • Tried to run curl/wget commands in sandboxed environment with and without network enabled
  • Tried to force the model to ask elevated permission for a command
  • Tried to make the model understand that a command was failing because of the sandbox and then retry it without sandbox when allowed
  • Tested multiple sandbox configuration combinations with and without unsandboxed retry allowance
  • Tested during 2 weeks of intensive agentic workflows

Screenshots / recordings

Screenshot 2026-04-08 at 15 22 46

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

Hey! Your PR title [experimental] Add macos bash commands sandboxing doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

The following comment was made by an LLM, it may be inaccurate:

Potential Duplicate Found:

Why it's related: This PR also addresses command sandboxing functionality, specifically for bash commands and includes MCP server sandboxing on both Linux and macOS. The current PR (21538) is experimental macOS-only sandboxing, which may overlap with or be a refinement/alternative approach to PR #20316's broader sandboxing implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Is there a way to sandbox the agent ?

2 participants