deepseek-harness/packages/sandbox/sandbox/README.md
kingwl 7b8c3a9b40 feat(sandbox): the confinement seam and the per-platform native runner chains
ctx.sandbox (dsh-sandbox): confine(argv, policy) returns the argv to spawn
instead — wrapped so the process and its children run confined — plus the
enforcement completeness and the backend denial/runner-failure dialects;
no usable backend throws the fail-closed SANDBOX_UNAVAILABLE. Policy rides
per call. dsh-sandbox-local selects by platform and caches the verdict:
multi-candidate chains probe FUNCTIONALLY in preference order (Linux:
bwrap → the registry-installed node-addon-landlock-run launcher), a sole
candidate is selected unprobed (darwin: sandbox-exec/Seatbelt) and fails
closed at execution via runnerFailureSignatures; win32 is a reserved empty
chain. Profile parity is honest per backend (documented temp-area and ABI
differences; enforcement full|partial is a structured result fact).

CI: the sandbox-e2e matrix proves real-kernel confinement per rung (bwrap,
Landlock per architecture through the registry-installed launcher,
Seatbelt), failing on a silent all-skip; the packed-install rehearsal
installs the launcher family from the registry and asserts the binary
executable apart from kernel enforcement.
2026-07-10 15:43:02 +08:00

2.1 KiB

@deepseek-ai/dsh-sandbox

Abstract process-sandbox seam. Owns the ctx.sandbox service contract (SandboxProvider) and the confinement vocabulary the harness shares: SandboxMode (read-only / workspace-write / danger-full-access, file effects only), SandboxEnforcement (full / partial, per kernel ABI), SandboxPolicy (per-CALL policy — mode + workspace root), and the fail-closed SANDBOX_UNAVAILABLE error. Interface package of the capability-seam split: depends only on cordis (+ the harness error base), never on a backend.

The contract in one line: ctx.sandbox.confine(argv, policy) returns the argv to spawn INSTEAD of your own — wrapped so the process (and everything it spawns) runs confined — plus two facts about the selected backend: the enforcement completeness it achieves and its denial dialect (denialSignatures, the stderr substrings its kernel prints on a denied file effect — what stderr-inferring consumers match instead of a cross-backend union); when no backend is usable it throws rather than passing the argv through unconfined.

Policy rides the call, not the provider: two consumers may confine under different policies at the same instant (bash under read-only while a confined child agent keeps its state directory writable), and an approved escalated retry is just a new call with a wider policy.

Same-world confinement only. A backend shares the host's filesystem and kernel (bwrap, Landlock, Seatbelt); workspaceRoot names a real host path. Containers, microVMs, and remote executors are NOT backends of this seam — they replace whole capability implementations (ctx.bash, ctx.fs) as environment-coherent groups. The boundary and its rationale: the sandbox RFC.

Implementations: @deepseek-ai/dsh-sandbox-local (Linux: bwrap, else the per-platform Landlock launcher; macOS: sandbox-exec/Seatbelt). The staged first consumer is the sandboxed bash executor (wrapping ['bash', '-c', command]).