DeepSeek Harness: サンドボックスと承認

最終更新:2026-08-31

Agent の力は操作を実行できることにありますが、「実行できる」≠「実行すべき」です。承認ポリシーは Agent のブレーキ、サンドボックスは Agent のフェンスです。この2つがあれば、Agent は安全な境界内で自由に行動できます。

💡 ヒント:承認ポリシーは「いつユーザーに聞くか」、サンドボックスは「どこで実行するか」を決めます。承認は決定権を、サンドボックスは実行環境の境界を決定。独立していますが補完関係にあります。

📋 前提知識13-effect.md22-capability.md の完了

1. 学習内容

ツール実行と権限パイプライン


2. 承認ポリシー

(1) ポリシーモード

DSH は4つの承認モードを提供:

モード 動作 最適な用途
always 常に許可、ポップアップなし 安全な操作(読取、検索)
ask 承認が必要、ポップアップ確認 危険な操作(作成、編集、shell)
ask_with_confirm 二重確認ポップアップ 極めて危険な操作(削除、sudo)
deny 自動拒否 絶対に実行してはいけない操作(rm -rf /)

▶ サンプル 2:

YAML
# 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:

YAML
approval:
  tools:
    file_edit:
      # パスホワイトリスト自動許可
      auto_allow_paths:
        - /tmp/**
        - /workspace/**
      # パスブラックリスト自動拒否
      auto_deny_paths:
        - /etc/**
        - /var/**

    shell:
      # コマンドホワイトリスト
      auto_allow_commands:
        - ls
        - cat
        - grep
        - head
        - wc
        - git status
        - git log
      # コマンドブラックリスト
      auto_deny_commands:
        - rm -rf /*
        - mkfs
        - dd if=*

▶ サンプル 4:

TYPESCRIPT
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. パーミッションプリセット

(1) 組み込みプリセット

DSH は3つのパーミッションプリセットを提供:

プリセット 説明 典型的な用途
trusted 信頼モード、ほとんどの操作を自動許可 個人開発環境
standard 標準モード、危険操作は承認が必要 デフォルト設定
restricted 制限モード、厳格な承認 本番環境

(2) プリセットの比較

YAML
# trusted — 信頼モード
approval:
  tools:
    file_edit:always
    shell:always
    search:always

# standard — 標準モード
approval:
  tools:
    file_edit:
      read:always
      create:ask
      edit:ask
      delete:ask_with_confirm
    shell:ask

# restricted — 制限モード
approval:
  tools:
    file_edit:ask_with_confirm
    shell:deny
    search:ask

(3) プリセットの選択

BASH
# 起動時にプリセットを選択
pnpm dsh web --preset trusted
pnpm dsh web --preset standard
pnpm dsh web --preset restricted

(4) カスタムプリセット

YAML
# dsh.config.yaml
approval:
  presets:
    my-team:
      tools:
        file_edit:
          read:always
          create:ask
          edit:ask
          delete:deny
        shell:ask

4. 危険操作の承認ポップアップ

(1) ポップアップ機構

ツール呼び出しが承認を必要とする場合、DSH は実行を一時停止し承認ポップアップを表示:

TEXT 📖 参照専用
⚠️ Approval Required:Execute shell command

  Command:npm install bcryptjs
  Working directory:/home/alice/project
  Risk level:MODERATE
  
  [Allow] [Always for npm] [Deny]

(2) 承認オプション

オプション 説明
Allow この操作を許可
Always このタイプの操作を常に許可(以降ポップアップなし)
Always for X 特定ルールにマッチする操作を常に許可
Deny この操作を拒否

(3) バッチ承認

複数操作を一括承認可能:

TEXT 📖 参照専用
⚠️ 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) 承認ログ

すべての承認決定が記録されます:

TEXT 📖 参照専用
[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. サンドボックスバックエンド登録

(1) サンドボックスの概念

サンドボックスはツール実行の隔離環境——Agent の操作はサンドボックス内で実行され、ホストシステムに影響しません:

100%
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) サンドボックスバックエンドインターフェース

TYPESCRIPT
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) サンドボックスバックエンドの登録

TYPESCRIPT
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) サンドボックスの設定

YAML
# dsh.config.yaml
sandbox:
  backend:docker
  config:
    image:dsh-sandbox:latest
    workdir:/workspace
    memory:512m
    cpus:1
    timeout:30000
    network:none

6. ctx.sandbox と ctx.shell

(1) ctx.sandbox

ctx.sandbox はサンドボックス化されたファイル操作を提供:

TYPESCRIPT
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 はサンドボックス内でコマンドを実行:

TYPESCRIPT
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 と直接 fs の比較

操作 直接 fs ctx.sandbox
ファイルパス ホストシステムのパス サンドボックス内部のパス
パーミッション ホストユーザー権限 サンドボックスユーザー権限
隔離 なし 完全隔離
パフォーマンス 高速 やや低速(サンドボックス層経由)

(4) 安全な使用原則

TYPESCRIPT
// ❌ ホストファイルシステムに直接アクセス
import { readFileSync } from 'fs'
const content = readFileSync('/etc/passwd')

// ✅ サンドボックス経由
const content = await ctx.sandbox.readFile('/etc/passwd')
// → サンドボックスにファイルシステム隔離があれば、この呼び出しは制限される

7. リモートサンドボックス設定

(1) リモートサンドボックスアーキテクチャ

100%
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) リモートサンドボックスの設定

YAML
# 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) リモートサンドボックスバックエンドの実装

TYPESCRIPT
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) サンドボックスのライフサイクル

TEXT 📖 参照専用
1. Agent セッション作成 → サンドボックスコンテナをリクエスト
2. Sandbox API がコンテナ作成 → コンテナ ID を返却
3. Agent の操作がコンテナ内で実行
4. Agent セッション破棄 → コンテナ破棄をリクエスト
5. Sandbox API がコンテナ破棄 → リソース解放

❓ よくある質問

Q 承認ポップアップは Agent をブロックしますか?
A はい。Agent はユーザーの承認を待ってから継続します。これは意図的——ユーザーの知らないうちに Agent が危険な操作を実行するのを防ぐため。
Q 承認ポップアップをスキップできますか?
A --preset trusted を使用するとほとんどの操作が自動許可されます。ただし本番環境では推奨されません。
Q サンドボックスと Docker の関係は?
A Docker は1つのサンドボックス実装です。DSH のサンドボックスバックエンドインターフェースは汎用的で、Docker、gVisor、リモートサーバーなど任意の実装を使用可能。
Q サンドボックス未設定の場合はどうなりますか?
A ツールはホストシステム上で直接実行されます。これは「サンドボックスなし」モード——Agent はホストの完全な権限を持ちます。
Q リモートサンドボックスのレイテンシは大きい?
A ネットワークとサンドボックス実装に依存。通常ファイル操作 10-50ms、コマンド実行 100-500ms(起動オーバーヘッド含む)。
Q 承認決定を監査するには?
A 承認ログを確認。各決定のタイムスタンプ、操作、ポリシー、ユーザーの選択が記録されています。

📖 まとめ


📝 練習問題

1. ⭐ 基礎:DSH を standard プリセットで設定し、Agent に ls(自動許可)と rm(承認必要)を実行させ、承認ポップアップの動作を観察。

2. ⭐⭐ 応用:カスタムツールに承認ルールを追加——SELECT クエリは自動許可、INSERT/UPDATE/DELETE は承認必要、DROP は自動拒否。各 SQL タイプの承認動作をテスト。

3. ⭐⭐⭐ チャレンジ:シンプルなサンドボックスバックエンド(サブプロセス隔離を使用)を実装し、DSH に登録してください。Agent にサンドボックス内でコマンドを実行させ、以下を確認:1) ファイル操作がサンドボックスディレクトリに制限される;2) ネットワークリクエストがブロックされる;3) サンドボックス破棄後のファイルクリーンアップ。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%