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.
This commit is contained in:
kingwl
2026-07-09 15:42:37 +08:00
parent 80d8726601
commit 7b8c3a9b40
30 changed files with 2007 additions and 3 deletions
+16
View File
@@ -157,6 +157,22 @@ Types: [GenerateOptions](../core-data-structures/core.md) · [StreamChunk](../co
Source: [`packages/llm/llm/src/index.ts:88`](../../packages/llm/llm/src/index.ts)
## `ctx.sandbox` — `SandboxProvider` (abstract seam)
Abstract process-sandbox service. Subclass, implement confine, and load the subclass as a plugin — it registers as `ctx.sandbox` (one implementation per context; loading a second throws, cordis' standard duplicate-service behavior).
Semantics every implementation must honor:
- confine either returns an argv whose runner ENFORCES the policy or fails closed — at `confine` time with SandboxUnavailableError (no backend for this host), or at EXECUTION time by the runner itself refusing to run the command (exiting without exec'ing it, identified by ConfinedArgv.runnerFailureSignatures). A silent unconfined passthrough is never a legal outcome on either path.
- Probing exists to ARBITRATE between multiple candidate backends and may be skipped when a platform has exactly one: the sole candidate is selected directly and the runner's exec-time fail-closed refusal carries the safety property. When probing does run, it is functional (actually enforcing a profile, not a version check), at most once per provider lifetime; `confine` itself spawns nothing beyond that one-time probing.
- The returned ConfinedArgv.enforcement states the backend's actual completeness for THIS host; `partial` is reported, never silently upgraded to `full`.
```ts cordis-catalog
abstract confine(argv: readonly string[], policy: SandboxPolicy): ConfinedArgv
```
Source: [`packages/sandbox/sandbox/src/index.ts:180`](../../packages/sandbox/sandbox/src/index.ts)
## `ctx.sessionPersistence` — `SessionPersistence` (abstract seam)
Abstract durable session-persistence service. Subclass, implement the abstract methods, and load the subclass as a plugin — it registers as `ctx.sessionPersistence` (one implementation per context; loading a second throws, cordis' standard duplicate-service behavior).