deno-sandbox
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDeno Sandboxes
Deno 沙箱
Overview
概述
Deno Sandboxes provide secure, isolated environments for running untrusted code. Each sandbox runs in its own Linux microVM (using Firecracker, the same technology as AWS Lambda) with a separate filesystem, network, and process space. This makes them ideal for code playgrounds, AI agent tool execution, and multi-tenant applications.
Reference: https://deno.com/deploy/sandboxes
Deno沙箱提供安全、隔离的环境来运行不可信代码。每个沙箱在独立的Linux微虚拟机(使用Firecracker技术,与AWS Lambda采用的技术相同)中运行,拥有独立的文件系统、网络和进程空间。这使得它们非常适合代码游乐场、AI Agent工具执行以及多租户应用场景。
When to Use Sandboxes
何时使用沙箱
Use Deno Sandboxes when you need to:
- Run user-submitted code safely
- Execute AI-generated code
- Build code playground platforms
- Create multi-tenant code execution environments
- Run automated tests in isolation
在以下场景中可以使用Deno沙箱:
- 安全运行用户提交的代码
- 执行AI生成的代码
- 构建代码游乐场平台
- 创建多租户代码执行环境
- 在隔离环境中运行自动化测试
Scope Boundaries
范围边界
This skill applies only to Deno Sandbox () questions. Follow these rules:
@deno/sandbox- If the user asks about Docker containers, Node.js vm2/vm, Web Workers, AWS Lambda isolation, or any other isolation technology, answer using that technology directly. Do not suggest Deno Sandboxes as an alternative.
- Do not include imports,
@deno/sandbox, orSandbox.create()in responses about other isolation technologies.sandbox.spawn() - Only recommend Deno Sandboxes when the user explicitly asks about them or is building code execution features in a Deno project.
本技能仅适用于Deno Sandbox()相关问题。请遵循以下规则:
@deno/sandbox- 如果用户询问Docker容器、Node.js vm2/vm、Web Workers、AWS Lambda隔离或其他任何隔离技术,直接针对该技术进行解答,不要推荐Deno沙箱作为替代方案。
- 在解答其他隔离技术的问题时,不要包含导入、
@deno/sandbox或Sandbox.create()相关代码。sandbox.spawn() - 仅当用户明确询问Deno沙箱,或在Deno项目中构建代码执行功能时,才推荐使用Deno沙箱。
Getting Started
快速开始
Installation
安装
bash
deno add jsr:@deno/sandboxbash
deno add jsr:@deno/sandboxBasic Usage
基础用法
typescript
import { Sandbox } from "@deno/sandbox";
// Create a sandbox (auto-disposed when scope ends)
await using sandbox = await Sandbox.create();
// Run a command
const child = await sandbox.spawn("echo", { args: ["Hello from sandbox!"] });
const output = await child.output();
console.log(new TextDecoder().decode(output.stdout));
// Output: Hello from sandbox!typescript
import { Sandbox } from "@deno/sandbox";
// 创建沙箱(作用域结束时自动销毁)
await using sandbox = await Sandbox.create();
// 运行命令
const child = await sandbox.spawn("echo", { args: ["Hello from sandbox!"] });
const output = await child.output();
console.log(new TextDecoder().decode(output.stdout));
// 输出: Hello from sandbox!Core Concepts
核心概念
Sandbox Lifecycle
沙箱生命周期
Sandboxes are resources that must be disposed when done. Always use for automatic cleanup:
await usingtypescript
await using sandbox = await Sandbox.create();
// Sandbox is automatically destroyed when this scope endsCRITICAL: Never show without . Always use the pattern for sandbox creation. Do not show manual disposal alternatives.
const sandbox = await Sandbox.create()await usingawait using沙箱是需要在使用后销毁的资源。务必使用来实现自动清理:
await usingtypescript
await using sandbox = await Sandbox.create();
// 沙箱会在当前作用域结束时自动销毁重要提示:绝对不要在不使用的情况下编写。创建沙箱时必须使用模式,不要展示手动销毁的替代方案。
await usingconst sandbox = await Sandbox.create()await usingRunning Processes
运行进程
The method runs commands inside the sandbox:
spawntypescript
const child = await sandbox.spawn("deno", {
args: ["run", "script.ts"],
stdin: "piped", // Enable stdin
stdout: "piped", // Capture stdout
stderr: "piped", // Capture stderr
});
// Wait for completion and get output
const output = await child.output();
console.log("Exit code:", output.code);
console.log("Stdout:", new TextDecoder().decode(output.stdout));
console.log("Stderr:", new TextDecoder().decode(output.stderr));spawntypescript
const child = await sandbox.spawn("deno", {
args: ["run", "script.ts"],
stdin: "piped", // 启用标准输入
stdout: "piped", // 捕获标准输出
stderr: "piped", // 捕获标准错误
});
// 等待进程完成并获取输出
const output = await child.output();
console.log("退出码:", output.code);
console.log("标准输出:", new TextDecoder().decode(output.stdout));
console.log("标准错误:", new TextDecoder().decode(output.stderr));Streaming I/O
流式I/O
For interactive processes or long-running commands:
typescript
const child = await sandbox.spawn("deno", {
args: ["repl"],
stdin: "piped",
stdout: "piped",
});
// Write to stdin
const writer = child.stdin!.getWriter();
await writer.write(new TextEncoder().encode("console.log('Hello')\n"));
await writer.close();
// Read from stdout
const reader = child.stdout!.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log(new TextDecoder().decode(value));
}对于交互式进程或长时间运行的命令:
typescript
const child = await sandbox.spawn("deno", {
args: ["repl"],
stdin: "piped",
stdout: "piped",
});
// 写入标准输入
const writer = child.stdin!.getWriter();
await writer.write(new TextEncoder().encode("console.log('Hello')\n"));
await writer.close();
// 读取标准输出
const reader = child.stdout!.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log(new TextDecoder().decode(value));
}Killing Processes
终止进程
typescript
const child = await sandbox.spawn("sleep", { args: ["60"] });
// Kill with SIGTERM (default)
await child.kill();
// Or with specific signal
await child.kill("SIGKILL");
// Wait for exit
const status = await child.status;
console.log("Exited with signal:", status.signal);typescript
const child = await sandbox.spawn("sleep", { args: ["60"] });
// 使用SIGTERM信号终止(默认)
await child.kill();
// 或使用指定信号
await child.kill("SIGKILL");
// 等待进程退出
const status = await child.status;
console.log("退出信号:", status.signal);Common Patterns
常见模式
Running User Code Safely
安全运行用户代码
typescript
import { Sandbox } from "@deno/sandbox";
async function runUserCode(code: string): Promise<string> {
await using sandbox = await Sandbox.create();
// Write user code to a file in the sandbox
await sandbox.writeFile("/tmp/user_code.ts", code);
// Run with restricted permissions
const child = await sandbox.spawn("deno", {
args: [
"run",
"--allow-none", // No permissions
"/tmp/user_code.ts"
],
stdout: "piped",
stderr: "piped",
});
const output = await child.output();
if (output.code !== 0) {
throw new Error(new TextDecoder().decode(output.stderr));
}
return new TextDecoder().decode(output.stdout);
}typescript
import { Sandbox } from "@deno/sandbox";
async function runUserCode(code: string): Promise<string> {
await using sandbox = await Sandbox.create();
// 将用户代码写入沙箱内的文件
await sandbox.writeFile("/tmp/user_code.ts", code);
// 以受限权限运行
const child = await sandbox.spawn("deno", {
args: [
"run",
"--allow-none", // 无任何权限
"/tmp/user_code.ts"
],
stdout: "piped",
stderr: "piped",
});
const output = await child.output();
if (output.code !== 0) {
throw new Error(new TextDecoder().decode(output.stderr));
}
return new TextDecoder().decode(output.stdout);
}Code Playground
代码游乐场
typescript
import { Sandbox } from "@deno/sandbox";
interface ExecutionResult {
success: boolean;
output: string;
error?: string;
executionTime: number;
}
async function executePlayground(code: string): Promise<ExecutionResult> {
const start = performance.now();
await using sandbox = await Sandbox.create();
await sandbox.writeFile("/playground/main.ts", code);
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-net", "/playground/main.ts"],
stdout: "piped",
stderr: "piped",
});
const output = await child.output();
const executionTime = performance.now() - start;
return {
success: output.code === 0,
output: new TextDecoder().decode(output.stdout),
error: output.code !== 0
? new TextDecoder().decode(output.stderr)
: undefined,
executionTime,
};
}typescript
import { Sandbox } from "@deno/sandbox";
interface ExecutionResult {
success: boolean;
output: string;
error?: string;
executionTime: number;
}
async function executePlayground(code: string): Promise<ExecutionResult> {
const start = performance.now();
await using sandbox = await Sandbox.create();
await sandbox.writeFile("/playground/main.ts", code);
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-net", "/playground/main.ts"],
stdout: "piped",
stderr: "piped",
});
const output = await child.output();
const executionTime = performance.now() - start;
return {
success: output.code === 0,
output: new TextDecoder().decode(output.stdout),
error: output.code !== 0
? new TextDecoder().decode(output.stderr)
: undefined,
executionTime,
};
}AI Agent Tool Execution
AI Agent工具执行
typescript
import { Sandbox } from "@deno/sandbox";
async function executeAgentTool(
toolCode: string,
input: unknown
): Promise<unknown> {
await using sandbox = await Sandbox.create();
// Create a wrapper that handles input/output
const wrapper = `
const input = ${JSON.stringify(input)};
const tool = await import("/tool.ts");
const result = await tool.default(input);
console.log(JSON.stringify(result));
`;
await sandbox.writeFile("/tool.ts", toolCode);
await sandbox.writeFile("/run.ts", wrapper);
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-net", "/run.ts"],
stdout: "piped",
stderr: "piped",
});
const output = await child.output();
if (output.code !== 0) {
throw new Error(new TextDecoder().decode(output.stderr));
}
return JSON.parse(new TextDecoder().decode(output.stdout));
}typescript
import { Sandbox } from "@deno/sandbox";
async function executeAgentTool(
toolCode: string,
input: unknown
): Promise<unknown> {
await using sandbox = await Sandbox.create();
// 创建处理输入输出的包装器
const wrapper = `
const input = ${JSON.stringify(input)};
const tool = await import("/tool.ts");
const result = await tool.default(input);
console.log(JSON.stringify(result));
`;
await sandbox.writeFile("/tool.ts", toolCode);
await sandbox.writeFile("/run.ts", wrapper);
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-net", "/run.ts"],
stdout: "piped",
stderr: "piped",
});
const output = await child.output();
if (output.code !== 0) {
throw new Error(new TextDecoder().decode(output.stderr));
}
return JSON.parse(new TextDecoder().decode(output.stdout));
}Sandbox Features
沙箱特性
Resource Configuration
资源配置
Sandboxes have configurable resources:
- Default: 2 vCPUs, 512MB memory, 10GB disk
- Startup time: Under 200ms
沙箱的资源可配置:
- 默认配置:2个vCPU、512MB内存、10GB磁盘
- 启动时间:低于200毫秒
What's Included
内置组件
Each sandbox comes with:
- TypeScript/JavaScript runtime (Deno)
- Full Linux environment
- Network access (can be restricted)
- Temporary filesystem
每个沙箱包含:
- TypeScript/JavaScript运行时(Deno)
- 完整Linux环境
- 网络访问权限(可限制)
- 临时文件系统
Security Features
安全特性
- Firecracker microVMs - Same technology as AWS Lambda
- Full isolation - Separate kernel, filesystem, network
- No data leakage - Sandboxes can't access host system
- Enforced policies - Control outbound connections
- Firecracker微虚拟机 - 与AWS Lambda采用相同技术
- 完全隔离 - 独立内核、文件系统、网络
- 无数据泄露 - 沙箱无法访问宿主系统
- 强制策略 - 控制出站连接
Deploying Sandboxes
部署沙箱
Sandboxes can be deployed directly to Deno Deploy:
bash
deno deploy --prodThe sandbox SDK works seamlessly in the Deno Deploy environment.
沙箱可直接部署到Deno Deploy:
bash
deno deploy --prod沙箱SDK可在Deno Deploy环境中无缝运行。
API Reference
API参考
For the complete API, run:
bash
deno doc jsr:@deno/sandboxKey classes:
- - Main class for creating/managing sandboxes
Sandbox - - Represents a running process
ChildProcess - - For managing Deploy resources (apps, volumes)
Client
要查看完整API文档,运行:
bash
deno doc jsr:@deno/sandbox核心类:
- - 创建和管理沙箱的主类
Sandbox - - 代表运行中的进程
ChildProcess - - 用于管理Deploy资源(应用、卷)
Client
Quick Reference
快速参考
| Task | Code |
|---|---|
| Create sandbox | |
| Run command | |
| Get output | |
| Write file | |
| Read file | |
| Kill process | |
| Check status | |
| 任务 | 代码 |
|---|---|
| 创建沙箱 | |
| 运行命令 | |
| 获取输出 | |
| 写入文件 | |
| 读取文件 | |
| 终止进程 | |
| 检查状态 | |
Common Mistakes
常见错误
Forgetting automatic disposal
typescript
// ❌ Wrong - always use "await using" for sandbox creation
// Never write: const sandbox = await Sandbox.create() without "await using"
// ✅ Correct - use "await using" for automatic cleanup
await using sandbox = await Sandbox.create();
await sandbox.spawn("echo", { args: ["hello"] });
// sandbox automatically disposed when scope endsGiving user code too many permissions
typescript
// ❌ Wrong - gives untrusted code full access
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-all", "/tmp/user_code.ts"],
});
// ✅ Correct - restrict permissions to what's needed
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-none", "/tmp/user_code.ts"], // No permissions
});
// Or if network is truly needed:
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-net", "/tmp/user_code.ts"], // Only network
});Not handling process output properly
typescript
// ❌ Wrong - forgetting to pipe stdout/stderr
const child = await sandbox.spawn("deno", { args: ["run", "script.ts"] });
const output = await child.output();
// output.stdout is empty because we didn't pipe it!
// ✅ Correct - pipe the streams you need
const child = await sandbox.spawn("deno", {
args: ["run", "script.ts"],
stdout: "piped",
stderr: "piped",
});
const output = await child.output();
console.log(new TextDecoder().decode(output.stdout));Not setting timeouts for user code execution
typescript
// ❌ Wrong - user code could run forever
const child = await sandbox.spawn("deno", {
args: ["run", "/tmp/user_code.ts"],
});
await child.output(); // Could hang indefinitely
// ✅ Correct - implement timeout handling
const child = await sandbox.spawn("deno", {
args: ["run", "/tmp/user_code.ts"],
stdout: "piped",
stderr: "piped",
});
// Set a timeout to kill the process
const timeoutId = setTimeout(() => child.kill(), 5000); // 5 second limit
try {
const output = await child.output();
return output;
} finally {
clearTimeout(timeoutId);
}Trusting sandbox output without validation
typescript
// ❌ Wrong - directly using untrusted output as code
const result = await runUserCode(code);
// Never execute or inject untrusted output!
// ✅ Correct - validate and sanitize output
const result = await runUserCode(code);
try {
const parsed = JSON.parse(result); // Parse as data, not code
if (isValidResponse(parsed)) {
return parsed;
}
} catch {
throw new Error("Invalid response from sandbox");
}忘记自动销毁
typescript
// ❌ 错误 - 创建沙箱时务必使用"await using"
// 绝对不要编写:const sandbox = await Sandbox.create() 而不使用"await using"
// ✅ 正确 - 使用"await using"实现自动清理
await using sandbox = await Sandbox.create();
await sandbox.spawn("echo", { args: ["hello"] });
// 沙箱会在作用域结束时自动销毁赋予用户代码过多权限
typescript
// ❌ 错误 - 赋予不可信代码完全访问权限
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-all", "/tmp/user_code.ts"],
});
// ✅ 正确 - 仅授予必要权限
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-none", "/tmp/user_code.ts"], // 无任何权限
});
// 若确实需要网络权限:
const child = await sandbox.spawn("deno", {
args: ["run", "--allow-net", "/tmp/user_code.ts"], // 仅网络权限
});未正确处理进程输出
typescript
// ❌ 错误 - 忘记管道化标准输出/标准错误
const child = await sandbox.spawn("deno", { args: ["run", "script.ts"] });
const output = await child.output();
// output.stdout为空,因为我们没有管道化它!
// ✅ 正确 - 管道化需要的流
const child = await sandbox.spawn("deno", {
args: ["run", "script.ts"],
stdout: "piped",
stderr: "piped",
});
const output = await child.output();
console.log(new TextDecoder().decode(output.stdout));未为用户代码执行设置超时
typescript
// ❌ 错误 - 用户代码可能无限运行
const child = await sandbox.spawn("deno", {
args: ["run", "/tmp/user_code.ts"],
});
await child.output(); // 可能无限挂起
// ✅ 正确 - 实现超时处理
const child = await sandbox.spawn("deno", {
args: ["run", "/tmp/user_code.ts"],
stdout: "piped",
stderr: "piped",
});
// 设置超时以终止进程
const timeoutId = setTimeout(() => child.kill(), 5000); // 5秒限制
try {
const output = await child.output();
return output;
} finally {
clearTimeout(timeoutId);
}未验证就信任沙箱输出
typescript
// ❌ 错误 - 直接将不可信输出作为代码使用
const result = await runUserCode(code);
// 绝对不要执行或注入不可信输出!
// ✅ 正确 - 验证并清理输出
const result = await runUserCode(code);
try {
const parsed = JSON.parse(result); // 解析为数据而非代码
if (isValidResponse(parsed)) {
return parsed;
}
} catch {
throw new Error("沙箱返回无效响应");
}