sand-boxer/docs/runbooks/profile-bwrap-local.md
tegwick b6655d8859
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Add bounded stdin to owner execution
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a06def-6490-7033-8448-2eab2d12ed44
2026-09-04 22:30:11 +02:00

94 lines
3 KiB
Markdown

# Runbook: profile.bwrap-local owner execution
`profile.bwrap-local` copies the requested repository into an owner-managed
workspace and starts a bubblewrap namespace with network default-deny. Commands
must cross the sand-boxer owner boundary; direct namespace entry is unsupported.
## Create with governed identity
```bash
sandboxer create \
--profile profile.bwrap-local \
--input repo=/path/to/repository \
--actor agt \
--project glas-harness \
--session-id session-123 \
--run-id run-456
```
Keep the returned sandbox id. The source path is copied; it is not mounted into
the namespace.
## Execute as the local owner
```bash
sandboxer exec SANDBOX_ID \
--actor agt \
--project glas-harness \
--session-id session-123 \
--run-id run-456 \
-- python3 -c 'from pathlib import Path; print(Path.cwd())'
```
The result records the bound identity, profile and extension, command name,
exit/timeout outcome, workspace, and declared network posture. Captured stdout
and stderr default to 256 KiB per stream and the timeout defaults to 15 minutes.
Credential values are never command options or environment assignments. A rein
that owns credential acquisition may receive only a catalog identifier, for
example `--credential-route-ref rein-openweights-openrouter-approle`; inside the
sandbox that appears as the value-free JSON list
`SANDBOXER_CREDENTIAL_ROUTE_REFS`. The selected rein resolves and cleans up the
credential through its approved owner-fronted route.
## Resident owner API
The high-risk HTTP route is disabled unless the service process receives
`SANDBOXER_EXEC_TOKEN` through its approved service credential delivery path.
Before provisioning that credential, locate its custody route with `warden route
find "sand-boxer owner execution service credential" --json`; do not paste it
into a shell history, workplan, State Hub, or sandbox mount.
Call `POST /v1/sandboxes/SANDBOX_ID/exec` with a bearer token and this body:
```json
{
"command": ["python3", "-V"],
"consumer": {
"actor": "agt",
"project": "glas-harness",
"session_id": "session-123",
"run_id": "run-456"
},
"credential_route_refs": [],
"stdin_text": null,
"timeout_seconds": 30,
"max_output_bytes": 65536
}
```
The bearer authenticates access to the owner service; exact consumer identity
matching additionally binds the command to the existing sandbox grant.
`stdin_text` is capped at 1,000,000 UTF-8 bytes and is not returned or logged.
## Destroy
```bash
sandboxer destroy SANDBOX_ID
```
Destroy kills the namespace process group and removes the copied workspace.
The namespace is not tied to the process that handled `create`, because the
resident API handles create and exec as separate requests. TTL expiry and the
stale-resource reaper provide crash recovery for an owner service that exits
before explicit destroy.
For a non-secret create/execute/source-absence/destroy proof, run:
```bash
make smoke-bwrap-exec
make smoke-bwrap-owner-api
```
The second target exercises the bearer-protected HTTP route with the real bwrap
backend, not a mocked manager.