The `readDenyPaths` policy field shipped in the previous commit broke Linux confinement outright. bwrap has to create the `/dev/null` bind's mount point inside a tree its own profile has already made read-only, so it refused the entire confinement whenever the parent directory was absent — every host that has not stored a credential yet, including a fresh install: bwrap: Can't mkdir parents for /home/runner/.dsh/.env: Read-only file system which the executor correctly classifies as SANDBOX_UNAVAILABLE, so every confined bash call failed closed. Landlock cannot subtract from its own `/` read grant, so it reported `partial` enforcement on every confined call for a file it never hid, with no way to switch the denial off (schemastery fills an omitted array with `[]`, so empty and omitted were indistinguishable). A protection that breaks confinement where it works and misreports it where it does not is worse than a documented absence. Revert the field, both expressible backends, the enforcement downgrade, and the policy default; state the residue plainly in the credentials-local READMEs — file mode stops other OS users, not the model — and keep the OS-keychain provider recorded as the real answer. The narrower discipline stands: no surface hoists the credential document into `process.env`, and the model is never handed a resolved path to it.
sandbox/ — process-sandbox capability family
English | 中文
The confinement half of the capability-seam split: an abstract provider interface, platform backends, and the shared policy home. Consumers hand ctx.sandbox the exact argv they are about to spawn and spawn the returned (wrapped) argv instead; a complete SandboxExecutionPolicy (mode + workspace root) rides each capability call, and its confined subset becomes the provider's SandboxPolicy. Different sessions and consumers can therefore confine under different policies at the same instant. All product packages.
| Package | Role | ctx key |
|---|---|---|
sandbox/ |
Abstract process-sandbox seam (the SandboxProvider contract + the mode/enforcement/policy vocabulary) plus the shared ESCALATION kit (approveEscalation, the strictly-wider ladder, the denial/hint markers) and the writableRoots derivation every enforcement dialect shares |
ctx.sandbox |
sandbox-local/ |
Local backends by platform chain: Linux bwrap else the landlock-run launcher (the npm-distributed node-addon-landlock-run family, built and released from its own repository), darwin sandbox-exec/Seatbelt — multi-candidate chains functionally probed, sole candidates selected directly, verdict cached, fail-closed |
(registers ctx.sandbox) |
sandbox-policy/ |
The policy resolver: deployment fallbacks plus each session's durable mode and immutable cwd root. Both enforcing families consume its complete per-call result, so bash and fs cannot confine to different roots | ctx.sandboxPolicy |
The seam confines SAME-WORLD subprocesses only (shared filesystem and kernel). Containers, microVMs, and remote executors are NOT backends here — they replace whole capability implementations (ctx.bash, ctx.fs) as environment-coherent groups; the boundary is recorded in the sandbox Agent Note.
Consumers today: bash/bash-sandbox (wraps ['bash', '-c', command] through ctx.sandbox) and fs/fs-sandbox (an in-process path fence, not an argv wrapper — reads ctx.sandboxPolicy and enforces the shared mode on write/edit). The cross-family boundary is the sandbox Agent Note's cross-family fs sandbox phase; the shared vocabulary lets both families teach the model one denial marker and one escalation flow.