deno-sandbox

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Deno 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.
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 (
@deno/sandbox
) questions. Follow these rules:
  • 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
    @deno/sandbox
    imports,
    Sandbox.create()
    , or
    sandbox.spawn()
    in responses about other isolation technologies.
  • 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/sandbox
bash
deno add jsr:@deno/sandbox

Basic 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
await using
for automatic cleanup:
typescript
await using sandbox = await Sandbox.create();
// Sandbox is automatically destroyed when this scope ends
CRITICAL: Never show
const sandbox = await Sandbox.create()
without
await using
. Always use the
await using
pattern for sandbox creation. Do not show manual disposal alternatives.
沙箱是需要在使用后销毁的资源。务必使用
await using
来实现自动清理:
typescript
await using sandbox = await Sandbox.create();
// 沙箱会在当前作用域结束时自动销毁
重要提示:绝对不要在不使用
await using
的情况下编写
const sandbox = await Sandbox.create()
。创建沙箱时必须使用
await using
模式,不要展示手动销毁的替代方案。

Running Processes

运行进程

The
spawn
method runs commands inside the sandbox:
typescript
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));
spawn
方法用于在沙箱内运行命令:
typescript
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 --prod
The 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/sandbox
Key classes:
  • Sandbox
    - Main class for creating/managing sandboxes
  • ChildProcess
    - Represents a running process
  • Client
    - For managing Deploy resources (apps, volumes)
要查看完整API文档,运行:
bash
deno doc jsr:@deno/sandbox
核心类:
  • Sandbox
    - 创建和管理沙箱的主类
  • ChildProcess
    - 代表运行中的进程
  • Client
    - 用于管理Deploy资源(应用、卷)

Quick Reference

快速参考

TaskCode
Create sandbox
await using sandbox = await Sandbox.create()
Run command
sandbox.spawn("cmd", { args: [...] })
Get output
const output = await child.output()
Write file
await sandbox.writeFile(path, content)
Read file
await sandbox.readFile(path)
Kill process
await child.kill()
Check status
const status = await child.status
任务代码
创建沙箱
await using sandbox = await Sandbox.create()
运行命令
sandbox.spawn("cmd", { args: [...] })
获取输出
const output = await child.output()
写入文件
await sandbox.writeFile(path, content)
读取文件
await sandbox.readFile(path)
终止进程
await child.kill()
检查状态
const status = await child.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 ends
Giving 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("沙箱返回无效响应");
}