4.0 KiB
Docker execution sandbox
Status: implementation prepared; Docker Engine/Compose are not installed on the development host, so image build and runtime isolation tests have NOT been executed. Existing localhost:5173 is still the host process, not this sandbox.
Scope
An instance contains the complete Fastify/Pi runtime and its child processes, not only the PPT worker. Non-root UID 1000, read-only rootfs, no capabilities, no privilege escalation, CPU/RAM/PID limits, default Docker seccomp, no host PID/network namespace, no Docker socket, no home or project bind mount. Source/dependencies and three explicitly selected Skills are baked into the image. Extensions remain disabled.
Each Compose project name receives a separate named data volume. This is instance isolation, not automatic per-message/per-task containers, and not tenant isolation within one instance. Do not share one instance across mutually untrusted users. The supervisor stops after one hour; data remains in its volume. Named volumes have no disk quota here.
Start (once Docker Engine + Compose are installed)
From the project directory:
node sandbox/manage.mjs start demo
node sandbox/manage.mjs verify demo
Open http://localhost:15173/ — it does not replace the existing port 5173 host service. Set the same model URL/name in the new UI. .env is used only as Compose interpolation input; only explicitly listed keys/tokens are passed. It is never copied or mounted. Container code can access those supplied credentials; use scoped, revocable keys. No fallback to host execution occurs if Docker or a runtime dependency is unavailable.
Stop/remove containers while retaining reports:
node sandbox/manage.mjs stop demo
For a separate isolated instance, choose another name and SANDBOX_PORT. Do not reuse an old data volume for untrusted new work.
Network
The agent connects only to an internal Docker network. A separate CONNECT proxy permits port 443 to exact names from SANDBOX_EGRESS_HOSTS (default: current model gateway and SW Ads MCP). The proxy resolves IPv4, rejects private/reserved and mixed public/private answers, then connects to the checked address. Arbitrary websites and web searches are blocked by default. Add only reviewed exact hostnames; do not add wildcards. Libraries that ignore the proxy must fail, not receive a direct route.
This is constrained HTTP(S) egress, not a complete data-loss-prevention system. The configured model/provider can receive data, allowed servers can themselves relay traffic, Docker DNS is not a general DNS-exfiltration firewall, and a kernel/container-runtime vulnerability can break isolation. Do not treat this as adequate for hostile multi-tenant execution without further hardening/rootless Docker or stronger isolation.
PPT support (optional, unverified in container)
The private artifact runtime is not available from the public package registry. Without it, PPT generation fails explicitly. To enable, set PPT_RUNTIME_HOST_DIR to the exact bundled dependencies directory and PPT_SKILL_HOST_DIR to the exact presentations skill directory. The launcher adds compose.sandbox-ppt.yaml, mounting only these two paths read-only at fixed container paths. Never set either path to a home directory or repository root. Host runtime binaries must be Linux-compatible with the container; fonts/native dependencies and full rendering need actual container validation.
Verification
Static/unit: node --test sandbox/*.test.mjs.
Runtime: node sandbox/manage.mjs verify demo checks actual container configuration, writable scope and blocked direct egress. Also test approved model HTTPS, denied private/unknown targets, cancellation/TTL, report download and restart persistence before trusting deployment. No authentication or multi-tenant authorization is added by this change.
References: https://docs.docker.com/reference/compose-file/services/ ; https://docs.docker.com/engine/security/rootless/ ; https://nodejs.org/api/cli.html#node_use_env_proxy1