mcpField
D
deno-sandbox

deno-sandbox

github.com/midudev開発7.0k58 回インストール1 週間前に更新
リポジトリ

deno-sandbox について

deno-sandbox は、Deno でコード実行機能を作る開発者向けに `@deno/sandbox` の使い方をまとめたスキルです。分離された Linux マイクロ VM での未信頼コードの実行や、リソースのライフサイクル、プロセス管理を扱います。

主な機能

  1. 01分離された Linux マイクロ VM での実行
  2. 02コマンド実行とプロセス管理
  3. 03プロセス入出力のストリーミング
  4. 04サンドボックス内のファイル操作
  5. 05権限とタイムアウトの設定ガイド

活用シーン

  1. 01ユーザー投稿コードの実行
  2. 02AI 生成コードの実行
  3. 03コードプレイグラウンドの構築
  4. 04自動テストの分離実行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/midudev/autoskills --skill deno-sandbox

インストール後、Claude Code で/deno-sandboxを入力して読み込まれたか確認します。

詳細

Deno サンドボックス

概要

Deno サンドボックスは、信頼できないコードを実行するための安全で隔離された環境を提供します。各サンドボックスは、独自の Linux マイクロ VM 内(AWS Lambda と同じ技術である Firecracker を使用)で実行され、ファイルシステム、ネットワーク、プロセス空間が個別に分離されています。そのため、コードプレイグラウンド、AI エージェントによるツール実行、マルチテナントアプリケーションに最適です。

リファレンス:https://deno.com/deploy/sandboxes

サンドボックスを使用する場面

次のような場合は、Deno サンドボックスを使用してください。

  • ユーザーが送信したコードを安全に実行する
  • AI が生成したコードを実行する
  • コードプレイグラウンドのプラットフォームを構築する
  • マルチテナントのコード実行環境を作成する
  • 自動テストを隔離された環境で実行する

適用範囲

このスキルは、Deno Sandbox(@deno/sandbox)に関する質問のみを対象とします。次のルールに従ってください。

  • ユーザーがDocker コンテナ、Node.js vm2/vm、Web Workers、AWS Lambda の分離、またはその他の分離技術について質問した場合は、その技術を直接使用して回答してください。代替案として Deno サンドボックスを提案しないでください。
  • 他の分離技術に関する回答には、@deno/sandbox のインポート、Sandbox.create()、または sandbox.spawn() を含めないでください。
  • Deno サンドボックスを推奨するのは、ユーザーが明示的に尋ねた場合、または Deno プロジェクトでコード実行機能を構築している場合に限ります。

はじめに

インストール
deno add jsr:@deno/sandbox
基本的な使い方
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!

基本概念

サンドボックスのライフサイクル

サンドボックスは、使用後に破棄する必要があるリソースです。自動クリーンアップのため、必ず await using を使用してください。

await using sandbox = await Sandbox.create();
// Sandbox is automatically destroyed when this scope ends

重大な注意:await using を使わずに const sandbox = await Sandbox.create() を示してはいけません。サンドボックスの作成には、必ず await using パターンを使用してください。手動で破棄する代替方法は示さないでください。

プロセスの実行

spawn メソッドは、サンドボックス内でコマンドを実行します。

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));
ストリーミング I/O

対話型プロセスや長時間実行されるコマンドの場合:

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));
}
プロセスの終了
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);

よくあるパターン

ユーザーコードを安全に実行する
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.fs.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);
}
コードプレイグラウンド
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.fs.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 エージェントによるツール実行
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.fs.writeFile("/tool.ts", toolCode);
  await sandbox.fs.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));
}

サンドボックスの機能

リソースの設定

サンドボックスのリソースは設定可能です。

  • デフォルト: 2 vCPU、512MB メモリ、10GB ディスク
  • 起動時間:200ms 未満
含まれるもの

各サンドボックスには、次のものが含まれています。

  • TypeScript/JavaScript ランタイム(Deno)
  • 完全な Linux 環境
  • ネットワークアクセス(制限可能)
  • 一時ファイルシステム
セキュリティ機能
  • Firecracker マイクロ VM - AWS Lambda と同じ技術
  • 完全な分離 - カーネル、ファイルシステム、ネットワークを個別に分離
  • データ漏えいなし - サンドボックスからホストシステムにはアクセスできません
  • ポリシーの適用 - 外部への接続を制御

サンドボックスのデプロイ

サンドボックスは Deno Deploy に直接デプロイできます。

deno deploy --prod

サンドボックス SDK は Deno Deploy 環境でシームレスに動作します。

API リファレンス

完全な API を確認するには、次を実行してください。

deno doc jsr:@deno/sandbox

主なクラス:

  • Sandbox - サンドボックスの作成・管理を行うメインクラス
  • ChildProcess - 実行中のプロセスを表します
  • Client - Deploy リソース(アプリ、ボリューム)を管理します

クイックリファレンス

タスクコード
サンドボックスを作成await using sandbox = await Sandbox.create()
コマンドを実行sandbox.spawn("cmd", { args: [...] })
出力を取得const output = await child.output()
ファイルを書き込むawait sandbox.fs.writeFile(path, content)
ファイルを読み込むawait sandbox.fs.readFile(path)
プロセスを終了するawait child.kill()
状態を確認するconst status = await child.status

よくある間違い

自動破棄を忘れる

// ❌ 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

ユーザーコードに過剰な権限を与える

// ❌ 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
});

プロセスの出力を適切に処理しない

// ❌ 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));

ユーザーコードの実行にタイムアウトを設定しない

// ❌ 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);
}

検証せずにサンドボックスの出力を信頼する

// ❌ 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");
}

コメント