Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 35 additions & 10 deletions docs/cli/configuration/sandbox.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,39 @@ Under the hood, Sandbox uses Seatbelt profiles on macOS, bubblewrap with seccomp
| --------------- | ------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| **File reads** | Allow all. Only explicit `denyRead` entries are blocked. | `sandbox.filesystem.denyRead` |
| **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` |
| **Network** | Deny all except Factory's own domains (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`** -- 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
- **File tools** (Read, Edit, Create, LS, Grep, Glob, ApplyPatch) -- checked before every operation, enforcing `denyRead` for reads and `allowWrite`/`denyWrite` for writes
- **Execute tool** -- shell commands run inside the OS sandbox, with network routed through a filtering proxy for domain-level control
- **FetchUrl** -- `checkNetworkAccess()` against `allowedDomains`
- **Note** -- main Droid process, MCPs and subagent are not isolated yet.
- **WebSearch** -- `checkNetworkAccess()` against `allowedDomains`
- **MCP tools** -- still enforced, but mediated by argument inspection rather than blanket-denied. Before the call runs, each argument is checked: values that parse as `http(s)` URLs go through `checkNetworkAccess()` against `allowedDomains`, and values that look like filesystem paths (by argument name, `file://`, or path form) go through `checkFileAccess()` for read and/or write. The call proceeds only if every detected path and URL passes; any violation blocks it. MCP server transports also egress through the sandbox proxy and are filtered against `allowedDomains`. An MCP tool still fails closed if its sandbox side-effect metadata is missing or declares an effect with no handler.
- **Subagents (Task tool)** -- delegated subagents inherit the parent sandbox policy
- **Note** -- the main Droid process itself is not isolated in this mode. Use `whole-process` mode to isolate it.

**Whole-process sandbox mode** (`mode: "whole-process"`):

- 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):**

- When sandbox is enabled, a tool is allowed only if every effect it can have (filesystem, network, process, etc.) can be enforced by a sandbox policy (file access, network, or per-command Execute). Tools with an unknown or unenforceable effect are denied
- Tools whose effects cannot be enforced locally -- such as connectors (external services) -- fail closed. MCP tools are the exception: they reach external services but are mediated by argument inspection (see above) rather than blanket-denied
- These denials are **non-promptable**: user approval cannot bypass them, and they are not configurable via `allowWrite`/`allowedDomains`

**Interactive permission prompts (TUI mode):**

