feat(sandbox): cross-family file sandbox — one policy home, sandboxed fs provider, fs escalation parity
Extend SandboxMode enforcement from bash to the filesystem tools, the sandbox RFC's deferred cross-family phase. - dsh-sandbox-policy (new, ctx.sandboxPolicy): the single home for the deployment default mode + workspaceRoot and the per-session override event, renamed bash/sandbox-mode -> sandbox/mode and moved here with its fold/setter. Decouples the bash seam from dsh-session. - dsh-fs-sandbox (new): SandboxedFileSystem extends LocalFileSystem and fences write/edit by the per-call mode (read-only denies, workspace-write contains to the workspace + temp roots via the shared writableRoots, danger passes through); reads pass through. Structured FS_SANDBOX_DENIED; in-lock parent re-canonicalization. A policy fence in trusted code, not a kernel boundary. - dsh-sandbox: the shared escalation kit (writableRoots, the strictly-wider ladder, denial/hint markers, approveEscalation) both tool families use; approveEscalation takes a structural approver so dsh-sandbox gains no approval/agent dependency, and both tools stay duplication-free. - tool-fs: write/edit advertise sandbox_permissions/justification under a confining ctx.fs, map FS_SANDBOX_DENIED to the shared [sandbox: ...] marker, and resolve the same one-approved-wider retry. - examples/acp-agent: composes sandbox-policy + fs-sandbox, drops the gating that disabled the fs stack under confined modes. RFC docs/rfc/implemented/feature/2026-07-14-cross-family-fs-sandbox.md; the old sandbox RFC's In-process/deferred/FAQ sections updated to shipped fact.
This commit is contained in:
@@ -201,7 +201,7 @@ Single-slot decision: produce the optional version guard for the next FileSystem
|
||||
|
||||
Types: [FsTarget](../core-data-structures/filesystem.md) · [FsVersion](../core-data-structures/filesystem.md)
|
||||
|
||||
Source: [`packages/fs/fs/src/index.ts:123`](../../packages/fs/fs/src/index.ts)
|
||||
Source: [`packages/fs/fs/src/index.ts:124`](../../packages/fs/fs/src/index.ts)
|
||||
|
||||
### `fs/observed` — emit
|
||||
|
||||
@@ -213,7 +213,7 @@ Record that an actor observed a target at a version, after a successful read/wri
|
||||
|
||||
Types: [FsTarget](../core-data-structures/filesystem.md) · [FsVersion](../core-data-structures/filesystem.md)
|
||||
|
||||
Source: [`packages/fs/fs/src/index.ts:138`](../../packages/fs/fs/src/index.ts)
|
||||
Source: [`packages/fs/fs/src/index.ts:139`](../../packages/fs/fs/src/index.ts)
|
||||
|
||||
### `fs/write-intent` — waterfall
|
||||
|
||||
@@ -225,7 +225,7 @@ Single-slot decision: produce the write intent for the next FileSystem.writeText
|
||||
|
||||
Types: [FsTarget](../core-data-structures/filesystem.md) · [FsWriteIntent](../core-data-structures/filesystem.md)
|
||||
|
||||
Source: [`packages/fs/fs/src/index.ts:109`](../../packages/fs/fs/src/index.ts)
|
||||
Source: [`packages/fs/fs/src/index.ts:110`](../../packages/fs/fs/src/index.ts)
|
||||
|
||||
## `llm/*`
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ onTaskDone(listener: BashTaskListener): () => void
|
||||
|
||||
Types: [BashExecRequest](../core-data-structures/bash.md) · [BashExecSpec](../core-data-structures/bash.md) · [BashRunResult](../core-data-structures/bash.md) · [BashTask](../core-data-structures/bash.md) · [BashTaskRead](../core-data-structures/bash.md)
|
||||
|
||||
Source: [`packages/bash/bash/src/index.ts:62`](../../packages/bash/bash/src/index.ts)
|
||||
Source: [`packages/bash/bash/src/index.ts:61`](../../packages/bash/bash/src/index.ts)
|
||||
|
||||
## `ctx.codeRuntime` — `CodeRuntime` (abstract seam)
|
||||
|
||||
@@ -139,13 +139,13 @@ abstract stat(target: FsTarget, signal?: AbortSignal): Promise<FsInfo | undefine
|
||||
abstract readText(target: FsTarget, signal?: AbortSignal): Promise<string>
|
||||
abstract streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>>
|
||||
abstract listDir(target: FsTarget, signal?: AbortSignal): Promise<FsDirEntry[]>
|
||||
abstract writeText(target: FsTarget, content: string, expected?: FsWriteIntent, signal?: AbortSignal): Promise<FsWriteOutcome>
|
||||
abstract editText(target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion }, signal?: AbortSignal): Promise<FsEditOutcome>
|
||||
abstract writeText( target: FsTarget, content: string, expected?: FsWriteIntent, signal?: AbortSignal, sandboxMode?: SandboxMode, ): Promise<FsWriteOutcome>
|
||||
abstract editText( target: FsTarget, edit: FsEditRequest, expected?: { version: FsVersion }, signal?: AbortSignal, sandboxMode?: SandboxMode, ): Promise<FsEditOutcome>
|
||||
```
|
||||
|
||||
Types: [FsEditOutcome](../core-data-structures/filesystem.md) · [FsEditRequest](../core-data-structures/filesystem.md) · [FsInfo](../core-data-structures/filesystem.md) · [FsTarget](../core-data-structures/filesystem.md) · [FsVersion](../core-data-structures/filesystem.md) · [FsWriteIntent](../core-data-structures/filesystem.md) · [FsWriteOutcome](../core-data-structures/filesystem.md)
|
||||
Types: [FsEditOutcome](../core-data-structures/filesystem.md) · [FsEditRequest](../core-data-structures/filesystem.md) · [FsInfo](../core-data-structures/filesystem.md) · [FsTarget](../core-data-structures/filesystem.md) · [FsVersion](../core-data-structures/filesystem.md) · [FsWriteIntent](../core-data-structures/filesystem.md) · [FsWriteOutcome](../core-data-structures/filesystem.md) · [SandboxMode](../core-data-structures/sandbox.md)
|
||||
|
||||
Source: [`packages/fs/fs/src/index.ts:172`](../../packages/fs/fs/src/index.ts)
|
||||
Source: [`packages/fs/fs/src/index.ts:173`](../../packages/fs/fs/src/index.ts)
|
||||
|
||||
## `ctx.llm` — `LlmService`
|
||||
|
||||
@@ -174,7 +174,7 @@ set(session: Session, name: string): void
|
||||
|
||||
Types: [SessionEvent](../core-data-structures/core.md)
|
||||
|
||||
Source: [`packages/ui/permission/src/index.ts:115`](../../packages/ui/permission/src/index.ts)
|
||||
Source: [`packages/ui/permission/src/index.ts:118`](../../packages/ui/permission/src/index.ts)
|
||||
|
||||
## `ctx.sandbox` — `SandboxProvider` (abstract seam)
|
||||
|
||||
@@ -192,7 +192,13 @@ abstract confine(argv: readonly string[], policy: SandboxPolicy): ConfinedArgv
|
||||
|
||||
Types: [ConfinedArgv](../core-data-structures/sandbox.md) · [SandboxPolicy](../core-data-structures/sandbox.md)
|
||||
|
||||
Source: [`packages/sandbox/sandbox/src/index.ts:180`](../../packages/sandbox/sandbox/src/index.ts)
|
||||
Source: [`packages/sandbox/sandbox/src/index.ts:191`](../../packages/sandbox/sandbox/src/index.ts)
|
||||
|
||||
## `ctx.sandboxPolicy` — `SandboxPolicyService`
|
||||
|
||||
The sandbox-policy service (`ctx.sandboxPolicy`). Owns the deployment default mode and workspace root; enforcing implementations read defaultMode and workspaceRoot, and the tool layers fold each session's `sandbox/mode` override with effectiveSandboxMode on top.
|
||||
|
||||
Source: [`packages/sandbox/sandbox-policy/src/index.ts:60`](../../packages/sandbox/sandbox-policy/src/index.ts)
|
||||
|
||||
## `ctx.sessionPersistence` — `SessionPersistence` (abstract seam)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user