Files
deepseek-harness/packages/sandbox/sandbox-local
imccyu a213befd0f build(release): publish the vendored framework and the native packages publicly
The three release sequences shipped with publishConfig.access: restricted, so
nothing in the @deepseek-ai scope was installable from outside the organization.

A restricted dependency is what actually blocks a public consumer: every harness
package declares the vendored framework as a peerDependency, and
dsh-sandbox-local declares the Landlock entry as a dependency. Those two
sequences therefore go public first — the nine vendor/* packages and the three
native/landlock-run packages — while the dsh family stays restricted until its
own sequence is opened deliberately. No public package requires a restricted one
in this arrangement.

Access is now per sequence, so no publish path can pass --access: one flag
cannot express two levels and would override the manifest that owns the fact.
publish.ts stops passing it, matching the native workflow, and
check-workspace-constraints holds each manifest to its own sequence's level,
which is what stops the scope from drifting one package at a time.

Harness consumers reference the Landlock entry as workspace:^ instead of
workspace:*, so a published harness package accepts the entry's patch and minor
releases. The entry keeps workspace:* for its platform packages, where the
binary must match the entry version exactly.

Two rationales that named a private registry no longer describe the vendored
sequence; they now state the durable reason, which is that the verification must
not depend on the registry already carrying matching versions.
2026-08-13 14:05:48 +08:00
..

@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.
  • 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.