Expand Down Expand Up @@ -80,19 +103,21 @@ Under the hood, Sandbox uses Seatbelt profiles on macOS, bubblewrap with seccomp
{
"sandbox": {
"enabled": true,
// Isolation scope: "per-command" (default) or "whole-process"
"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"],
},
},
// Only these domains are reachable (Factory's own domains always included)
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
}
```

Expand Down
45 changes: 35 additions & 10 deletions docs/jp/cli/configuration/sandbox.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,39 @@ OSレベルのサンドボックス化では、ユーザーがDroidのファイ
| --- | --- | --- |
| **ファイル読み取り** | すべて許可。明示的な `denyRead` エントリのみブロックされます。 | `sandbox.filesystem.denyRead` |
| **ファイル書き込み** | **CWD**(現在の作業ディレクトリ)以外はすべて拒否。追加のパスは許可できます。`denyWrite` は `allowWrite` より優先されます。 | `sandbox.filesystem.allowWrite`, `sandbox.filesystem.denyWrite` |
| **ネットワーク** | `*.factory.ai`(デフォルトで常に許可)以外はすべて拒否。追加のドメインは明示的に許可する必要があります。 | `sandbox.network.allowedDomains` |
| **ネットワーク** | Factory 自身のドメイン(デフォルトで常に許可)以外はすべて拒否。追加のドメインは明示的に許可する必要があります。 | `sandbox.network.allowedDomains` |

## サンドボックスモード

`sandbox.mode` 設定で、分離の適用方法を選択します:

- **`per-command`**(デフォルト) -- Droid が開始するシェルコマンドとツール操作のみがサンドボックス化されます。
- **`whole-process`** -- Droid プロセス全体が OS サンドボックス内で起動され、メインプロセス、MCP の stdio トランスポート、サブエージェントにまで分離が拡張されます。

## 含まれる機能

**コマンド単位のサンドボックスモード**(有効時のデフォルト):
**コマンド単位のサンドボックスモード**(`mode: "per-command"`、有効時のデフォルト):

- **ファイルツール**(Read、Edit、Create、LS、Grep、Glob、ApplyPatch) -- すべての操作の前に `checkFileAccess()` を実行し、読み取りには `denyRead`、書き込みには `allowWrite` / `denyWrite` を適用
- **Execute ツール** -- シェルコマンドを OS サンドボックス(Seatbelt / bubblewrap)でラップし、ネットワークはドメインレベル制御のために SRT のフィルタリングプロキシ経由でルーティング
- **ファイルツール**(Read、Edit、Create、LS、Grep、Glob、ApplyPatch) -- すべての操作の前にチェックし、読み取りには `denyRead`、書き込みには `allowWrite` / `denyWrite` を適用
- **Execute ツール** -- シェルコマンドを OS サンドボックス内で実行し、ネットワークはドメインレベル制御のためにフィルタリングプロキシ経由でルーティング
- **FetchUrl** -- `allowedDomains` に対して `checkNetworkAccess()` を実行
- **注記** -- メインのDroidプロセス、MCP、サブエージェントはまだ分離されていません。
- **WebSearch** -- `allowedDomains` に対して `checkNetworkAccess()` を実行
- **MCP ツール** -- 引き続き強制されますが、一律に拒否するのではなく引数の検査によって仲介されます。呼び出し前に各引数がチェックされ、`http(s)` URL として解析される値は `checkNetworkAccess()` で `allowedDomains` に対して、ファイルシステムパスのように見える値(引数名、`file://`、またはパス形式による)は `checkFileAccess()` で読み取り/書き込みについてチェックされます。検出されたすべてのパスと URL が通過した場合にのみ呼び出しが進み、いずれかが違反するとブロックされます。MCP サーバーのトランスポートもサンドボックスプロキシ経由で送信され、`allowedDomains` に対してフィルタリングされます。MCP ツールは、サンドボックスの副作用メタデータが欠落しているか、ハンドラのない効果を宣言している場合は、依然として fail closed になります。
- **サブエージェント(Task ツール)** -- 委任されたサブエージェントは親のサンドボックスポリシーを継承します
- **注記** -- このモードではメインの Droid プロセス自体は分離されません。これを分離するには `whole-process` モードを使用してください。

**プロセス全体のサンドボックスモード**(`mode: "whole-process"`):

- 起動時に Droid プロセス全体が OS サンドボックス内で再実行されるため、メインプロセス、MCP の stdio トランスポート、サブエージェントのライフサイクルがすべて、設定されたファイルシステムおよびネットワーク境界の範囲内で実行されます
- Droid プロセスが直接行うネットワークリクエスト(Execute ツールからのものだけでなく)も `allowedDomains` に対してフィルタリングされ、TUI モードでは対話型のドメインプロンプトが表示されます
- **Fails closed** -- 起動時にセキュアなランタイムを確立できない場合(非対応プラットフォーム、サンドボックスサポートの欠如、または分離チェックの失敗)、Droid はサンドボックスなしで実行するのではなく起動を拒否します
- デフォルトのアクセスポリシー、ファイルシステムおよびネットワーク設定、「常に許可」の永続化は、コマンド単位モードと同じ挙動です

**ツールポリシー(デフォルト拒否):**

- サンドボックス有効時、ツールが持ちうるすべての効果(ファイルシステム、ネットワーク、プロセスなど)がサンドボックスポリシー(ファイルアクセス、ネットワーク、またはコマンド単位の Execute)で強制できる場合にのみ、ツールが許可されます。不明な効果や強制できない効果を持つツールは拒否されます
- ローカルで強制できない効果を持つツール(コネクタ(外部サービス)など)は fail closed になります。MCP ツールは例外で、外部サービスに到達しますが、一律に拒否されるのではなく引数の検査によって仲介されます(上記参照)
- これらの拒否は**プロンプト不可**です。ユーザーの承認で回避することはできず、`allowWrite` / `allowedDomains` では設定できません

**対話型の権限プロンプト(TUIモード):**

Expand Down Expand Up @@ -80,19 +103,21 @@ OSレベルのサンドボックス化では、ユーザーがDroidのファイ
{
"sandbox": {
"enabled": true,
// 分離のスコープ: "per-command"(デフォルト)または "whole-process"
"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"],
},
},
// 到達可能なドメインはこれらのみ(Factory 自身のドメインは常に含まれる
"allowedDomains": ["github.com", "*.npmjs.org"]
}
}
}
```

Expand Down
Loading