Skip to content
Open
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
2 changes: 2 additions & 0 deletions src/claude_agent_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
RateLimitStatus,
RateLimitType,
ResultMessage,
SandboxFilesystemConfig,
SandboxIgnoreViolations,
SandboxNetworkConfig,
SandboxSettings,
Expand Down Expand Up @@ -638,6 +639,7 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> Any:
# Sandbox support
"SandboxSettings",
"SandboxNetworkConfig",
"SandboxFilesystemConfig",
"SandboxIgnoreViolations",
# MCP Server Support
"create_sdk_mcp_server",
Expand Down
45 changes: 44 additions & 1 deletion src/claude_agent_sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,20 +779,50 @@ class SdkPluginConfig(TypedDict):


# Sandbox configuration types
class SandboxFilesystemConfig(TypedDict, total=False):
"""Filesystem configuration for sandbox.

Attributes:
allowWrite: Additional paths where sandboxed commands can write.
denyWrite: Paths where sandboxed commands cannot write.
denyRead: Paths where sandboxed commands cannot read.
allowRead: Re-allow reading specific paths within denyRead regions.
allowManagedReadPathsOnly: When True, only allowRead entries from managed
settings are respected. Default: False
"""

allowWrite: list[str]
denyWrite: list[str]
denyRead: list[str]
allowRead: list[str]
allowManagedReadPathsOnly: bool


class SandboxNetworkConfig(TypedDict, total=False):
"""Network configuration for sandbox.

Attributes:
allowUnixSockets: Unix socket paths accessible in sandbox (e.g., SSH agents).
allowAllUnixSockets: Allow all Unix sockets (less secure).
allowLocalBinding: Allow binding to localhost ports (macOS only).
allowMachLookup: XPC/Mach service names accessible in sandbox
(macOS only, supports ``*`` prefix matching).
allowedDomains: Outbound network domains allowed in sandbox
(supports wildcards like ``*.example.com``).
deniedDomains: Blocked domains (takes precedence over allowedDomains).
allowManagedDomainsOnly: When True, only allowedDomains entries from managed
settings are respected. Default: False
httpProxyPort: HTTP proxy port if bringing your own proxy.
socksProxyPort: SOCKS5 proxy port if bringing your own proxy.
"""

allowUnixSockets: list[str]
allowAllUnixSockets: bool
allowLocalBinding: bool
allowMachLookup: list[str]
allowedDomains: list[str]
deniedDomains: list[str]
allowManagedDomainsOnly: bool
httpProxyPort: int
socksProxyPort: int

Expand Down Expand Up @@ -823,14 +853,19 @@ class SandboxSettings(TypedDict, total=False):

Attributes:
enabled: Enable bash sandboxing (macOS/Linux only). Default: False
failIfUnavailable: Exit with error if sandbox dependencies are not available
when enabled. Default: False
autoAllowBashIfSandboxed: Auto-approve bash commands when sandboxed. Default: True
excludedCommands: Commands that should run outside the sandbox (e.g., ["git", "docker"])
allowUnsandboxedCommands: Allow commands to bypass sandbox via dangerouslyDisableSandbox.
When False, all commands must run sandboxed (or be in excludedCommands). Default: True
network: Network configuration for sandbox.
filesystem: Filesystem configuration for sandbox.
ignoreViolations: Violations to ignore.
enableWeakerNestedSandbox: Enable weaker sandbox for unprivileged Docker environments
(Linux only). Reduces security. Default: False
enableWeakerNetworkIsolation: Allow system TLS service access for Go-based tools
with MITM proxy (macOS only). Reduces security. Default: False

Example:
```python
Expand All @@ -840,19 +875,27 @@ class SandboxSettings(TypedDict, total=False):
"excludedCommands": ["docker"],
"network": {
"allowUnixSockets": ["/var/run/docker.sock"],
"allowLocalBinding": True
"allowLocalBinding": True,
"allowedDomains": ["github.com", "*.npmjs.org"]
},
"filesystem": {
"allowWrite": ["/tmp/build"],
"denyRead": ["~/.aws/credentials"]
}
}
```
"""

enabled: bool
failIfUnavailable: bool
autoAllowBashIfSandboxed: bool
excludedCommands: list[str]
allowUnsandboxedCommands: bool
network: SandboxNetworkConfig
filesystem: SandboxFilesystemConfig
ignoreViolations: SandboxIgnoreViolations
enableWeakerNestedSandbox: bool
enableWeakerNetworkIsolation: bool


# Content block types
Expand Down
87 changes: 87 additions & 0 deletions tests/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,93 @@ def test_sandbox_network_config(self):
assert network["httpProxyPort"] == 8080
assert network["socksProxyPort"] == 8081

def test_sandbox_filesystem_config(self):
"""Test sandbox with filesystem configuration."""
import json

from claude_agent_sdk import SandboxSettings

sandbox: SandboxSettings = {
"enabled": True,
"filesystem": {
"allowWrite": ["/tmp/build", "~/.kube"],
"denyRead": ["~/.aws/credentials"],
"allowRead": ["/etc/hosts", "/etc/resolv.conf"],
},
}

transport = SubprocessCLITransport(
prompt="test",
options=make_options(sandbox=sandbox),
)

cmd = transport._build_command()
settings_idx = cmd.index("--settings")
settings_value = cmd[settings_idx + 1]

parsed = json.loads(settings_value)
fs = parsed["sandbox"]["filesystem"]

assert fs["allowWrite"] == ["/tmp/build", "~/.kube"]
assert fs["denyRead"] == ["~/.aws/credentials"]
assert fs["allowRead"] == ["/etc/hosts", "/etc/resolv.conf"]

def test_sandbox_network_domains(self):
"""Test sandbox with domain-based network configuration."""
import json

from claude_agent_sdk import SandboxSettings

sandbox: SandboxSettings = {
"enabled": True,
"network": {
"allowedDomains": ["github.com", "*.npmjs.org"],
"deniedDomains": ["evil.com"],
"allowManagedDomainsOnly": False,
},
}

transport = SubprocessCLITransport(
prompt="test",
options=make_options(sandbox=sandbox),
)

cmd = transport._build_command()
settings_idx = cmd.index("--settings")
settings_value = cmd[settings_idx + 1]

parsed = json.loads(settings_value)
network = parsed["sandbox"]["network"]

assert network["allowedDomains"] == ["github.com", "*.npmjs.org"]
assert network["deniedDomains"] == ["evil.com"]
assert network["allowManagedDomainsOnly"] is False

def test_sandbox_new_settings_fields(self):
"""Test sandbox with failIfUnavailable and enableWeakerNetworkIsolation."""
import json

from claude_agent_sdk import SandboxSettings

sandbox: SandboxSettings = {
"enabled": True,
"failIfUnavailable": True,
"enableWeakerNetworkIsolation": True,
}

transport = SubprocessCLITransport(
prompt="test",
options=make_options(sandbox=sandbox),
)

cmd = transport._build_command()
settings_idx = cmd.index("--settings")
settings_value = cmd[settings_idx + 1]

parsed = json.loads(settings_value)
assert parsed["sandbox"]["failIfUnavailable"] is True
assert parsed["sandbox"]["enableWeakerNetworkIsolation"] is True

def test_build_command_with_tools_array(self):
"""Test building CLI command with tools as array of tool names."""
transport = SubprocessCLITransport(
Expand Down