fix(sandbox): preserve filesystem cwd semantics

This commit is contained in:
Tianyi Cui
2026-07-21 19:53:02 +08:00
parent 7677d49c93
commit ae98294ec5
14 changed files with 119 additions and 27 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ The contract in one line: `ctx.sandbox.confine(argv, policy)` returns the argv t
Policy rides the call, not the provider: two consumers may confine under different policies at the same instant (bash under `read-only` while a confined child agent keeps its state directory writable), and an approved escalated retry is just a new call with a wider policy.
**Same-world confinement only.** A backend shares the host's filesystem and kernel (`bwrap`, Landlock, Seatbelt); `workspaceRoot` names a real host path. Containers, microVMs, and remote executors are NOT backends of this seam — they replace whole capability implementations (`ctx.bash`, `ctx.fs`) as environment-coherent groups. The boundary and its rationale: [the sandbox Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md).
**Same-world confinement only.** A backend shares the host's filesystem and kernel (`bwrap`, Landlock, Seatbelt); `workspaceRoot` names the filesystem-canonical real host directory. Workspace identity is resolved before lexical normalization, so a valid cwd containing `symlink/..` grants the directory where `chdir` actually lands rather than an unrelated lexical parent. Containers, microVMs, and remote executors are NOT backends of this seam — they replace whole capability implementations (`ctx.bash`, `ctx.fs`) as environment-coherent groups. The boundary and its rationale: [the sandbox Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md).
Implementations: [`@deepseek-ai/dsh-sandbox-local`](../sandbox-local/) (Linux: `bwrap`, else the per-platform Landlock launcher; macOS: `sandbox-exec`/Seatbelt). Consumers: [`@deepseek-ai/dsh-bash-sandbox`](../../bash/bash-sandbox/) (wraps `['bash', '-c', command]`).
+6 -2
View File
@@ -29,9 +29,13 @@ import type { SandboxExecutionPolicy } from './index.ts'
*/
export function canonicalPath(path: string): string {
try {
return realpathSync(path)
// Node's JavaScript realpath implementation lexically collapses `..`
// before resolving a preceding symlink on some platforms. The native
// implementation follows the filesystem's component-by-component lookup,
// matching chdir/spawn and the enforcement layers this identity feeds.
return realpathSync.native(path)
} catch {
// realpathSync failed: the path (or a prefix) is missing or unreadable.
// realpathSync.native failed: the path (or a prefix) is missing or unreadable.
return path
}
}