description: "The sandbox-consuming PowerShell executor for deployments and maintainers choosing, configuring, or debugging confined PowerShell command execution with denial facts."
English | 中文
dsh-pwsh-sandbox is the sandbox-consuming PowerShell executor: every command runs as a fresh pwsh -Command process confined through the ctx.sandbox capability, with the selected mode, enforcement, and denial facts stamped on each settled result. On Windows the sandbox seam resolves to the ACL restricted-token runner chain; on Linux and macOS it uses bwrap, Landlock, or Seatbelt. When no runner can enforce a confined mode, the call fails closed with a structured SANDBOX_UNAVAILABLE error rather than running unconfined. It is the pwsh twin of dsh-bash-sandbox, mirroring it call-for-call.
Mount this executor instead of dsh-pwsh-local when PowerShell commands must not run with the harness process's full file authority. It registers as ctx.shell, inherits dsh-pwsh-local's process mechanics, and requires a ctx.sandbox provider plus ctx.sandboxPolicy.
Choose it when a deployment needs file-level confinement for PowerShell commands, typically on Windows. The confinement substance is platform-neutral: the sandbox seam picks the platform's runner — the ACL restricted-token chain on Windows, bwrap/Landlock/Seatbelt elsewhere — while this executor owns the pwsh side. The sandbox policy (mode plus workspace root) is not this package's config: it rides each call from ctx.sandboxPolicy, with tool calls passing the calling session's resolved policy and direct calls falling back to deployment policy.
| Mode | File effects |
|---|---|
read-only (default) |
Writes are denied; the boundary stays partial because the restricted token retains Everyone |
workspace-write |
Writes under the policy's workspace root plus a private temp directory; TMP/TEMP are rewritten to it before spawning |
danger-full-access |
No confinement; the provider is never consulted, and results carry sandbox: { mode, denied: false } |
On Windows, mount the ACL restricted-token provider; on Linux and macOS, mount the local runner provider instead. The executor's own config is the local pwsh executor's knobs verbatim; the generated configuration catalog is the exhaustive source.
- id: sandbox
name: '@deepseek-ai/dsh-sandbox-windows-acl'
- id: sandbox-policy
name: '@deepseek-ai/dsh-sandbox-policy'
config:
mode: read-only
workspaceRoot: !!js process.cwd() # fallback for calls without a session cwd
- id: bash
name: '@deepseek-ai/dsh-pwsh-sandbox'
A denied command is reported as a fact: the result carries sandbox: { mode, denied: true }, and the tool layer converts it into the standard permission-denied surface — the same one the bash tool uses. When escalation is available, the model may retry the exact command once with the narrowest wider mode and a one-sentence justification; the approval prompt asks the user, and nothing executes before approval. This executor never negotiates permissions itself.
If no runner can enforce a confined mode, the foreground call fails with SANDBOX_UNAVAILABLE and a background process records a runner-failure fact — never a silent unconfined run. A provider rejection is attributed to the confinement runner only when its ENOENT/EACCES path or syscall independently names argv[0]; otherwise it keeps the local executor's stage-neutral provider-failure semantics.
Read these pages when the executor contract is not enough. They move from the seam to the confinement backends and the pwsh tool.
The confined command's own stderr — for example Access to the path '...' is denied. under the Windows ACL runner; the tool layer converts classified denials into the standard permission-denied surface exactly as it does for the bash tool.
No model-visible text beyond the command's stderr and the tool layer's standard denial surface.
None directly; the denial surface belongs to the tool layer.
These limits define when this executor is only a partial boundary on Windows. They are current package constraints, not a roadmap.
@deepseek-ai/dsh-sandbox-windows-acl.TMP/TEMP to the private directory before spawning.> $null redirection still works without opening NUL.