DeepSeek Harness: Sandbox and Approval
Last updated: 2026-08-31
An Agent's power lies in its ability to execute operations, but "can execute" doesn't mean "should execute." Approval policies are the Agent's brakes; sandboxes are the Agent's fences. Together, they let the Agent act freely within safe boundaries.
📋 Prerequisites: Completed 13-effect.md and 22-capability.md
1. What You'll Learn
- Approval policy
- Permission presets
- Dangerous operation approval popups
- Sandbox backend registration
- ctx.sandbox and ctx.shell
- Remote sandbox configuration
2. Approval Policy
(1) Policy Modes
DSH provides four approval modes:
| Mode | Behavior | Best For |
|---|---|---|
always |
Always allow, no popup | Safe operations (read, search) |
ask |
Requires approval, popup confirmation | Dangerous operations (create, edit, shell) |
ask_with_confirm |
Double-confirmation popup | Extremely dangerous operations (delete, sudo) |
deny |
Auto-deny | Operations that must never run (rm -rf /) |
(2) ▶ Example 2
# dsh.config.yaml
approval:
default: ask
tools:
file_edit:
read: always
create: ask
edit: ask
delete: ask_with_confirm
shell:
safe: always
moderate: ask
dangerous: ask_with_confirm
forbidden: deny
search:
default: always
sandbox:
default: ask
(3) ▶ Example 3
approval:
tools:
file_edit:
# Path whitelist auto-allow
auto_allow_paths:
- /tmp/**
- /workspace/**
# Path blacklist auto-deny
auto_deny_paths:
- /etc/**
- /var/**
shell:
# Command whitelist
auto_allow_commands:
- ls
- cat
- grep
- head
- wc
- git status
- git log
# Command blacklist
auto_deny_commands:
- rm -rf /*
- mkfs
- dd if=*
(4) ▶ Example 4
import { defineTool } from '@deepseek-ai/dsh'
export default defineTool({
name: 'db_query',
description: 'Execute SQL query',
parameters: { /* ... */ },
approval: {
level: 'ask',
rules: [
{ match: { query: /^SELECT/i }, level: 'always' },
{ match: { query: /^DROP/i }, level: 'deny' },
{ match: { query: /^INSERT|^UPDATE|^DELETE/i }, level: 'ask_with_confirm' }
]
},
async execute({ query }, ctx) {
return await ctx.database.query(query)
}
})
3. Permission Presets
(1) Built-in Presets
DSH provides three permission presets:
| Preset | Description | Typical Use |
|---|---|---|
| trusted | Trust mode, most operations auto-allowed | Personal dev environment |
| standard | Standard mode, dangerous operations need approval | Default configuration |
| restricted | Restricted mode, strict approval | Production environment |
(2) Preset Comparison
# trusted — Trust mode
approval:
tools:
file_edit: always
shell: always
search: always
# standard — Standard mode
approval:
tools:
file_edit:
read: always
create: ask
edit: ask
delete: ask_with_confirm
shell: ask
# restricted — Restricted mode
approval:
tools:
file_edit: ask_with_confirm
shell: deny
search: ask
(3) Choosing a Preset
# Select preset at startup
pnpm dsh web --preset trusted
pnpm dsh web --preset standard
pnpm dsh web --preset restricted
(4) Custom Presets
# dsh.config.yaml
approval:
presets:
my-team:
tools:
file_edit:
read: always
create: ask
edit: ask
delete: deny
shell: ask
4. Dangerous Operation Approval Popup
(1) Popup Mechanism
When a tool call requires approval, DSH pauses execution and shows an approval popup:
⚠️ Approval Required: Execute shell command
Command: npm install bcryptjs
Working directory: /home/alice/project
Risk level: MODERATE
[Allow] [Always for npm] [Deny]
(2) Approval Options
| Option | Description |
|---|---|
| Allow | Allow this operation |
| Always | Allow this type of operation (no more popups) |
| Always for X | Allow operations matching a specific rule |
| Deny | Deny this operation |
(3) Batch Approval
Multiple operations can be approved in batch:
⚠️ Batch Approval Required: 3 operations
1. file_edit: create src/utils.ts
2. file_edit: edit src/app.ts
3. shell: npm install bcryptjs
[Allow All] [Review Each] [Deny All]
(4) Approval Log
All approval decisions are recorded:
[approval] ALLOWED: file_edit(read, src/config.ts) — policy: always
[approval] ASKED: file_edit(create, src/utils.ts) — user: allowed
[approval] DENIED: shell(rm -rf /tmp/test) — policy: deny
5. Sandbox Backend Registration
(1) Sandbox Concept
A sandbox is an isolated environment for tool execution — Agent operations run inside the sandbox without affecting the host system:
graph LR
AGENT[Agent] -->|calls tools| SANDBOX[Sandbox environment]
SANDBOX -->|isolated execution| FS[Sandbox filesystem]
SANDBOX -->|isolated execution| SHELL[Sandbox Shell]
SANDBOX -->|isolated network| NET[Sandbox network]
SANDBOX -.->|not allowed| HOST[Host system]
(2) Sandbox Backend Interface
interface SandboxBackend {
name: string
execute(command: string, options: ShellOptions): Promise<ShellResult>
readFile(path: string): Promise<string>
writeFile(path: string, content: string): Promise<void>
stat(path: string): Promise<FileStat>
readdir(path: string): Promise<DirEntry[]>
}
(3) Registering a Sandbox Backend
import { Service, Context } from '@deepseek-ai/cordis'
export default class DockerSandboxBackend extends Service {
constructor(ctx: Context) {
super(ctx, 'sandbox')
ctx.implement(SandboxCapability, {
name: 'docker-sandbox',
async execute(command, options) {
const container = await this.getContainer()
const result = await container.exec(command, options)
return result
},
async readFile(path) {
const container = await this.getContainer()
return await container.readFile(path)
},
async writeFile(path, content) {
const container = await this.getContainer()
await container.writeFile(path, content)
},
// ...
})
}
}
(4) Configuring a Sandbox
# dsh.config.yaml
sandbox:
backend: docker
config:
image: dsh-sandbox:latest
workdir: /workspace
memory: 512m
cpus: 1
timeout: 30000
network: none
6. ctx.sandbox and ctx.shell
(1) ctx.sandbox
ctx.sandbox provides sandboxed file operations:
export const inject = ['sandbox']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'sandbox_read',
description: 'Read file in sandbox',
parameters: {
type: 'object',
properties: {
path: { type: 'string', description: 'File path in sandbox' }
},
required: ['path']
},
async execute({ path }, ctx) {
const content = await ctx.sandbox.readFile(path)
return { content }
}
}))
}
(2) ctx.shell
ctx.shell executes commands inside the sandbox:
export const inject = ['shell']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'sandbox_exec',
description: 'Execute command in sandbox',
parameters: {
type: 'object',
properties: {
command: { type: 'string', description: 'Command to execute' }
},
required: ['command']
},
async execute({ command }, ctx) {
const result = await ctx.shell.execute(command, {
cwd: '/workspace',
timeout: 30000
})
return {
stdout: result.stdout,
stderr: result.stderr,
exitCode: result.exitCode
}
}
}))
}
(3) sandbox vs Direct fs
| Operation | Direct fs | ctx.sandbox |
|---|---|---|
| File paths | Host system paths | Sandbox-internal paths |
| Permissions | Host user permissions | Sandbox user permissions |
| Isolation | None | Fully isolated |
| Performance | Fast | Slightly slower (through sandbox layer) |
(4) Safe Usage Principles
// ❌ Direct host filesystem access
import { readFileSync } from 'fs'
const content = readFileSync('/etc/passwd')
// ✅ Through sandbox
const content = await ctx.sandbox.readFile('/etc/passwd')
// → If sandbox has filesystem isolation, this call will be restricted
7. Remote Sandbox Configuration
(1) Remote Sandbox Architecture
graph TB
DSH[DSH Agent] -->|HTTP API| API[Sandbox API Server]
API -->|manages| CONTAINER1[Container 1<br/>Agent A]
API -->|manages| CONTAINER2[Container 2<br/>Agent B]
CONTAINER1 --> FS1[Isolated filesystem 1]
CONTAINER2 --> FS2[Isolated filesystem 2]
(2) Configuring a Remote Sandbox
# dsh.config.yaml
sandbox:
backend: remote
config:
endpoint: http://sandbox-server:8080
apiKey: sk-sandbox-xxx
defaultImage: dsh-sandbox:latest
maxContainers: 10
containerTimeout: 3600
allowedImages:
- dsh-sandbox:latest
- dsh-sandbox-python:latest
(3) Remote Sandbox Backend Implementation
export default class RemoteSandboxBackend extends Service {
private endpoint: string
private apiKey: string
constructor(ctx: Context) {
super(ctx, 'sandbox')
this.endpoint = ctx.config.endpoint
this.apiKey = ctx.config.apiKey
}
async execute(command: string, options: ShellOptions): Promise<ShellResult> {
const response = await fetch(`${this.endpoint}/execute`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`
},
body: JSON.stringify({ command, ...options })
})
return await response.json()
}
async readFile(path: string): Promise<string> {
const response = await fetch(`${this.endpoint}/read`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${this.apiKey}` },
body: JSON.stringify({ path })
})
const data = await response.json()
return data.content
}
// ...
}
(4) Sandbox Lifecycle
1. Agent session created → Request sandbox container
2. Sandbox API creates container → Return container ID
3. Agent operations execute inside container
4. Agent session destroyed → Request container destruction
5. Sandbox API destroys container → Release resources
❓ FAQ
--preset trusted auto-allows most operations. But not recommended for production.📖 Summary
- Approval policy four modes: always/ask/ask_with_confirm/deny
- Permission presets: trusted (auto-allow), standard (need approval), restricted (strict approval)
- Approval popups pause Agent execution, waiting for user decision
- Sandbox backends register via SandboxCapability interface, supporting Docker/remote/custom implementations
- ctx.sandbox and ctx.shell execute operations inside the sandbox, isolated from the host system
- Remote sandboxes manage via HTTP API, supporting multi-container isolation
📝 Exercises
1. ⭐ Basic: Configure DSH with the standard preset, try having the Agent execute ls (auto-allowed) and rm (needs approval), and observe the approval popup behavior.
2. ⭐⭐ Intermediate: Add approval rules to a custom tool — SELECT queries auto-allowed, INSERT/UPDATE/DELETE need approval, DROP auto-denied. Test each SQL type's approval behavior.
3. ⭐⭐⭐ Challenge: Implement a simple sandbox backend (using subprocess isolation) and register it with DSH. Have the Agent execute commands inside the sandbox, verifying: 1) file operations are restricted to the sandbox directory; 2) network requests are blocked; 3) files are cleaned up after sandbox destruction.