diff --git a/docs/cli/configuration/sandbox.mdx b/docs/cli/configuration/sandbox.mdx index 2dee7df1..0545d8cd 100644 --- a/docs/cli/configuration/sandbox.mdx +++ b/docs/cli/configuration/sandbox.mdx @@ -34,14 +34,36 @@ Under the hood, Sandbox uses Seatbelt profiles on macOS, bubblewrap with seccomp | **File writes** | Deny all except **CWD** (current working directory). Additional paths can be allowed. `denyWrite` overrides `allowWrite`. | `sandbox.filesystem.allowWrite`, `sandbox.filesystem.denyWrite` | | **Network** | Deny all except `*.factory.ai` (always allowed by default). Additional domains must be explicitly allowed. | `sandbox.network.allowedDomains` | +## Sandbox modes + +The `sandbox.mode` setting selects how isolation is applied: + +- **`per-command`** (default) -- only Droid-initiated shell commands and tool operations are sandboxed. +- **`whole-process`** (Linux only) -- the entire Droid process is launched inside the OS sandbox, extending isolation to the main process, MCP stdio transports, and subagents. + ## What's included -**Per-command sandbox mode** (default when enabled): +**Per-command sandbox mode** (`mode: "per-command"`, default when enabled): - **File tools** (Read, Edit, Create, LS, Grep, Glob, ApplyPatch) -- `checkFileAccess()` before every operation, enforcing `denyRead` for reads and `allowWrite`/`denyWrite` for writes - **Execute tool** -- shell commands wrapped in OS sandbox (Seatbelt/bubblewrap) with network routed through SRT's filtering proxy for domain-level control - **FetchUrl** -- `checkNetworkAccess()` against `allowedDomains` -- **Note** -- main Droid process, MCPs and subagent are not isolated yet. +- **MCP tools** -- fail closed (denied) under an active sandbox. MCP tool behavior is opaque (a server can read/write files, reach the network, etc.) and the protocol exposes no per-tool effect metadata, so MCP tools cannot be mapped to an enforceable sandbox policy and are blocked by the default-deny tool policy below. +- **Note** -- the main Droid process and subagents are not isolated in this mode. Use `whole-process` mode to isolate them. + +**Whole-process sandbox mode** (`mode: "whole-process"`, Linux only): + +- At startup the entire Droid process is re-executed inside the OS sandbox, so the main process, MCP stdio transports, and subagent lifecycles all run within the configured filesystem and network boundaries +- Network requests made directly by the Droid process (not only those from the Execute tool) are filtered against `allowedDomains`, with interactive domain prompts in TUI mode +- **Fails closed** -- if the secure runtime cannot be established at startup (unsupported platform, missing sandbox support, or a failed isolation check), Droid refuses to start rather than running unsandboxed +- Default access policies, filesystem and network configuration, and allow-always persistence behave the same as per-command mode + +**Tool policy (default-deny):** + +- Every registered tool declares sandbox side-effect metadata (`filesystem-read`, `filesystem-write`, `network`, `process`, `external-service`, `persistent-settings`) +- When sandbox is enabled, a tool is allowed only if every declared side effect maps to a sandbox policy handler (file access, network, or per-command Execute). Tools with an unannotated, unknown, or unhandled side effect are denied +- Tools whose effects cannot be enforced locally -- such as MCP tools and connectors (`external-service`) -- have no handler and therefore fail closed +- Tool-policy denials are **non-promptable**: user approval cannot bypass missing policy coverage, and these denials are not configurable via `allowWrite`/`allowedDomains` **Interactive permission prompts (TUI mode):** @@ -80,19 +102,21 @@ Under the hood, Sandbox uses Seatbelt profiles on macOS, bubblewrap with seccomp { "sandbox": { "enabled": true, + // Isolation scope: "per-command" (default) or "whole-process" (Linux only) + "mode": "per-command", "filesystem": { // Additional writable paths beyond CWD (which is always writable) "allowWrite": ["/tmp/build-output", "~/.config"], // Deny writes to specific subpaths even if parent is in allowWrite "denyWrite": ["/tmp/build-output/cache/locks", "~/.config/secrets"], // Block reads to specific paths (everything else is readable) - "denyRead": ["~/.aws/credentials", "~/.ssh/id_rsa"], + "denyRead": ["~/.aws/credentials", "~/.ssh/id_rsa"] }, "network": { // Only these domains are reachable (*.factory.ai always included) - "allowedDomains": ["github.com", "*.npmjs.org"], - }, - }, + "allowedDomains": ["github.com", "*.npmjs.org"] + } + } } ``` diff --git a/docs/jp/cli/configuration/sandbox.mdx b/docs/jp/cli/configuration/sandbox.mdx index c9623f43..520a8a72 100644 --- a/docs/jp/cli/configuration/sandbox.mdx +++ b/docs/jp/cli/configuration/sandbox.mdx @@ -34,14 +34,36 @@ OSレベルのサンドボックス化では、ユーザーがDroidのファイ | **ファイル書き込み** | **CWD**(現在の作業ディレクトリ)以外はすべて拒否。追加のパスは許可できます。`denyWrite` は `allowWrite` より優先されます。 | `sandbox.filesystem.allowWrite`, `sandbox.filesystem.denyWrite` | | **ネットワーク** | `*.factory.ai`(デフォルトで常に許可)以外はすべて拒否。追加のドメインは明示的に許可する必要があります。 | `sandbox.network.allowedDomains` | +## サンドボックスモード + +`sandbox.mode` 設定で、分離の適用方法を選択します: + +- **`per-command`**(デフォルト) -- Droid が開始するシェルコマンドとツール操作のみがサンドボックス化されます。 +- **`whole-process`**(Linux のみ) -- Droid プロセス全体が OS サンドボックス内で起動され、メインプロセス、MCP の stdio トランスポート、サブエージェントにまで分離が拡張されます。 + ## 含まれる機能 -**コマンド単位のサンドボックスモード**(有効時のデフォルト): +**コマンド単位のサンドボックスモード**(`mode: "per-command"`、有効時のデフォルト): - **ファイルツール**(Read、Edit、Create、LS、Grep、Glob、ApplyPatch) -- すべての操作の前に `checkFileAccess()` を実行し、読み取りには `denyRead`、書き込みには `allowWrite` / `denyWrite` を適用 - **Execute ツール** -- シェルコマンドを OS サンドボックス(Seatbelt / bubblewrap)でラップし、ネットワークはドメインレベル制御のために SRT のフィルタリングプロキシ経由でルーティング - **FetchUrl** -- `allowedDomains` に対して `checkNetworkAccess()` を実行 -- **注記** -- メインのDroidプロセス、MCP、サブエージェントはまだ分離されていません。 +- **MCP ツール** -- サンドボックス有効時は fail closed(拒否)になります。MCP ツールの挙動は不透明で(サーバーがファイルの読み書きやネットワークアクセスなどを行う可能性があります)、プロトコルはツールごとの効果メタデータを公開しないため、強制可能なサンドボックスポリシーにマッピングできず、後述のデフォルト拒否ツールポリシーによってブロックされます。 +- **注記** -- このモードではメインのDroidプロセスとサブエージェントは分離されません。これらを分離するには `whole-process` モードを使用してください。 + +**プロセス全体のサンドボックスモード**(`mode: "whole-process"`、Linux のみ): + +- 起動時に Droid プロセス全体が OS サンドボックス内で再実行されるため、メインプロセス、MCP の stdio トランスポート、サブエージェントのライフサイクルがすべて、設定されたファイルシステムおよびネットワーク境界の範囲内で実行されます +- Droid プロセスが直接行うネットワークリクエスト(Execute ツールからのものだけでなく)も `allowedDomains` に対してフィルタリングされ、TUI モードでは対話型のドメインプロンプトが表示されます +- **Fails closed** -- 起動時にセキュアなランタイムを確立できない場合(非対応プラットフォーム、サンドボックスサポートの欠如、または分離チェックの失敗)、Droid はサンドボックスなしで実行するのではなく起動を拒否します +- デフォルトのアクセスポリシー、ファイルシステムおよびネットワーク設定、「常に許可」の永続化は、コマンド単位モードと同じ挙動です + +**ツールポリシー(デフォルト拒否):** + +- 登録されたすべてのツールは、サンドボックスの副作用メタデータ(`filesystem-read`、`filesystem-write`、`network`、`process`、`external-service`、`persistent-settings`)を宣言します +- サンドボックス有効時、宣言されたすべての副作用がサンドボックスポリシーハンドラ(ファイルアクセス、ネットワーク、またはコマンド単位の Execute)にマッピングされる場合にのみ、ツールが許可されます。注釈のない副作用、不明な副作用、または未処理の副作用を持つツールは拒否されます +- ローカルで強制できない効果を持つツール(MCP ツールやコネクタ(`external-service`)など)はハンドラを持たないため、fail closed になります +- ツールポリシーによる拒否は**プロンプト不可**です。ユーザーの承認でポリシーカバレッジの欠如を回避することはできず、これらの拒否は `allowWrite` / `allowedDomains` では設定できません **対話型の権限プロンプト(TUIモード):** @@ -80,19 +102,21 @@ OSレベルのサンドボックス化では、ユーザーがDroidのファイ { "sandbox": { "enabled": true, + // 分離のスコープ: "per-command"(デフォルト)または "whole-process"(Linux のみ) + "mode": "per-command", "filesystem": { // CWD(常に書き込み可)に加えて書き込み可能にするパス "allowWrite": ["/tmp/build-output", "~/.config"], // 親が allowWrite にあっても特定のサブパスへの書き込みを拒否 "denyWrite": ["/tmp/build-output/cache/locks", "~/.config/secrets"], // 特定のパスへの読み取りをブロック(それ以外は読み取り可) - "denyRead": ["~/.aws/credentials", "~/.ssh/id_rsa"], + "denyRead": ["~/.aws/credentials", "~/.ssh/id_rsa"] }, "network": { // 到達可能なドメインはこれらのみ(*.factory.ai は常に含まれる) - "allowedDomains": ["github.com", "*.npmjs.org"], - }, - }, + "allowedDomains": ["github.com", "*.npmjs.org"] + } + } } ```