Overview
dsh-sandbox-local
dsh-sandbox seam. It selects and caches one platform runner: Linux prefers a working bwrap then Landlock; macOS uses Seatbelt; Windows uses the ACL restricted-token runner. Multiple candidates are probed in order, while a sole candidate is selected directly.This is an atomic module already shipped with Harness, not a standalone profile layer.
Capabilities
What it contributes
README / EN
Package documentation
@deepseek-ai/dsh-sandbox-local
English | 中文
Local implementation of the dsh-sandbox seam. It selects and caches one platform runner: Linux prefers a working bwrap then Landlock; macOS uses Seatbelt; Windows uses the ACL restricted-token runner. Multiple candidates are probed in order, while a sole candidate is selected directly.
The package root exports the default and named LocalSandboxProvider plugin and Config; platform profile builders stay internal.
Unsupported platforms and unusable runners fail closed with SANDBOX_UNAVAILABLE; execution never silently falls through unconfined. Each wrap carries structured runner-failure rules so consumers can distinguish a broken sandbox from a command failure. The sandbox Agent Note owns selection rationale and profile differences.
Policy is per call; the provider stores only the mechanism and cached runner verdict. Each wrap reports enforcement completeness plus backend-specific denial signatures and runner-failure rules. Landlock requires exit 125 and a landlock-run: fatal line after excluding only the exact partial-enforcement notice; a notice with child exit 1, 2, or 125 remains a child outcome. Bubblewrap and Seatbelt remain signature-only because neither public contract reserves a launcher-failure status. Consumers spawn the returned argv directly, so a missing or unexecutable runner is an out-of-band spawn failure while a successfully launched child exit 126 or 127 remains ordinary. runnerCommand skips probes and requires one or more non-empty, single-line, case-insensitive runnerFailureSignatures entries for the custom runner's own fatal dialect. Because its mechanism is unknown, it carries both Linux denial dialects. probeTimeoutMs bounds functional probes. The sandbox Agent Note owns selection and failure semantics.
The Seatbelt profile is allow-default with (deny file-write*) plus write allow-lists, so exactly the mode's promised file effects are governed: read-only grants the /dev/null literal alone; workspace-write adds the workspace root, /tmp, and the per-user darwin temp dir (os.tmpdir() — the platform's real temp area for mkstemp-family tools), every root canonicalized because Seatbelt matches resolved paths (/tmp IS /private/tmp). Apple marks the sandbox-exec CLI deprecated but ships it on every macOS; the functional probe is what fails closed if that ever changes.
The Windows rung keeps one deterministic write SID and standing ACE per workspace, but gives every live session/workspace pair a random private temp directory with a distinct SID and revocable ACE. Sessions sharing a workspace therefore share its intended write authority without inheriting one another's temp authority. A fresh provider always chooses a new temp path and SID, so crash residue cannot block or authorize a resumed session; agentless calls receive the same per-invocation isolation from the runner. A workspace equal to or containing the platform temp root fails before any ACL mutation because its inheritable workspace ACE would otherwise reach every private temp child.
@deepseek-ai/node-addon-landlock-run supplies the platform launcher, functional probe, and CLI argument vocabulary. This provider owns only mode-to-grant mapping and runner selection. Keeping path resolution and probe parsing with the versioned binary prevents contract drift.
- id: sandbox
name: '@deepseek-ai/dsh-sandbox-local'
Consumers: @deepseek-ai/dsh-bash-sandbox; see the acp-agent example for the runnable default composition.
Model Experience
Indirectly, through dsh-bash-sandbox and dsh-tool-bash, which render this provider's enforcement and denial facts while the dsh-sandbox seam owns the SANDBOX_UNAVAILABLE text and runner selection and profiles stay outside context.
KV Cache effect
No direct invalidation; the named consumer owns any request-prefix changes.
Known Limitations and Deferred Work
- Windows ACL enforcement is partial — the restricted token must retain Everyone for process initialization, so external objects granting Everyone write access remain writable; NTFS hard links also alias one file object across workspace and external paths. The provider reports
enforcement: 'partial'rather than overstating that boundary as full. - Landlock may be partial — older supported kernel ABIs confine only the access classes they expose, reported as
enforcement: 'partial'rather than overstated as full. - Seatbelt depends on deprecated
sandbox-exec— macOS still ships it, but this provider cannot replace or probe that private policy engine if Apple removes it. - Runner selection is cached for the provider lifetime — installing, removing, or repairing a runner requires reloading the plugin before selection changes.
runnerCommandis an operator assertion — a configured custom runner skips functional probes and is assumed to implement the bwrap-compatible profile honestly; if it is itself a Bash script, its interpreter startup runs before that script applies confinement.
LIMITATIONS
Known limitations
- **Windows ACL enforcement is partial** — the restricted token must retain Everyone for process initialization, so external objects granting Everyone write access remain writable; NTFS hard links also alias one file object across workspace and external paths. The provider reports `enforcement: 'partial'` rather than overstating that boundary as full. - **Landlock may be partial** — older supported kernel ABIs confine only the access classes they expose, reported as `enforcement: 'partial'` rather than overstated as full. - **Seatbelt depends on deprecated `sandbox-exec`** — macOS still ships it, but this provider cannot replace or probe that private policy engine if Apple removes it. - **Runner selection is cached for the provider lifetime** — installing, removing, or repairing a runner requires reloading the plugin before selection changes. - **`runnerCommand` is an operator assertion** — a configured custom runner skips functional probes and is assumed to implement the bwrap-compatible profile honestly; if it is itself a Bash script, its interpreter startup runs before that script applies confinement.
