Sandbox policy
CRUD over the per-workspace SandboxPolicy (packages/sandbox/types.py:52) that the agent runtime enforces on sandbox.start / sandbox.run calls. Policy fields cover the filesystem allowlist, network allowlist, CPU / memory / PID limits, wall-clock cap, and the base image; together they bound what an agent-tool subprocess can see and do.
The router lives at packages/sandbox/policy_routes.py. The registry is SandboxPolicyRegistry on app.state.sandbox_policy_registry.
Endpoints
| Method | Path | Auth | Summary |
|---|---|---|---|
| GET | /admin/sandbox/policy | Bearer | Read the workspace's resolved policy (falls back to default). |
| PUT | /admin/sandbox/policy | Bearer | Upsert the workspace's policy. |
| DELETE | /admin/sandbox/policy | Bearer | Drop the workspace override. |
GET /admin/sandbox/policy
Returns the resolved SandboxPolicy for the caller's workspace. Always returns a policy — when no override is set the registry default fills in. Callers can rely on the response shape and inspect the fields to decide if they need to PUT an override.
{
"workspace_id": "default",
"fs_allowlist": ["/workspace"],
"network_allowlist": [],
"cpu_shares": 1024,
"memory_mb": 1024,
"pids_limit": 256,
"wall_clock_seconds": 300,
"output_bytes_limit": 1048576,
"base_image": "bigwave/sandbox-base:latest"
}curl -H "Authorization: Bearer $BIGWAVE_ADMIN_TOKEN" \
http://localhost:8000/admin/sandbox/policyPUT /admin/sandbox/policy
Body must be a full SandboxPolicy document — including workspace_id, which must equal the caller's workspace. Cross- tenant writes (policy.workspace_id != principal.workspace) are rejected with 403.
{
"workspace_id": "default",
"fs_allowlist": ["/workspace", "/data/shared-readonly"],
"network_allowlist": ["api.openai.com:443"],
"cpu_shares": 2048,
"memory_mb": 2048,
"pids_limit": 512,
"wall_clock_seconds": 600,
"output_bytes_limit": 4194304,
"base_image": "bigwave/sandbox-base:latest"
}Returns the persisted SandboxPolicy on success.
curl -X PUT -H "Authorization: Bearer $BIGWAVE_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d @policy.json \
http://localhost:8000/admin/sandbox/policyDELETE /admin/sandbox/policy
Drops the workspace override. Returns 204 No Content. Subsequent sandbox.start calls use the registry default.
Operator notes
- Workspace fence. All three routes scope to the bearer principal's workspace; you cannot read or replace another tenant's policy through this surface. The
403onpolicy.workspace_idmismatch is an extra belt-and-braces check on top of the principal-derived workspace. See workspace fence. - Default policy. The registry default is read from
BIGWAVE_SANDBOX_DEFAULT_POLICY(or the in-tree fallback); see the configuration reference.GETalways returns something — either an override or the default. - Atomic replace.
PUTis full-replace. Edit the document client-side and re-upload. - Hot-reload. The next
sandbox.startcall picks up the new policy without a process restart. In-flight sandboxes keep their original policy until they exit. 503causes.app.state.sandbox_policy_registryis wired in lifespan; routes return503with"sandbox_policy_registry not initialised"when the lifespan did not complete or sandbox support is disabled.- Related concept. See the agent harness for how the sandbox primitive fits the broader tool-orchestration story.