Skip to content

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 ​

MethodPathAuthSummary
GET/admin/sandbox/policyBearerRead the workspace's resolved policy (falls back to default).
PUT/admin/sandbox/policyBearerUpsert the workspace's policy.
DELETE/admin/sandbox/policyBearerDrop 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.

json
{
  "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"
}
bash
curl -H "Authorization: Bearer $BIGWAVE_ADMIN_TOKEN" \
  http://localhost:8000/admin/sandbox/policy

PUT /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.

json
{
  "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.

bash
curl -X PUT -H "Authorization: Bearer $BIGWAVE_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @policy.json \
  http://localhost:8000/admin/sandbox/policy

DELETE /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 403 on policy.workspace_id mismatch 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. GET always returns something — either an override or the default.
  • Atomic replace. PUT is full-replace. Edit the document client-side and re-upload.
  • Hot-reload. The next sandbox.start call picks up the new policy without a process restart. In-flight sandboxes keep their original policy until they exit.
  • 503 causes. app.state.sandbox_policy_registry is wired in lifespan; routes return 503 with "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.

Dual-licensed: MIT OR Apache-2.0