
AIコーディングエージェント用のサンドボックス。Copilot CLI、Claude Code、OpenCode、Gemini CLI、Antigravity、Pi、goose、またはプレーンシェルをカーネルレベルのサンドボックス内で実行し、gitおよびghガードとサンドボックスポリシーをリポジトリにコミットします。
AIコーディングエージェント向けのカーネル強制サンドボックス。 cpltはGitHub Copilot CLI、OpenCode、Gemini CLI、Antigravity CLI、Pi、Claude Code、goose、DeepSeek Harness、または任意のシェルをラップし、エージェントがコードを書けるようにしつつ、認証情報の窃取、mainへのプッシュ、PRのマージ、シークレットの持ち出しを防ぎます。
sandbox-exec 経由のApple Seatbelt/SBPL
AIエージェントは任意のコードを実行します。プロンプトインジェクション、サプライチェーン攻撃、悪意のあるMCPサーバーなどによって侵害されたエージェントは、OS自体が拒否しない限り、~/.sshの読み取り、mainへのプッシュ、PRのマージ、コードの持ち出しが可能です。
cpltはチームで設定可能なポリシーによるカーネルレベルの強制を提供します:
.cplt.toml内のリポジトリごとのポリシーをバージョン管理にコミットするため、改ざん防止と監査が可能詳細ドキュメント: 設定 · プロキシとドメインフィルタリング · ghコマンドガード · gitコマンドガード · 既知の影響 · セキュリティ詳細 · セキュリティモデル
brew install navikt/tap/cplt # macOS. On Debian or Ubuntu, see apt below cplt --shell-install # make 'copilot' run sandboxed (persistent) # --agent opencode for any other agent cplt doctor # check your environment cplt -- -p "fix the tests" # run Copilot in sandbox
その他のエージェントとサンドボックスコマンド:```bash
cplt --agent opencode # OpenCode (Copilot subscription)
cplt --agent opencode --pass-env ANTHROPIC_API_KEY # third-party provider
cplt --agent shell # interactive sandboxed shell (no AI)
cplt exec -- npm install # sandbox any command directly
cplt exec -c "npm install && npm test" # compound commands in sandbox
alias npm="cplt exec -- npm" # sandboxed npm for every invocation
cplt init --write
cplt trust accept --all
cplt config set git_guard.protect_default_branch_only false # block every push, not just main cplt config set git_guard.mode warn # observe instead of blocking
## ブロックするもの
サンドボックスはカーネル内の認証情報とシークレットへのアクセスをブロックします。コマンドガードは破壊的な操作をブロックします。すべての制限はエージェントと、それが生成するすべてのプロセスに適用されます。
| リソース | ステータス | 備考 |
| --- | --- | --- |
| プロジェクトディレクトリの読み書き | ✅ 許可 | |
| プロジェクト内の `.env*`、`.pem`、`.key` の読み書き/削除 | 🔒 カーネルでブロック | シークレットの持ち出しと破壊を防ぎます。`--allow-env-files` で上書き可能 |
| `.git/hooks`、`.git/config`、`.gitmodules` の書き込み | 🔒 カーネルでブロック (macOS)、⚠️ Linux では部分的 | git フック、hooksPath リダイレクト、サブモジュールハイジャックによる永続化を防ぎます。**Linux:** Landlock は許可されたツリー内のサブパスを拒否できないため、Landlock のみのパスではこれらは書き込み可能なままです。`bwrap` は `.git/hooks` を読み取り専用に再バインドしますが、`.git/config` と `.gitmodules` は意図的に書き込み可能なままにするため、`core.hooksPath` は永続化の経路として残ります。[Linux の制限](https://github.com/navikt/cplt/blob/main/docs/security.md#linux)を参照。**すべての**書き込み可能ルート、つまりプロジェクトと各 `allow.write` 許可に適用され、実際のフックが `<root>/.git` の外にある許可されたワークツリーやベアリポジトリも含みます |
| `/tmp`、`/var/folders` からの実行 | 🔒 カーネルでブロック | 書き込み後の実行を防ぎます。スクラッチディレクトリは TMPDIR を安全な場所にリダイレクトし、デフォルトで有効です |
| PATH で解決される bin/shim ディレクトリ (`~/.bun/bin`、`~/.deno/bin`、`$PNPM_HOME`、mise の `shims/` と `installs/` 全体) への書き込み | 🔒 カーネルでブロック (macOS)、⚠️ Linux では mise が部分的 | 次に *サンドボックス外* で実行されるコマンドが PATH 経由で解決するバイナリをトロイの木馬化するのを防ぎます。`~/.cargo/bin` と `~/go/bin` が常に読み取り専用であったのと同じ理由です。cplt 内での `bun install -g`、`deno install`、`pnpm add -g`、`mise install`、`mise upgrade`、`mise use -g` を意図的に壊し、未インストールのツールチェーンを固定したリポジトリはブートストラップしなくなります。プロジェクトローカルのインストールは影響を受けません。**Linux:** mise の 2 つは `bwrap` の読み取り専用オーバーレイに乗り、残りはネイティブに保持されます。[グローバルツールのインストール](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#global-tool-installs)を参照 |
| `~/Library/Caches` からの実行 | 🔒 デフォルトでカーネルブロック | バイナリドロップのステージングを防ぎます。Copilot のネイティブモジュールはカーブアウトにより除外されます。`--allow-cache-exec <SUBDIR>` で対象を絞った除外を追加できます (例: `ms-playwright`) |
| `.vscode/tasks.json`、`launch.json` の変更 | ⚠️ 許可、既知のリスク | IDE の信頼境界。緩和策については [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md) を参照 |
| `~/.copilot` (認証、設定) の読み書き | ✅ 許可 | `keytar.node`、`pty.node`、`computer.node` 用の `file-map-executable` を含みます |
| `~/.copilot/pkg` (ネイティブモジュール) への書き込み | 🔒 カーネルでブロック | ネイティブモジュールの置き換えによる永続化を防ぎます |
| 環境変数 | 🔒 サニタイズ + 強化 | 安全な許可リストのみが通過します。ライフサイクルスクリプトはブロックされます。`--pass-env VAR` で 1 つ戻せます |
| `~/.config/gh/hosts.yml` + `config.yml` の読み取り | ✅ 許可 (読み取り専用) | この 2 ファイルのみ。`.config/gh` の残りはブロックされます |
| `~/.config/mise` の読み取り | ✅ 許可 (読み取り専用) | ツールのバージョンと PATH、シークレットなし |
| `~/.gitconfig`、`~/.config/git/config` の読み取り | ✅ 許可 (読み取り専用) | dotfiles のシンボリックリンクはターゲットまで追跡されるため、stow された `~/.gitconfig` も機能します |
| `~/.git-credentials` の読み取り | 🔒 カーネルでブロック | `credential.helper = store` はここに平文トークンを保持します。`~/.netrc` と同様、`--allow-read` でも再び開けません。**Linux:** *祖先* (`$HOME` 自体) への許可は依然としてこれを露出させます。Landlock は許可されたツリー内のサブパスを拒否できないためです |
| グローバル git フック (`core.hooksPath`) の読み取り | ✅ 許可 (読み取り専用、書き込み拒否) | 自動検出されます。`$HOME` 配下で深さ ≥3 である必要があります。書き込みは明示的にブロックされます |
| コミット/タグ署名 (`commit.gpgsign`、`tag.gpgsign`) | 🔒 無効化 | `~/.ssh` と `~/.gnupg` の秘密鍵がブロックされるため、環境変数の上書きにより署名は無効化されます |
| `~/Library/Application Support/Microsoft` の読み取り | ✅ 許可 (読み取り専用) | テレメトリ用のデバイス ID |
| macOS Keychain へのアクセス | ⚠️ 認証をそこに保存するエージェントには許可 (読み書き) | 許可は 1 つの項目にスコープできないため、エージェントがロック解除できるすべてのキーチェーン項目に到達します。エージェントがそれなしで認証できる実行では、`sandbox.keychain_substitute` (実験的、デフォルト無効) をオプトインしてこれを外します — Claude Code の場合は `CLAUDE_CODE_OAUTH_TOKEN`、Antigravity の場合は既存のフォールバックトークンファイル。[SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md#keychain-access-is-all-or-nothing) を参照 |
| 外向きネットワーク (ポート 443) | ✅ 許可 | 他のすべてのポートはブロックされます。`--allow-port` で追加できます |
| ローカルホストへの外向き | 🔒 カーネルでブロック (macOS)、⚠️ Linux ではポートベース | ローカルサービスへのアクセスを防ぎます。インバウンドはプロキシ用に引き続き機能します。**Linux:** Landlock ルールはポート番号のみで、`localhost:443` と `remote:443` を区別できないため、許可されたポート上のローカルサービスに到達可能で、localhost 固有の拒否はありません。SSRF 保護には `--with-proxy` を使用してください。[Linux の制限](https://github.com/navikt/cplt/blob/main/docs/security.md#linux)を参照 |
| SSH エージェント (unix ソケット) | 🔒 カーネルでブロック (macOS)、⚠️ Linux では環境変数のみ | git 操作への署名やホストへの SSH を防ぎます。**Linux:** unix ソケットの `connect()` はゲートされないため、保留された `SSH_AUTH_SOCK` が唯一の障壁であり、自身で設定するエージェントはロードされた鍵を使用できます。`bwrap` は標準の OpenSSH ソケットを `/tmp` 配下に隠しますが、`$XDG_RUNTIME_DIR` 配下の gnome-keyring/gcr や systemd エージェントは隠しません。[Linux の制限](https://github.com/navikt/cplt/blob/main/docs/security.md#linux)を参照 |
| 開発者ツール (`~/.cargo`、`~/.gradle`、`~/.m2`、`~/.sdkman`、`~/.jenv`、`~/.pyenv`、`~/.konan` など) | ✅ 許可 (キャッシュは読み書き) | ディスク上に存在するディレクトリのみ。実行時に `cplt doctor` が検出した内容で絞り込まれます |
| レジストリ認証情報ファイル (`~/.m2/settings.xml`、`~/.gradle/gradle.properties`、`~/.cargo/credentials`) | 🔒 macOS ではカーネルでブロック。Linux では親ツールディレクトリが読み取り可能なまま | `--allow-read` で上書き。[プライベートレジストリ](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#private-registries)を参照 |
| `~/.npmrc` の読み取り | 🔒 カーネルでブロック (両プラットフォーム) | `--allow-read` で上書き。yarn 1 を壊します。[yarn 1](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#yarn-1-and-unreadable-home-rc-files) を参照 |
| Go ソースコード (`~/go/src`) | 🔒 カーネルでブロック | `~/go/bin` と `~/go/pkg` のみ読み取り可能 |
| `~/.ssh`、`~/.gnupg`、`~/.aws`、`~/.azure` の読み取り | 🔒 カーネルでブロック | |
| `~/.kube`、`~/.docker`、`~/.nais` の読み取り | 🔒 カーネルでブロック | |
| `~/.password-store`、`~/.terraform.d` の読み取り | 🔒 カーネルでブロック | |
| `~/.config/gcloud`、`~/.config/op` の読み取り | 🔒 カーネルでブロック | 個々のファイルは `--allow-read` で上書き可能。[クラウド認証情報](https://github.com/navikt/cplt/blob/main/docs/known-impacts.md#cloud-credential-directories)を参照 |
| `~/.config/cplt`、`~/.nav-pilot` の読み書き | 🔒 カーネルでブロック | *次回*の起動が何をできるかを決めるツール状態。`~/.config/cplt` はサブツリー全体として上書き不可。`~/.nav-pilot` 内では、固定された agentpakke ペイロードを読み取れるよう、名前付きパスは許可可能なままです |
| `~/.netrc`、`~/.pypirc`、`~/.vault-token` の読み取り | 🔒 カーネルでブロック | 両プラットフォームで上書き不可。`allow.read` で指定すると起動エラーになります |
| `~/.gem/credentials` の読み取り | 🔒 カーネルでブロック | 両プラットフォームで上書き不可。`allow.read` で指定すると起動エラーになります |
| `gh` CLI の破壊的操作 (merge、delete、release) | 🔒 コマンドでゲート (デフォルト有効) | `--no-gh-guard` でオプトアウト。[gh ガード](https://github.com/navikt/cplt/blob/main/docs/gh-guard.md)を参照 |
| デフォルトブランチへの `git push` | 🔒 コマンドでゲート (デフォルト有効) | `main`/`master` へのプッシュをブロックします。フィーチャーブランチへのプッシュは引き続き機能します。`protect_default_branch_only = false` はすべてのプッシュをブロックし、`git_guard.mode = "warn"` は警告のみ、`--no-git-guard` はオプトアウトします |
| 子プロセスの継承 | ✅ すべての制限がサブプロセスに適用されます | |
この表は要約です。サンドボックスはシステムファイル (SSL 証明書、`/etc/hosts`)、一時ディレクトリ (読み書き、実行なし)、システムツールパス (`/usr/bin`、`/opt/homebrew`) へのアクセスも許可します。完全な SBPL ルールを確認するには `cplt --print-profile` を実行してください。
完全なセキュリティモデル、脅威分析、テスト戦略については [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md) をお読みください。
## cplt の比較
### Codex CLI のサンドボックス
| 領域 | cplt | Codex CLI サンドボックス |
| --- | --- | --- |
| 外向きネットワーク制御 | ドメイン許可/ブロックリスト付き CONNECT プロキシ | ドメインレベルのフィルタリングなし |
| 環境変数の扱い | 許可リスト + 強化された環境変数注入 | より基本的なパススルーモデル |
| シークレットファイル保護 | リポジトリ内の `.env*`、`.pem`、`.key` などの拒否パターン | 主にディレクトリスコープのアクセス |
| リポジトリポリシー | 明示的な信頼/承認フロー付きの [`.cplt.toml`](https://github.com/navikt/cplt/blob/main/docs/configuration.md#per-repo-configuration-cplttoml) | リポジトリレベルのポリシーファイルなし |
| エージェントサポート | Copilot、OpenCode、Gemini CLI、Antigravity CLI、Pi、Claude Code、goose、DeepSeek Harness、またはシェル | Codex のみ |
cplt がすべての面で強いわけではありません。Codex CLI は現在 Linux 名前空間分離を備えており、読み取り専用や workspace-write といった明示的なサンドボックスモードをすでに公開しています。cplt にはまだそのモードマトリクスがありません。
### Docker ベースのサンドボックス
| 領域 | cplt | Docker ベースのサンドボックス |
| --- | --- | --- |
| 起動時間 | 通常の CLI 使用ではほぼ即時 | 通常はコンテナ起動が遅い |
| ネットワーク制御 | プロキシ経由のリクエスト単位の外向きフィルタリング | 通常はオール・オア・ナッシングのネットワークアクセス |
| ファイル制御 | パス単位およびパターン単位のルール | マウント単位の制御 |
| ホスト要件 | 単一バイナリ | Docker デーモンが必要 |
| 企業ノート PC への適合性 | Docker が利用できない、または制限されている環境で動作 | ローカルポリシーでブロックされることが多い |
Docker は一部の環境では依然としてより強力な分離を提供します。特に完全に分離されたファイルシステムとプロセス名前空間が必要な場合です。cplt はそれを、より軽量なセットアップと、すでに開発に使用しているマシンとのより緊密な統合と引き換えにします。
### VS Code エージェントモードの権限
VS Code エージェントモードなどのツールは、主に UI 権限に依存しています。cplt はその制限をカーネルで強制するため、エージェントはプロンプトや改変された指示でそれを回避することはできません。これは CLI エージェントと認証情報の露出にとって最も重要です:
- cplt は IDE の外でも動作します
- 環境変数はエージェントが起動する前にフィルタリングされます
- 機密ファイルはリポジトリ内に存在する場合でもブロックできます
- 同じ制限が子プロセスにも適用されます
### Claude Code のサンドボックス (Anthropic Sandbox Runtime)
[Anthropic Sandbox Runtime](https://github.com/anthropic-experimental/sandbox-runtime) (`srt`) は Claude Code が使用するサンドボックス層です。cplt と同じ高レベルのアプローチ、macOS Seatbelt とカーネルレベルの Linux 強制と HTTP プロキシですが、実装は異なります。
| 領域 | cplt | Anthropic srt |
| --- | --- | --- |
| 言語 / 配布 | 単一の Rust バイナリ | Node.js + npm パッケージ + 外部依存 |
| Linux バックエンド | Landlock LSM (依存なし、名前空間なし) | bubblewrap (ユーザー名前空間経由のコンテナ) |
| 環境変数フィルタリング | 厳格な許可リスト + サフィックス拒否 (`_TOKEN`、`_SECRET`) | 親環境全体を継承 (シークレットが通過) |
| 認証情報ディレクトリ保護 | 15 以上のディレクトリをデフォルトで拒否 | ユーザーが手動で設定する必要あり |
| DNS リバインディング保護 | ✅ DNS 後の IP をプライベートレンジと照合 | ❌ 未実装 |
| ネットワークプロキシ | HTTP CONNECT + ドメイン許可/ブロック | HTTP + SOCKS5 + 実験的 TLS MITM |
| SSH git | macOS ではカーネルでブロック (エージェントソケット拒否)。Linux では `SSH_AUTH_SOCK` のみ保留 | SOCKS5 経由でプロキシ |
| パッケージマネージャスクリプト | デフォルトでブロック (`npm_config_ignore_scripts`) | ブロックなし |
| エージェントサポート | Copilot、OpenCode、Gemini、Antigravity、Pi、Claude Code、goose、DSH、Shell | Claude Code |
| 設定 | TOML (グローバル + リポジトリ単位) | JSON (グローバルのみ) + `--control-fd` ライブ更新 |
| ライブラリ API | ❌ バイナリのみ | ✅ 埋め込み可能な TypeScript ライブラリ |
cplt はすぐに使える状態でより安全です: 環境変数フィルタリング、認証情報保護、DNS リバインディングチェック、ライフサイクルスクリプトのブロック。srt はより柔軟です: SOCKS5、TLS 検査、リクエスト単位のコールバック、ライブラリの埋め込み。Linux バックエンドの選択が重要です。bwrap は AppArmor の userns 制限のため Ubuntu 24.04+ で回避策が必要ですが、Landlock はカーネル 5.13 以降が必要なものの外部依存がゼロです。
### GitHub Copilot CLI 自身のサンドボックス
Copilot CLI は 2026 年 6 月からローカルサンドボックスを同梱しており、
標準シートに含まれています。Microsoft MXC を通じてシェルコマンドを実行し、
macOS、Linux、Windows でファイルシステム、ネットワーク、システムアクセスを制限します。
`/sandbox enable` で有効になります。
それがあなたの要件を満たすなら、それを使ってください。追加費用はかからず、cplt が対応していない Windows でも動作します。
それが行わないことが 2 つあります。
ポリシーはリポジトリではなく管理者と共にあります。企業は Intune や他の MDM を通じて
サンドボックスポリシーを設定します。コードの隣には何も存在しないため、
あるリポジトリにとって重要なルールは、コントリビューター、CI、または MDM が管理しない
ノート PC にまで追随できません。cplt ではポリシーはリポジトリ内の
`.cplt.toml` です。レビュアーはプルリクエストでその変更を確認でき、このファイルは
開発者自身の設定を厳しくすることはできますが、緩めることは決してできません。
それはプロセスを閉じ込めますが、プロセスが保持する認証情報で何をするかは閉じ込めません。
`/sandbox` タブはファイルシステム、ネットワーク、システム機能をカバーしており、
Git リポジトリ内ではエージェントにデフォルトで `.git` の読み書きが許可されます。
サンドボックス化されたエージェントは依然としてあなたの `gh` トークンとプッシュアクセスを持っています。
ブランチのプッシュ、プルリクエストのマージ、リポジトリの削除はすべて、認可されたクライアントからの
整形式の API 呼び出しであり、ファイルシステムやネットワークのルールはそれらについて何の意見も持ちません。
cplt は代わりに `git` と `gh` をラップします。エージェントは自由にコミット、ブランチ、リベースできます。
`gh pr merge`、`gh repo delete`、`gh release create` はデフォルトでブロックされます。
`main`/`master` への `git push` も同様です。フィーチャーブランチへのプッシュは引き続き機能します。
`protect_default_branch_only` が有効だからです。すべてのプッシュをブロックするには `false` に、
警告のみにするには `git_guard.mode = "warn"` に設定してください。
両方を実行するのは合理的です。MXC はプロセスを閉じ込めます。ガードはエージェントが
保持する認証情報で何をしてよいかを決定します。
### 正直なギャップ
- macOS は現在最も強力なファイルレベルの強制を備えています。Linux のカバレッジは改善中ですが同一ではありません。
- cplt はまだ単純な読み取り専用 / workspace-write / フルアクセスのポリシープリセットを提供していません。
- 完全なコンテナ分離が必要なら、cplt は Docker を置き換えようとはしていません。
## インストール
### Homebrew (推奨)```bash
brew install navikt/tap/cplt
mise use -g 'github:navikt/cplt@'
mise はプラットフォームに適したリリースアセットを選択し、そのビルド来歴アテステーションを検証します。
バージョンを固定してください。私たちのバージョン文字列は比較可能な semver ではありません — 先頭にゼロがあり、ハイフンが 2 つ含まれているため、`mise latest` が最新リリースより古いリリースに解決されることがあります ([navikt/copilot#818](https://github.com/navikt/copilot/issues/818))。
### apt (Debian/Ubuntu、Linux では推奨)
[navikt/apt](https://navikt.github.io/apt/) は GitHub Pages 経由で提供される署名済みアーカイブで、amd64 および arm64 向けの cplt と nav-pilot を含んでいます:```bash
curl -fsSL https://navikt.github.io/apt/keyring/navikt-archive-keyring.gpg \
| sudo tee /usr/share/keyrings/navikt-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/navikt-archive-keyring.gpg] https://navikt.github.io/apt stable main" \
| sudo tee /etc/apt/sources.list.d/navikt.list
sudo apt update && sudo apt install cplt
これは私たちのリリースをミラーする単なる apt リポジトリであり、独自のメンテナを持つディストリビューションパッケージではありません。その公開ジョブは毎時実行され、各ツールの最新リリースから最新の .deb を取得するため、数分前にカットされたリリースがこの方法でインストール可能になるまで最大1時間かかります。
このパッケージはバイナリを /usr/bin/cplt に配置し、以降のアップグレードは sudo apt upgrade に乗ります。cplt update は apt インストールに触れることを拒否し、代わりに sudo apt upgrade を指し示します。dpkg の背後でバイナリを置き換えると、次の apt 実行で元に戻されてしまうからです。
アーカイブがなければ、同じ .deb はリリースアセットです:```bash
arch=$(dpkg --print-architecture) # amd64 or arm64
gh release download --repo navikt/cplt --pattern "${arch}.deb"
sudo apt install ./cplt_"${arch}".deb
### curl | bash
Debian 派生ディストリビューション以外のディストリビューション、および CI 向け:```bash
curl -fsSL https://raw.githubusercontent.com/navikt/cplt/main/install.sh | bash
オプション:```bash
curl -fsSL ... | bash -s -- --version 2026.05.05-174753-75bae5b
curl -fsSL ... | bash -s -- --dir ~/.local/bin
curl -fsSL ... | bash -s -- --no-brew
### リリースからダウンロード
お使いのプラットフォーム向けの最新ビルドを [GitHub Releases](https://github.com/navikt/cplt/releases/latest) から入手してください:```bash
# macOS, Apple Silicon (M1/M2/M3/M4)
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-aarch64-apple-darwin.tar.gz | tar xz
sudo mv cplt /usr/local/bin/
# macOS, Intel
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-x86_64-apple-darwin.tar.gz | tar xz
sudo mv cplt /usr/local/bin/
# Linux, x86_64
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv cplt /usr/local/bin/
# Linux, ARM64
curl -fsSL https://github.com/navikt/cplt/releases/latest/download/cplt-aarch64-unknown-linux-gnu.tar.gz | tar xz
sudo mv cplt /usr/local/bin/
すべてのリリースバイナリにはビルド来歴の証明が付属しています。検証するには:```bash gh attestation verify cplt -o navikt
### ソースからのビルド```bash
git clone https://github.com/navikt/cplt.git && cd cplt
cargo build --release
sudo cp target/release/cplt /usr/local/bin/
または mise を使用する場合:```bash mise run install
`mise run install` および手動ビルドでは、cplt は `/usr/local/bin/cplt` に配置されます。Homebrew ビルドも `/opt/homebrew/bin/cplt` にある場合は、開発ビルドが優先されるように `PATH` の先頭に `/usr/local/bin` を追加してください:```bash
# Check which cplt is active
which cplt
# If it shows /opt/homebrew/bin/cplt, reorder your PATH:
export PATH="/usr/local/bin:$PATH"
または /usr/local/bin/cplt を明示的に実行し、PATH 解決を完全にスキップします。
cplt には Windows サンドボックスバックエンドがありません。強制は macOS では Apple Seatbelt、Linux では Landlock LSM で行われるため、Windows 上でネイティブに実行できるものはありません。サポートされている方法は WSL2 であり、そこでは cplt は通常の Linux インストールであり、サンドボックスはカーネルによって強制されます。Microsoft のすべてのカーネルブランチは CONFIG_SECURITY_LANDLOCK=y をビルドし、CONFIG_LSM の先頭に landlock をリストしています(config-wsl)。これはカーネル 5.15.57.1 以降で提供されており、WSL のデフォルトのカーネルコマンドラインは lsm= オーバーライドを設定しません。
PowerShell で、一度だけ:```powershell wsl --install # WSL2 + the default distro (now Ubuntu 26.04 LTS), then reboot wsl --install -d Ubuntu-24.04 # ...or pin an older release wsl --update # keep the Microsoft kernel current, see the ABI note below
Everything below runs **inside the distro** (`wsl`、または Windows Terminal の Ubuntu プロファイル内) で実行され、PowerShell では実行されません:```bash
# 1. Node. Copilot CLI requires Node 22+
# Ubuntu 26.04 ships 22.x, so apt is enough:
sudo apt update && sudo apt install -y nodejs npm
# Ubuntu 24.04 ships Node 18, too old. Use nvm, fnm, or NodeSource there instead.
# 2. GitHub CLI, and log in. Ubuntu's universe package works but lags
# (2.45 on 24.04); add GitHub's apt repo if you want a current gh:
# https://github.com/cli/cli/blob/trunk/docs/install_linux.md
sudo apt install -y gh
gh auth login
# 3. The agent, installed in the distro, never on the Windows side
npm install -g @github/copilot
# 4. cplt, from the apt archive. The default distro is Ubuntu, so this is
# the same route as on any other Debian derivative.
curl -fsSL https://navikt.github.io/apt/keyring/navikt-archive-keyring.gpg \
| sudo tee /usr/share/keyrings/navikt-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/navikt-archive-keyring.gpg] https://navikt.github.io/apt stable main" \
| sudo tee /etc/apt/sources.list.d/navikt.list
sudo apt update && sudo apt install cplt
# 5. Check the result
cplt doctor
Windows 側に Copilot CLI をインストールしないでください。 interop が有効(デフォルト)な場合、Windows の PATH がディストロの PATH に追加されるため、Windows 側で npm install -g @github/copilot を実行すると、ディストロ内では /mnt/c/Users/<user>/AppData/Roaming/npm/copilot として現れます。これは interop 経由で到達する Windows インストールです。Linux サンドボックス内では実行できず、npm シムはディストロ側に node がなければ実行できません(ディストロ側にもインストールしていない限り)。以前は無関係なランタイム抽出エラーとして症状が出ていました。cplt は /mnt/<drive>/ 配下でエージェントを解決し、かつ WSL 上で実行されている場合に原因を特定するようになり、cplt doctor はこれを合格ではなく失敗チェックとして報告します(#188)。WSL の検出はカーネルが管理する状態、つまり /run/WSL または /proc/sys/kernel/osrelease と /proc/version のカーネル名から行い、WSL_DISTRO_NAME からは行いません。これは sudo 下や systemd ユニット内では存在せず、どのプロセスでも設定できるためです。通常の Linux マシンでは はそのままにされます。そこでは単なる通常のマウントポイントです。
このチェックには 2 つの制限があり、どちらも意図的なものです。デフォルトの自動マウントルートをキーにしているため、ルートを変更している場合(/etc/wsl.conf の [automount] root)、Windows 側のインストールは認識されず、パスを含む以前のより役に立たない失敗が表示されます。また、interop をオフにすると Windows の PATH の漏れは止まりますが、/mnt/c はアンマウントされません。
カーネルと Landlock ABI。 現在の WSL(2.7.x 以降)は Linux 6.18 を同梱しており、Landlock ABI 7 が利用できます。これは cplt が使用するすべての機能を含みますが、unix ソケットの connect() 権限だけは ABI 9(カーネル 7.1)が必要です。6.6 カーネル系のインストールでは ABI 3 となり、ファイルシステムルールは適用されますが、TCP ポートルール(ABI 4)、ioctl 制限(ABI 5)、シグナル/抽象ソケットのスコープ(ABI 6)は利用できず、ネットワークフィルタリングは CONNECT プロキシにフォールバックします。wsl --update で前に進めます。cplt doctor はカーネルバージョンと検出した ABI を表示します。これがあなたのマシンで重要なチェックです。
.wslconfigで Landlock を無効にしないでください。lsm=リストからlandlockを省略した[wsl2] kernelCommandLine、またはCONFIG_SECURITY_LANDLOCKなしでビルドされたカスタム[wsl2] kernel=は、cplt が依存するカーネル強制を除去し、cplt doctorは Landlock を利用不可として報告します。
プロジェクトは Linux ファイルシステム内に置いてください。 /mnt/c/Users/... ではなく、ディストロ内の ~/src/... で作業してください。Microsoft 自身のガイダンスでも、クロス OS のファイルアクセスは著しく遅いとされており、WSL 2.9.x 以降 /mnt/c はデフォルトで 9p 経由で提供されます(virtiofs は [wsl2] virtiofs=true でオプトイン)。さらに重要な点として、そのマウント上で Landlock がルールをどのように強制するかは検証していません。カーネルはネットワークや FUSE バックエンドのファイルシステムに対する除外を文書化しておらず、パイプ、ソケット、nsfs のみであり、Landlock 自身のテストスイートは 9p と FUSE を試しているため、動作すると予想しています。ここでは誰も確認していません。/mnt/c 配下のプロジェクトはサポート済みではなく未検証として扱ってください。
Bubblewrap。 Ubuntu 23.10 以降は kernel.apparmor_restrict_unprivileged_userns を通じて非特権ユーザー名前空間をブロックし、bwrap が壊れます。この sysctl は Microsoft カーネルには存在しない Ubuntu カーネルパッチに由来するため、オプションの Bubblewrap レイヤーは Ubuntu-on-WSL2 で動作すると予想されます。これはカーネルソースからの推論であり、実際に実行したものではありません。そこで bwrap が失敗する場合は、#189 でお知らせください。cplt 自身の seccomp フィルタは単純な PR_SET_SECCOMP BPF プログラムであり、WSL がすべてのプロセスにインストールするフィルタの上に重ねられます。
実際の WSL2 インストールではまだ検証されていません。 ソースから検証済み: Landlock は Microsoft カーネルでコンパイルされており、
CONFIG_LSMの先頭にあること。/mnt/<drive>/の検出、使用する WSL シグナル、およびそれらのエラーテキスト。そのようなエージェントでcplt doctorが失敗し、カーネル + Landlock ABI を表示すること。5.13+/6.7+ の要件。そしてinstall.shが Linux リリースバイナリをインストールすること。ここではまだ誰も検証していない:/mnt/c上での Landlock の挙動、WSL2 下で Bubblewrap が動作するか、あなたのディストロリリースが同梱する正確なパッケージバージョン、そして上記の手順のエンドツーエンド。実行した場合は、実際に何が起きたかを #189 で報告してください。
デフォルトでは cplt と入力することでサンドボックスを利用できます。素の copilot もサンドボックス化して実行するには:```bash
cplt --shell-install
シェルを検出し、rcファイルにエイリアスを追加して、実行内容を出力します。何度実行しても重複は追加されません。
`--agent` はどのコマンドにエイリアスを付けるかを選択し、cpltが起動できるすべてのエージェントが利用可能です:```bash
cplt --shell-install --agent opencode # 'opencode' runs sandboxed
cplt --shell-install --agent claude # and 'claude', alongside the others
各インストールは rc ファイルを置き換えるのではなく追記するため、使用するエージェントの数だけサンドボックス化できます。--agent を指定しない場合は copilot になり、これはこのフラグがこれまでずっとインストールしてきたものです。
--agent antigravity は antigravity と agy の両方のエイリアスをインストールします。どちらの名前でも同じエージェントが起動するためです。
シェルを再起動するか、ファイルを source して有効化してください。
--agent shell にはエイリアスがありません。隠すべき shell バイナリが存在しないためです。サンドボックス化されたシェルには cplt --agent shell を、単一のコマンドには cplt exec -- <command> を使用してください。
--shell-install を使いたくない場合は、この行を自分で追加してください:```bash
eval "$(cplt --shell-setup --agent opencode)"
alias opencode 'cplt --agent opencode'
mise、direnv、starship が使っているのと同じパターンです。
</details>
**各エイリアスがエージェントを指定する理由。** `alias opencode=cplt` は見た目どおりには動作しません。素の `cplt` は `--agent`、次に設定ファイル、そして PATH で見つけたものからエージェントを選びますが、PATH 検出は `copilot` を優先します。`opencode` と入力すると、代わりに Copilot がサンドボックス化され、画面上にはそれを示すものが何も表示されません。エイリアスは `--agent` を渡すので、入力したコマンドがそのまま得られるエージェントになります。
**シンボリックリンクではなくエイリアスを使う理由は?** cplt と Copilot CLI は同じ Homebrew の bin ディレクトリ(`/opt/homebrew/bin/`)にインストールされ、`copilot` という名前のファイルは 1 つしか置けないため、シンボリックリンクは競合します。エイリアスはそれを回避します。実際の `copilot` バイナリは PATH に残り、cplt がそれを見つけてラップでき、エイリアスがコマンドをリダイレクトします。
> **注記:** cplt はネストを拒否します。すでにサンドボックス内で実行中であることを検出すると(`__CPLT_WRAPPED` 環境変数経由)、再度起動しません。`--print-profile` や `cplt doctor` などの読み取り専用サブコマンドは、既存のサンドボックス内でも引き続き動作します。
## 使用方法```
cplt [OPTIONS] [-- <AGENT_ARGS>...]
-- 以降のすべてはそのままエージェントプロセス(copilot、opencode、gemini、antigravity、pi、claude、goose、dsh、または shell)に渡されます。
プリセットは、5つの主要なサンドボックストグルのベースラインを、それらを列挙する代わりに1つのフラグで設定します。個別のフラグはプリセットより優先されるため、 はその名の通りに動作します。設定ファイルで として設定することもできます。
/mnt/c| Shell | 変更されるファイル | 追加される内容(--agent opencode の場合) |
|---|
| zsh(macOS のデフォルト) | ~/.zshrc | eval "$(cplt --shell-setup --agent opencode)" |
| bash | ~/.bashrc | eval "$(cplt --shell-setup --agent opencode)" |
| fish | ~/.config/fish/conf.d/cplt.fish | alias opencode 'cplt --agent opencode' |
--preset permissive --no-allow-tmp-exec[sandbox] preset = "..."| フラグ | 動作 |
|---|---|
--preset strict | 完全なネットワークロックダウン。5つのトグルはすべてオフ、加えて gh_guard、git_guard、proxy.forced(強制プロキシegress)および proxy.default_allowlist(フェイルクローズドなドメイン許可リスト)がオン。脱出ハッチ: --allow-all-domains は許可リストのみを無効化する |
--preset standard | 現在のデフォルト。5つすべてオフ、スクラッチディレクトリはオンのまま。プリセットを渡さない場合と同じ |
--preset permissive | allow_localhost_any、allow_tmp_exec、allow_lifecycle_scripts をオンにする |
--preset full-trust | ⚠️ 危険。5つすべてをオンにし、さらに allow_env_files と allow_docker を追加する |
プリセットの完全なマトリクスと解決順序: docs/configuration.md。
プロジェクトディレクトリが書き込み可能なワークスペースであり、加えて認証、ランタイム、ツーリングに必要な狭い許可リストがあります(上の表を参照)。カーネルはそれ以外のすべてをブロックし、SSH鍵やクラウド認証情報も含まれます。
| フラグ | 動作 |
|---|---|
-d, --project-dir <DIR> | Copilotが作業できるディレクトリ。デフォルトは現在のgitリポジトリのルート |
--allow-read <PATH> | プロジェクト外のファイルをCopilotに読み取り専用で読ませる。繰り返し指定可能 |
--allow-write <PATH> | プロジェクト外のファイルをCopilotに読み書きさせる。慎重に使用すること。繰り返し指定可能。ツリーは書き込み可能だが実行可能ではない — 両方を兼ねるツリーはバイナリドロップの経路になるため、~/.cargo に対する allow.write は ~/.cargo/bin の実行も止める。両方が必要な場合は、重複しない別のツリーに --allow-exec を使用すること |
--allow-exec <PATH> | ⚠️ 危険。デフォルトのツールディレクトリ外のツリーからエージェントがバイナリを実行できるようにする — 例えば移転されたHomebrewやツールチェーンのプレフィックス。読み取りと実行を許可し、書き込みは決して許可しない。繰り返し指定可能。安全でないルート(/、/tmp、$HOME とその親、プラットフォームのシステムディレクトリ)や、書き込み可能なツリーと重複するツリーに対しては拒否される — プロジェクトディレクトリ、--allow-write の許可、~/.cache のような書き込み可能なツールディレクトリ、書き込み可能なエージェントデータディレクトリ(~/.claude、~/.local/share/opencode、~/.pi/agent など)、worktreeやbareリポジトリの実際の .git、またはバックエンドが許可なしで書き込み可能にするツリー(Linuxでは /tmp と /dev/shm、macOSでは /private/tmp と /private/var/folders): 書き込み可能かつ実行可能はバイナリドロップの経路であり、どちらのバックエンドも実行許可から書き込み許可を差し引くことはできない |
--allow-socket <PATH> | ⚠️ 危険。Unixドメインソケットのパスを許可する。例えばカスタムLSPデーモンやデータベースソケット。繰り返し指定可能。反対側にあるものはサンドボックス外で実行されるため、これを docker.sock やエージェントソケットに向けることは --allow-docker と等価であり、唯一のガードは --deny-path の重複が拒否されることだけである。Linuxではカーネル7.1未満では何もしない。ABI v9より前はunixソケット接続がLandlockでゲートされないため(Linux limitations を参照) |
--deny-path <PATH> | そうでなければ許可されるパスをブロックする。拒否は常に優先される。繰り返し指定可能 |
--allow-port <PORT> | 追加のポートでのアウトバウンドトラフィックを許可する。デフォルトでは443のみ。繰り返し指定可能。macOSではルールは (remote ip "*:PORT") であり、これはファミリー非依存であるためTCPだけでなくUDPも運ぶ。LandlockはTCP接続のみをゲートする。proxy.forced の下では、そのポートは直接ソケットを一切開かない — プロキシ経由で到達可能であるため、プロキシ対応ツールは動作し続ける |
--allow-localhost <PORT> |
cpltはデフォルトで子環境をサニタイズします。安全な変数のみが通過し、クラウド認証情報、データベースURL、パッケージトークンは除去されます。また、npm/yarn/pnpmのライフサイクルスクリプト(postinstallフック、最大のサプライチェーン攻撃ベクター)をブロックし、gitのコミットとタグの署名を無効化し(サンドボックス内では ~/.ssh と ~/.gnupg に到達できないため)、開発者ツーリングのテレメトリをオプトアウトする(DO_NOT_TRACK=1、NEXT_TELEMETRY_DISABLED=1、TURBO_TELEMETRY_DISABLED=1、CHECKPOINT_DISABLE=1 など)ハードニング変数を注入します。
通過するもの:
| カテゴリ | 例 | 方法 |
|---|---|---|
| コアシステム | HOME、USER、PATH、SHELL、TMPDIR、LANG | 明示的な許可リスト |
| ターミナル | TERM、COLORTERM、TERM_PROGRAM | 明示的な許可リスト |
| エディタ | EDITOR、VISUAL、PAGER | 明示的な許可リスト |
| 認証トークン | GH_TOKEN、GITHUB_TOKEN、COPILOT_GITHUB_TOKEN | すでに設定している場合のみ渡される。ghガードは代わりにワンタイムファイルを使用する |
| Copilot設定 | COPILOT_DEBUG、COPILOT_* | プレフィックス許可リスト |
| 言語ランタイム | NODE_*、GOPATH、CARGO_HOME、JAVA_HOME、VIRTUAL_ENV、PYTHONPATH | 明示的な許可リスト |
| ツールマネージャ | NVM_*、FNM_*、PYENV_*、MISE_*、SDKMAN_*、COREPACK_*、YARN_* | プレフィックス許可リスト |
| OpenTelemetry | OTEL_EXPORTER_OTLP_ENDPOINT、OTEL_SERVICE_NAME、OTEL_RESOURCE_ATTRIBUTES、OTEL_* | プレフィックス許可リスト(OTEL_EXPORTER_OTLP_HEADERS はオプトインの認証を運ぶ場合がある) |
| XDGディレクトリ | XDG_CONFIG_HOME、XDG_DATA_HOME、XDG_STATE_HOME、XDG_CACHE_HOME | 明示的な許可リスト |
シークレットサフィックス保護付きプレフィックス許可リスト。 COPILOT_* や YARN_* のような許可されたプレフィックスに一致する変数でも、シークレットを含むサフィックスで終わる場合は除外されます: _TOKEN、_AUTH、_SECRET、_SECRET_KEY、_KEY、_PASSWORD、または _CREDENTIALS。したがって COPILOT_DEBUG は通過し、COPILOT_API_KEY は通過しません。
常にブロック: AWS_*、AZURE_*、NPM_TOKEN、DATABASE_URL、VAULT_TOKEN、SSH_AUTH_SOCK、Docker変数、CIトークン、および許可リストにないものすべて。
| フラグ | 動作 |
|---|---|
--pass-env <VAR> | 1つの環境変数をエージェントに通過させる。繰り返し指定可能 |
--inherit-env | ⚠️ 危険。親環境全体を継承する。NO_COLOR、FORCE_COLOR、SSH_AUTH_SOCK、SSH_AGENT_PID のみを除去する。デバッグ専用 |
| フラグ | 動作 |
|---|---|
--allow-lifecycle-scripts | npm/yarn/pnpmのライフサイクルスクリプト(postinstallフック)の実行を許可する。デフォルトでブロックされる。npm install がそれらを必要とする場合に使用する |
--allow-gpg-signing | サンドボックス内でのGPGコミットとタグの署名を許可する。公開鍵リングとGPGエージェントソケットへの読み取り専用アクセスを許可する。秘密鍵は拒否されたまま。 GPG signing を参照 |
--allow-jvm-attach | /tmp 内のJVM Attach API unixソケットを許可する。MockKのインラインモック、Mockitoのインラインエージェント、ByteBuddyに必要。 JVM Attach API を参照 |
--allow-msbuild | /tmp 内のMSBuildワーカーノードunixソケットを許可する。dotnet build に必要。永続的なMSBuild Serverは有効化しない。 MSBuild worker-node IPC を参照 |
--no-scratch-dir | デフォルトでオンのセッションごとのスクラッチディレクトリを無効化する。TMPDIRはリダイレクトされない |
--scratch-dir | セッションごとのスクラッチディレクトリを明示的に有効化する。すでにデフォルトであるため、これは設定の scratch_dir = false を上書きするためのもの |
--brief | 🧪 実験的。エージェント向けのサンドボックスブリーフをスクラッチディレクトリに書き込む(CPLT_BRIEF.md)。デフォルトはオフ。設定で sandbox.brief = true も可能。不安定なため、将来のリリースで変更または削除される可能性がある |
--no-brief | この実行でサンドボックスブリーフをオフにし、設定の sandbox.brief = true を上書きする。ブリーフでゲートされている AGENTS.md ブロックも抑制する |
--agents-md | 🧪 実験的。--brief と併用すると、管理されたcpltブロックをプロジェクトの AGENTS.md にも書き込む。デフォルトはオフ。設定で sandbox.agents_md = true も可能。--brief なしでは効果なし。不安定なため、将来のリリースで変更または削除される可能性がある |
--no-agents-md | この実行で AGENTS.md ブロックをオフにし、設定の sandbox.agents_md = true を上書きする。スクラッチディレクトリのブリーフはそのまま残す |
--allow-tmp-exec | ⚠️ 危険。システムの一時ディレクトリ(/private/tmp、)からの実行を許可する。スクラッチディレクトリを優先すること |
cpltはインストールされたツールを自動検出し、それに合わせたサンドボックスルールを書き込みます。一般に、ディスク上に存在するディレクトリのみがルールを取得するため、ファントムパスはありません。macOSでは、書き込み可能なアプリディレクトリはまだ存在しなくても検出された場合に含まれるため、初回使用時に作成できます。Linuxは存在しないパスへの書き込みを許可できないため、そこでは作成をサンドボックス外で行う必要があります。
| ランタイム | ホームディレクトリ | 環境変数 / プレフィックス | 検出 |
|---|---|---|---|
| Node.js | .nvm、.local/share/fnm、.local/bin | NODE_*、NPM_*、NVM_*、FNM_* | node |
| Rust | .cargo、.rustup | CARGO_HOME、RUSTUP_HOME | cargo |
| Go | go/bin、go/pkg | GOPATH、GOROOT、GOCACHE など | go |
| Java/Kotlin (JVM) | .sdkman、.jenv、.gradle、.m2 | JAVA_HOME、JAVA_TOOL_OPTIONS、GRADLE_*、MAVEN_*、SDKMAN_*、JENV_* | java、gradle |
| Kotlin Native | .konan | なし | なし |
| Python | .pyenv | VIRTUAL_ENV、PYTHONPATH、PYENV_ROOT、PYENV_* | python3 |
| Yarn Berry | .yarn | YARN_*(ハードニングが YARN_ENABLE_SCRIPTS を上書きする) | yarn |
| pnpm | Library/pnpm、.local/share/pnpm | PNPM_HOME | pnpm |
| Corepack | なし | COREPACK_* | なし |
| mise | .local/share/mise、.mise |
cplt doctor を実行して、あなたのエージェントに対してcpltがここで動作するかどうかを確認し、cplt doctor --verbose でマシン上で検出されたすべてを確認してください。
| フラグ | 動作 |
|---|---|
--doctor | 非推奨。 代わりに cplt doctor サブコマンドを使用すること |
--print-profile | 生成されたサンドボックスプロファイル(SBPL)を出力して終了する |
--show-denials | macOSサンドボックスの拒否ログをリアルタイムでストリームする |
--no-validate | サンドボックス制限が有効であることを検証する起動時チェックをスキップする |
-y, --yes | 対話的な確認プロンプトをスキップする。監査可能性のために設定サマリーは依然として出力される。stdinがTTYでない場合に必要であるため、CIとスクリプトには必須 |
-q, --quiet | 起動バナーと必須でないメッセージを抑制する。エラーと警告は依然として出力される。設定で sandbox.quiet = true も可能 |
--no-quiet | sandbox.quiet = true を上書きし、起動サマリーを表示する |
--no-audit | セッション後の変更レポートをスキップする。cpltは通常、実行前に固定されたベースラインコミットに対して作業ツリーを差分し、セッションが触れたものをリストアップして、機密パスにフラグを立てる。-q もこれを抑制する |
--init-config | ~/.config/cplt/config.toml にスターター設定ファイルを作成して終了する |
これらはエージェント自身のセッションフラグに変換されるため、-- セパレータは不要です。
| フラグ | 動作 |
|---|---|
--resume[=SESSION] | 前のセッションを再開する。裸の --resume は対話的に選択し、--resume=NAME は名前またはIDで選択する |
--continue | 現在のディレクトリで最も最近のセッションを再開する |
--remote | リモートコントロールを有効にし、GitHub.comやモバイルからセッションを監視・操作できるようにする |
--name SESSION | セッションに名前を付け、後で --resume=NAME がそれを見つけられるようにする |
--continue と --resume はOpenCode、Antigravity、Claude Codeにもマッピングされます:
| cpltフラグ | Copilot | OpenCode | Antigravity (agy) | Claude Code |
|---|---|---|---|---|
--continue | --continue | --continue | --continue | --continue |
--resume | --resume | --continue¹ | --continue¹ | --resume |
--resume=ID | --resume=ID | --session ID | --conversation ID | --resume ID |
--remote | --remote | 無視される | 無視される | 無視される |
--name NAME | --name NAME | 無視される | 無視される | 無視される |
¹ OpenCodeもAntigravityも対話的なセッションピッカーを持たないため、裸の --resume は「最後のセッションを続行する」を意味します。Claude Codeはそれを持つため、そのままマッピングされます。
--remote と --name はCopilot専用です。Piとshellモードはまったく変換されないため、4つのフラグすべてがそれらでは破棄されます。自動再開は別のメカニズムです: パススルー引数もセッションフラグもなしでcpltを呼び出すと、--resume が自動的に追加され、それはCopilotにのみ適用されます。
これらをサンドボックスフラグと -- パススルー引数と組み合わせてください:```bash
cplt --resume=my-task # resume by name
cplt --remote --name my-task -- -p "fix tests" # remote + named + prompt
### エージェント
`--agent <name>` でいずれかを選択するか、`cplt config set sandbox.agent <name>` でデフォルトに設定できます。名前を指定しない場合、Copilot、OpenCode、Antigravity の順に `PATH` から自動検出されます。
| エージェント | `--agent` の値 | 自動検出 | 認証 |
| --- | --- | --- | --- |
| GitHub Copilot CLI | `copilot` | はい、優先度 1 | GitHub トークン、Keychain または `gh` から |
| [OpenCode](https://opencode.ai/) | `opencode` | はい、優先度 2 | `/connect` 経由の Copilot サブスクリプション、または `--pass-env ANTHROPIC_API_KEY` |
| [Antigravity CLI](https://github.com/google-antigravity/antigravity-cli) | `antigravity`、エイリアス `agy` と `agi` | はい、優先度 3 | ブラウザでの Google OAuth |
| [Pi](https://github.com/earendil-works/pi) | `pi` | いいえ | `--pass-env ANTHROPIC_API_KEY` など |
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `claude`、エイリアス `cc` と `claude-code` | いいえ | `~/.claude` または Keychain でのサブスクリプション OAuth、`CLAUDE_CODE_OAUTH_TOKEN` (Keychain の許可を破棄)、または `--pass-env ANTHROPIC_API_KEY` |
| [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | `dsh`、エイリアス `deepseek` と `deepseek-harness` | いいえ | `--pass-env DEEPSEEK_API_KEY`、または `$DSH_HOME/.env` (`~/.dsh/.env`) |
| あなたのシェル | `shell` | いいえ | なし |
- **Pi、Claude Code、goose、DeepSeek Harness は自動検出されません。** `pi` と `dsh` は、マシン上の他の何かと衝突する可能性のある一般的なバイナリ名であり、Claude Code は意図的に選択する必要があります。
- **サードパーティの API キーはオプトインです。** `ANTHROPIC_API_KEY`、`OPENAI_API_KEY`、`GEMINI_API_KEY`、`OPENROUTER_API_KEY`、`ANTHROPIC_AUTH_TOKEN`、`CLAUDE_CODE_OAUTH_TOKEN`、および Bedrock/Vertex ルーティング変数 (`CLAUDE_CODE_USE_BEDROCK`、`AWS_BEARER_TOKEN_BEDROCK`、`CLAUDE_CODE_USE_VERTEX`、`ANTHROPIC_VERTEX_PROJECT_ID`、`GOOGLE_CLOUD_PROJECT`) は、`--pass-env` で指定しない限り通過しません。
- **サブスクリプション認証には環境変数は不要です。** OpenCode の `/connect` デバイスフローはトークンを `~/.local/share/opencode/auth.json` に保存し、Claude Code の OAuth トークンは `~/.claude` (Linux では `.credentials.json`) または macOS Keychain に存在します。どちらもサンドボックス内から到達可能なため、cplt はどちらについても API キーの欠落を警告しません。
- **OAuth ブラウザフローにはサインインプロンプトが表示されたときに `--allow-browser` が必要です。** これには Antigravity が該当します。ここにある他のすべてのエージェントは、コードと URL を出力するデバイスフローを使用し、ブラウザを必要としません。このフラグはエージェントがサンドボックス外の任意のアプリケーションを起動できるようにし、URL に絞り込むことはできないため、サインイン時にオンにして、その後オフにしてください — [フラグ表](#sandbox-toggles) と [docs/security.md](https://github.com/navikt/cplt/blob/main/docs/security.md#--allow-browser-is-a-sandbox-escape-and-cannot-be-scoped) を参照してください。
- **Claude Code の自動更新は `DISABLE_AUTOUPDATER=1` で無効化されます。** Claude Code には `--no-auto-update` フラグがなく、サンドボックス内での自己更新は永続化のベクターであり、読み取り専用のインストールパスに対してはとにかく失敗します。
- **`CLAUDE_CONFIG_DIR` は尊重されます。** これが設定されている場合、cplt は `~/.claude` の代わりにそのディレクトリを許可し、変数を通過させるため、移転された設定ルートは引き続き機能します。
- OpenCode は [公式にサポートされている Copilot クライアント](https://github.blog/changelog/2026-01-16-github-copilot-now-supports-opencode/) であるため、既存の Copilot サブスクリプションは OpenCode 内の `/connect` で機能します。
エージェントごとの設定ディレクトリ、Keychain の使用、実行権限、および環境分離については、[SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md#supported-agents) を参照してください。
### goose サポート
cplt は [goose](https://github.com/aaif-goose/goose) (オープンソース AI エージェント、バイナリ `goose`) をサンドボックス化できます。goose 1.48.0 で検証済みです。```bash
# Run goose (must be explicit — not auto-detected)
cplt --agent goose
# goose is provider-agnostic — pass your provider's API key
cplt --agent goose --pass-env ANTHROPIC_API_KEY
cplt --agent goose --pass-env OPENAI_API_KEY
# Skip the keyring entirely: keep the key in the environment
GOOSE_DISABLE_KEYRING=1 cplt --agent goose --pass-env OPENAI_API_KEY --pass-env GOOSE_DISABLE_KEYRING
# Set goose as your default agent
cplt config set sandbox.agent goose
goose のセキュリティに関する注意事項:
--agent goose で明示的に選択するか、設定で sandbox.agent = "goose" を設定してくださいANTHROPIC_API_KEY、OPENAI_API_KEY、AZURE_OPENAI_API_KEY、GOOGLE_API_KEY、DATABRICKS_HOST/DATABRICKS_TOKEN、GROQ_API_KEY、OPENROUTER_API_KEY、XAI_API_KEY、AWS_BEARER_TOKEN_BEDROCK)は認証ヒントとして認識され、--pass-env を介して渡す必要があります。goose は GEMINI_API_KEY ではなく GOOGLE_API_KEY を読み取ります。このサブセット以外のプロバイダーでも動作します。--pass-env でその変数名を指定してください--observe-domains キャプチャにおいて goose は自身のホストに一切接続しなかったため、その組み込み許可リストは共有パッケージレジストリのベースのみです。--default-allowlist を有効にする前に、allowed_domains を介してプロバイダーのドメインを追加してくださいGOOSE_DISABLE_KEYRING=1 を設定すると goose は代わりに設定ディレクトリ内の secrets.yaml を使用し、--pass-env でキーを渡せば保存されたシークレットを完全に回避できます。Linux では goose は D-Bus Secret Service を使用し、Keychain の許可は影響しません~/.config/goose/config.yaml は extensions: エントリを宣言しており、その cmd を goose がセッション開始ごとに起動するため、書き込み可能な設定ディレクトリはホスト永続化のベクターとなります。通常のセッションでは書き込みは行われず、/mode の変更や永続化されたツール権限はサンドボックス実行を超えて存続しません。cplt の外で goose configure を使用して再設定してください~/.local/share/goose/)および状態(~/.local/state/goose/)ディレクトリは書き込み可能で、exec は拒否されます。goose は macOS でもこれらの XDG パスを使用し、そこでの XDG_* オーバーライドを尊重します--continue および引数なしの --resume は goose session --resume にマップされます。--resume=ID は goose session --resume --session-id ID に、--name X は goose session --name X にマップされます。これらはサブコマンドのフラグであるため、cplt はそれらとともに session サブコマンドを注入します。--remote は無視されます(goose に相当するものはありません)cplt は DeepSeek Harness(バイナリ dsh)をサンドボックス化できます。これは DeepSeek によるプラグイン指向のエージェントハーネスです。アップストリームはこれを開発者プレビューとして提供しており、その独自の SAFETY.md には、その制御を唯一の境界として依存しないよう記載されています。まさに cplt が存在する理由がこれです。```bash
cplt --agent dsh
cplt --agent dsh --pass-env DEEPSEEK_API_KEY
cplt config set sandbox.agent dsh
**DSH のセキュリティに関する注意事項:**
- **自動検出されない**: `--agent dsh`(エイリアス `deepseek`、`deepseek-harness`)で選択するか、`sandbox.agent = "dsh"` を設定してください。`dsh` は短く一般的なコマンド名であり、お使いのマシン上の別の何かに属している可能性があります
- **cplt 内では DSH 自身のサンドボックスをオフにする**: DSH はすべてのシェルおよびファイルツール呼び出しを独自のプロセスサンドボックス(macOS では Seatbelt、Linux では bwrap または Landlock)でラップします。どちらも cplt の中に入れ子にすることはできません。macOS はネストされた `sandbox-exec` 呼び出しをサポートしていません(これは cplt が Gradle の内部サンドボックスをオフにするのと同じ制限です。[制限事項](#limitations)を参照)。また bwrap は `unshare` で名前空間を構築しますが、これは cplt の seccomp フィルターによって拒否されます。いずれにせよ cplt が強制境界となるため、サンドボックス化されたセッションでは DSH に同梱されている `danger-full-access` 権限プリセットを選択してください。内部ランナーを有効にしたままにすると、ツール呼び出しはタスクエラーではなくサンドボックスランナーエラーで失敗します
- **ホームルートは1つ、cplt はオーバーライドに従う**: DSH はセッション、設定、キャッシュ、プロファイルを `$DSH_HOME`(デフォルトは `~/.dsh`)の下に保持します。`DSH_HOME` は環境変数許可リストに含まれているため、子プロセスは cplt が許可するのと同じルートを解決します。システムルートやホームディレクトリを指す値は起動前に拒否され、これは `CLAUDE_CONFIG_DIR` が経るのと同じ拒否措置です
- **ホスト永続化ガード**: `$DSH_HOME/cordis.patch.yml` は、Loader が起動時に読み込むホームレベルのオーバーレイであり、書き込みが拒否されます。`$DSH_HOME/profiles/` は書き込み可能なままです。これは DSH が起動のたびに各プロファイルの `cordis.yml` インクルードルートを書き換えるためであり、プロファイルごとの `cordis.patch.yml` とインストール済みプラグインは文書化された残存リスクです。プロファイルと `dsh plugin` の編集は cplt の外で行い、常に cplt 経由で `dsh` を起動して、何かが仕込まれていてもサンドボックス内で実行されるようにしてください
- **デフォルトドメイン**: `deepseek.com` のみ。同梱の `dsh-llm-deepseek` アダプターはデフォルトで `https://api.deepseek.com` を使用します。`DEEPSEEK_BASE_URL` をゲートウェイに向ける場合は、`allowed_domains` 経由でそのゲートウェイのドメインを追加する必要があります
- **認証**: `--pass-env DEEPSEEK_API_KEY` でキーを渡すか、`$DSH_HOME/.env` に保管してください。DSH 自身のモデル UI を通じて保存されたキーは `$DSH_HOME/.credentials.yaml` に書き込まれ、同じ書き込み可能ルート内にあります。macOS Keychain は拒否されるため、HTTPS 経由の `git push` には `hosts.yml` 内の `gh` のトークンか `--pass-env GH_TOKEN` が必要です
### シェルモード
AI エージェントなしで、同じ制限を持つプレーンなサンドボックス化シェルを実行します。ビルドツールのテスト、サンドボックスの問題のデバッグ、または手作業で慎重に作業するのに便利です。```bash
# Interactive sandboxed shell (uses $SHELL: fish, zsh, bash)
cplt --agent shell
# Inspect what's allowed without entering the shell
cplt --agent shell --print-profile
デフォルト拒否の同じルールが適用されます: ファイルシステムの分離、ネットワーク制限、環境変数のサニタイズ。シェル設定ディレクトリ(fish の変数と履歴、zsh の履歴)は書き込み可能なままです。
単一のコマンドには、cplt exec が cplt --agent shell -- -c 'cmd' よりもクリーンです。
エージェントを起動せずに、サンドボックス内で任意のコマンドを実行します。起動バナーも確認プロンプトもないため、スクリプト、パイプ、シェルエイリアスに適しています。```bash
cplt exec -- npm install cplt exec -- make build cplt exec -- go test ./...
cplt exec -c "npm install && npm test"
cplt exec --allow-lifecycle-scripts -- npm install cplt exec --project-dir /path/to/repo -- make build cplt exec --with-proxy -- curl https://example.com
alias npm="cplt exec -- npm" alias node="cplt exec -- node" alias python="cplt exec -- python"
すべてのトップレベル `cplt` フラグが適用されます: `--project-dir`、`--allow-read`、`--deny-path`、`--with-proxy`、`--pass-env` など。コマンド実行前に完全なサンドボックス設定の概要を確認するには `--no-quiet` を追加してください。
### 例```bash
# The common case: Copilot in the sandbox
cplt -- -p "fix the tests"
# Sessions
cplt --resume # pick one interactively
cplt --resume=my-refactor # by name
cplt --continue # most recent in this directory
cplt --remote --name my-task -- -p "fix tests" # named remote session
# Check the environment before the first run
cplt doctor
# Let Copilot read a shared library directory
cplt --allow-read ~/shared-libs -- -p "use shared-libs"
# Block a path you don't want Copilot to see
cplt --deny-path ~/.config/gh -- -p "refactor auth"
# Extra outbound port, e.g. an external API
cplt --allow-port 8443 -- -p "test the API"
# Localhost for MCP servers or dev servers
cplt --allow-localhost 3000 --allow-localhost 8080 -- -p "use the MCP server"
# All of localhost, needed by Next.js/Turbopack and Vite builds
cplt --allow-localhost-any -- -p "fix the build"
# Pass specific env vars through
cplt --pass-env MY_CUSTOM_VAR --pass-env ANOTHER_VAR -- -p "run with custom config"
# Inherit the full environment (dangerous, debugging only)
cplt --inherit-env -- -p "debug the build"
# Network
cplt --no-proxy -- -p "fix the tests" # proxy is on by default
cplt --blocked-domains ./blocked-domains.txt -- -p "refactor"
cplt --allow-private-domain intern.nav.no -- -p "use mcp-onboarding"
# Non-interactive / CI (skip the confirmation prompt)
cplt --yes -- -p "fix the tests"
# Inspect and debug the sandbox itself
cplt --print-profile
cplt --show-denials -- -p "fix the tests"
設定は2つのレベルで行われます。開発者の好みに合わせたグローバル設定と、チームポリシーに合わせたリポジトリごとの設定です。```bash
cplt settings
cplt config set sandbox.quiet true cplt config set proxy.blocked_domains "~/.config/cplt/blocked-domains.txt" cplt config set git_guard.mode warn # observe pushes instead of blocking them cplt config set gh_guard.enabled false # opt out of the gh guard entirely
cplt config set --repo sandbox.allow_jvm_attach true cplt config set --repo deny.paths "~/secrets"
cplt config show # effective config (file + defaults) cplt config explain # every key with its description
`cplt settings` は対話型エディタであり、Effective、Global、Repository の各ビュー、検索、ステージングされた変更、およびセキュリティ上重要なものを保存する前の明示的な確認を備えています。`cplt config` はスクリプトや CI 向けの安定した非対話型インターフェースのままです。リポジトリの提案は依然として `cplt trust` で別途コミットおよび承認されます。エディタがそれらをコミットしたり自動承認したりすることはありません。
優先順位は CLI フラグ、次に `~/.config/cplt/config.toml` のグローバル設定ファイル、そして組み込みのデフォルトの順に適用されます。`.cplt.toml` 内のリポジトリごとの設定は、その階層の一段ではなく別個のレイヤーです。`[deny]` は無条件に厳格化し、承認されたパーミッションは追加のみであるため、リポジトリは機能を有効にできますが、CLI フラグやグローバル設定で設定されたものを無効にすることは決してできません。
リポジトリルートの `.cplt.toml` はチームポリシーを保持します:```toml
[deny] # Applied automatically, no opt-in needed
paths = ["~/secrets", "~/.vault-token"]
env = ["VAULT_TOKEN", "DATABASE_URL"]
[propose] # Requires developer approval (cplt trust accept)
gh_guard = true
git_push_prevention = true
allow_jvm_attach = true
allow_docker = true
[propose.allow]
ports = [5432]
localhost = [3000]
socket = ["/var/run/docker.sock"]
cplt はそれを git HEAD から読み取るため、エージェントはセッション中に自身のポリシーを改ざんできず、信頼の承認はファイルの内容に固定されます。コミットされていない .cplt.toml は、コミットされるまで何も許可しませんが、その [deny] キーは依然として適用されます。誰もプロンプトに応答できない CI やスクリプトでは、--accept-repo-config がその 1 回の実行に限りコミット済みファイルの提案を承認し、信頼を永続化しません。cplt init はプロジェクトのツールを検出して、あなたのために 1 つを書き出します:```bash
cplt init # preview detected permissions
cplt init --write # write .cplt.toml to disk
cplt init --quiet # output only TOML (pipe-friendly)
cplt init --global # generate a personal ~/.config/cplt/config.toml
JVM(Gradle/Maven)、Node.js、Docker、Python、Rust、Go、Playwright、Spring Boot、Ktor、TestContainers、Next.js、Vite、Flyway、Cypress、および `.env.example` からの環境シークレットを認識します。危険なパーミッションは、リスク警告が添付された状態でジェネレーターから出力されます。`--global` は代わりにマシンレベルの項目を調べます:Playwright ブラウザ、GPG 署名、レジストリ認証情報、代替エージェント。
一部のキーはグローバル専用であり、マシン固有またはローカル設定であるため `.cplt.toml` からは拒否されます:`sandbox.agent`、`sandbox.quiet`、`sandbox.yes`、`sandbox.validate`、`sandbox.scratch_dir`、`sandbox.pass_env`、`sandbox.inherit_env`、`sandbox.allow_cache_exec`、`sandbox.allow_cache_exec_any`、`proxy.enabled`、`proxy.port`、`proxy.log_file`、`proxy.log_level`、`proxy.blocked_domains`、`proxy.allowed_domains`、およびすべての `[gh_guard]` と `[git_guard]` キー。
信頼モデル、パス展開ルール、完全な設定ファイルリファレンスを含む詳細:[docs/configuration.md](https://github.com/navikt/cplt/blob/main/docs/configuration.md)。
## アーキテクチャ```
┌──────────────────────────────────┐
│ cplt (Rust binary) │
│ ┌───────────┐ ┌─────────────┐ │
│ │ Policy │ │ CONNECT │ │
│ │ Generator │ │ Proxy │ │
│ └─────┬─────┘ │ (optional) │ │
│ │ └─────────────┘ │
│ ▼ │
│ ┌─────────────┬────────────┐ │
│ │ macOS │ Linux │ │
│ │ Seatbelt │ Landlock │ │
│ │ sandbox- │ + seccomp │ │
│ │ exec │ pre_exec │ │
│ └─────────────┴────────────┘ │
│ │ │
│ ▼ │
│ copilot (sandboxed) │
│ ├── All child processes │
│ ├── Cannot read ~/.ssh │
│ ├── Network port-restricted │
│ ├── SSH agent blocked │
│ └── Filesystem = primary ctrl │
└──────────────────────────────────┘
セキュリティモデルは、カーネルによる強制を伴うデフォルト拒否のファイルシステムです。macOS、およびカーネル6.7以降(Landlock ABI v4)のLinuxでは、ネットワークはデフォルトでポート443に制限され、追加分には --allow-port を使用します。古いLinuxカーネルでは、代わりにCONNECTプロキシがその制限を提供するため、デフォルトで有効になっています。SSHエージェントへのアクセスとlocalhostへのアウトバウンドは、macOSではカーネルでブロックされます。Linuxではどちらもブロックされません。ポートベースのLandlockルールはlocalhostとリモートホストを区別できず、unixソケットの connect() はカーネル7.1未満ではLandlockによってゲートされないため、bubblewrapがマスクするソケットを除けば、保留された SSH_AUTH_SOCK がエージェントとロード済みのキーとの間に立ちはだかる唯一のものです。プロファイルジェネレーターは環境を検出し(cplt doctor --verbose は同じプローブ結果を表示します)、ディスク上に実際に存在するツールディレクトリに対してのみルールを出力します。ルールが少ないほど、サンドボックスは厳密になります。
sandbox-exec に渡されますpre_exec を介して適用されます(カーネル5.13以降、TCPポートフィルタリングは6.7以降)内部構造とモジュール構成: docs/architecture.md。脅威モデル、防御層、正直なギャップ: SECURITY.md。
単一バイナリ、最小限の依存関係、ランタイムサービスなし、テレメトリなし。明確な境界を持つ3つの防御層:
| 層 | 強制 | バイパス可能? | 保護対象 |
|---|---|---|---|
| 1. カーネルサンドボックス | macOS Seatbelt / Linux Landlock+seccomp | ❌ いいえ | ファイルアクセス、exec、ネットワークポート |
| 2. ネットワークプロキシ | CONNECTプロキシ、ドメインフィルタリング | ❌ いいえ(サンドボックス内) | アウトバウンド接続、持ち出し |
| 3. コマンドガード | PATHベースのラッパースクリプト | ⚠️ ソフトバリア | プッシュ、マージ、リリース、API書き込み |
cpltが防御するもの:
.env ファイル): カーネルでブロック.git/hooks はmacOSではカーネルレベルで書き込みが拒否されます。Linuxでは、LandlockでBubblewrapなしの場合、書き込み可能なままで、cplt自身の親側の git は core.hooksPath=/dev/null で実行されるため、仕込まれたフックを実行することはありませんが、自分で実行する git は実行してしまいますPNPM_HOME、~/.deno/bin、~/.bun/bin)による永続化: サンドボックス内で pnpm add -g などが動作するように書き込みが許可されているため、エージェントは、後で シェルが PATH から拾い上げるバイナリを残すことができますgit、bwrap、sandbox-exec、mise、およびトークンを読み取る gh)を PATH ではなく固定のシステムディレクトリから解決しますが、エージェントバイナリ自体は発見された場所から実行され、npmグローバルインストールの場合、通常は書き込み可能なmiseまたはnodeツリーの下にあります。cpltはそれを固定ディレクトリから解決できません — それは正当にあなたのバージョンマネージャーが置いた場所に存在するため — そのため、解決されたパスをサンドボックスが適用しようとしている書き込みルールと照合し、起動時に警告して、バイナリと書き込み可能なツリーを名指しした上で続行しますcplt doctor: その --version プローブは、PATH 上で見つけた各エージェントバイナリを親プロセスで実行するため、仕込まれたものがそこで実行されます — 上記の起動時と同じ発見パスへの露出であり、これがdoctorが境界ではなくレポートである理由です。その gh チェックは信頼されたディレクトリから解決され、カーネルリリースの読み取りは何も起動しませんcpltが防御しないもの:
sandbox.keychain_substitute でその許可を引き換えにできます私たちの優先事項は、順に: 正確(すべての主張はテストされ、すべてのエッジケースにはCVEまたは研究の参照がある)、透明(SECURITY.md は何も隠さない)、シンプル(単一バイナリ、設定不要、適切なデフォルト)、そして有用(邪魔にならず、エージェントを安全に作業させる)。
詳細: docs/security.md · SECURITY.md
プロキシはデフォルトで有効です。Copilot CLI、gh、curl からのすべてのアウトバウンドトラフィックは、HTTP_PROXY/HTTPS_PROXY と NODE_USE_ENV_PROXY=1 を介してローカルホストのCONNECTプロキシを通ります。OSが割り当てたエフェメラルポートでリッスンするため、何も衝突しません。リアルタイムの接続ログ、ドメインブロッキング、ドメイン許可リスト、永続的な監査ログ、そしてサンドボックスが強制するのと同じポートポリシー(443と allow.ports にあるもの)が得られます。```bash
cplt --proxy-forced -- -p "fix tests" # force all egress through the proxy
cplt --no-proxy -- -p "fix tests" # disable for one run
cplt --blocked-domains blocked-domains.txt -- -p "x" # block known-bad domains
cplt --allowed-domains allowed-domains.txt -- -p "x" # allowlist mode
cplt --default-allowlist -- -p "x" # fail-closed: only the agent's own domains
cplt --observe-domains -- -p "x" # record what the agent contacts, block nothing
cplt --proxy-upstream http://proxy.corp:8080 -- -p "x" # chain through a corporate proxy
`--observe-domains-out <FILE>` は観測されたセットを1行に1ドメインずつ書き出し、
`--proxy-upstream-no-proxy <HOST>` はアップストリーム経由ではなく直接到達するホストを列挙します。```bash
cplt config set proxy.enabled false
cplt config set proxy.blocked_domains "~/.config/cplt/blocked-domains.txt"
cplt config set proxy.allowed_domains "~/.config/cplt/allowed-domains.txt"
cplt config set proxy.log_file "~/.config/cplt/proxy.log"
プロキシ強制モードはオプトインです。カーネルの外向き通信をプロキシポートに制限するため、直接開かれたソケットや env -u HTTPS_PROXY がすり抜けることはできません。強制は macOS では完全で、localhost:<proxy_port> に固定されます。Linux では直接の TCP :443 をブロックし、seccomp ルールは AF_INET/AF_INET6 に対してプロトコル 0 または IPPROTO_TCP を持つ SOCK_STREAM のみを許可するため、UDP、raw、SCTP、DCCP も閉じられます — その代償として、UDP を送信するコードだけでなく、そのようなソケットを開くあらゆるものが対象になります。残るのはポートベースの残余、evil.com:<proxy_port> であり、これは #114 まで続きます。
プロキシ強制以外では、Linux は UDP を制限しません。Landlock のネットワーク権限は ABI v10 まで TCP のみであり、cplt は AccessNet::ConnectTcp のみを処理し、上記の seccomp ルールは意図的に適用されません — そこで SOCK_DGRAM を拒否すると getaddrinfo(3) が壊れ、したがってプロキシを使用しないすべてのツールで DNS が壊れます。したがって、任意のホストへの外向き UDP、内向き UDP バインド、DNS トンネリング、QUIC/HTTP-3 はデフォルトモードでは仲介されず、CONNECT プロキシは TCP のみを運ぶため、そのいずれもプロキシログに現れません。macOS はデフォルトモードで UDP を制限しますが、同様にルーティングもしません: remote ip "*:443" は UDP をカバーするため、443 上の QUIC/HTTP-3 はそこでもプロキシに触れることなく出ていきます。proxy.forced の下では、macOS ではプロキシログが外向き通信の完全な記録となります。Linux では、上記の evil.com:<proxy_port> 残余を除いて完全であり、これはプロキシを通過しないためそのログにも現れません。
両方のリストは同じようにマッチします: example.com は正確なドメインとすべてのサブドメインをカバーし、マッチングは大文字小文字を区別せず、末尾のドットは除去されます。ブロックリストと許可リストのファイルは 5 秒ごとに再読み込みされるため、ライブで編集できます。ローカルホストのトラフィックは NO_PROXY を介してプロキシをバイパスし、監査ログに現れることはありません。--proxy-timeout <SECONDS> はリクエストとヘッダーの読み取りを制限し(デフォルト 60)、確立された CONNECT トンネルを切断しません。トンネルは最大 1 時間アイドル状態になることがあります。
すべてのプロキシフラグ、ドメインフィルタリングの詳細、上流の企業プロキシチェーニング、および接続ログの形式: docs/proxy.md。
これらを有効にすると、cplt は $PATH 内のラッパースクリプトを通じて gh と git をインターセプトします:
| コマンド | アクション |
|---|---|
gh pr merge、gh repo delete、gh release create | 🔒 ブロック |
git push origin main、git push --force | 🔒 ブロック |
gh api(他のリポジトリへの書き込み) | 🔒 スコープチェック |
gh pr list、gh issue list、git commit | ✅ 許可 |
git push origin feature-branch | ✅ protect_default_branch_only で許可 |
これはレイヤー 3、ソフトバリアです。従順なエージェントが誤って破壊的なことをするのを防ぎます。ハードな境界には、カーネルサンドボックスとサーバー側のブランチ保護に頼ってください。
gh ガードを有効にすると、cplt は起動時に GitHub トークンをキャッシュし、gh auth token コールバックを通じて一度だけ提供し、その後キャッシュを削除します。これにより偶発的および環境ベースの漏洩を削減します。これは敵対的なエージェントに対する境界ではありません。キャッシュはエージェント自身の TMPDIR に存在し、正当なコンシューマーの前にそれを読むエージェントは依然としてトークンを取得するからです。block_auth_token に関する完全な声明は SECURITY.md にあります。
完全な動作: docs/gh-guard.md · docs/git-guard.md
サンドボックスは一部のワークフローを意図的にブロックします。一般的なものとその修正方法:
| 影響 | 修正 |
|---|---|
.env ファイルがブロックされる | cplt config set sandbox.allow_env_files true |
| npm postinstall フックがブロックされる | cplt config set sandbox.allow_lifecycle_scripts true |
go test / mise run がブロックされる(一時実行) | スクラッチディレクトリはデフォルトで有効です。それでも必要な場合は cplt config set sandbox.allow_tmp_exec true |
| ローカルホスト接続がブロックされる | cplt config set allow.localhost 3000、または cplt config set sandbox.allow_localhost_any true |
| Docker がブロックされる | cplt config set sandbox.allow_docker true ⚠️ |
| SSH がブロックされる | 代わりに HTTPS リモートを使用してください |
| GPG 署名が無効化される | cplt config set sandbox.allow_gpg_signing true |
| JVM MockK/Mockito が失敗する | cplt config set sandbox.allow_jvm_attach true |
dotnet build の MSBuild ワーカーノードがブロックされる | cplt config set sandbox.allow_msbuild true |
| プライベートレジストリの認証情報がブロックされる | cplt config set allow.read "~/.m2/settings.xml" |
| 内部 Maven/Nexus リポジトリに到達できない(Gradle/Maven) | cplt config set proxy.allow_private_domains "intern.example.com"。IP リテラルのリポジトリ URL は許可できません — ホストに DNS 名を付けてください。以下を参照 |
| Playwright Chromium が起動しない | キャッシュ実行を許可し、Chromium のネストされたサンドボックスを無効にします。以下を参照 |
Playwright Chromium には cplt config set sandbox.allow_cache_exec ms-playwright が必要です。 また、Chromium は自身のネストされたサンドボックスなしで実行する必要があります。macOS ではそのヘルパーは cplt 内で 2 つ目の Seatbelt サンドボックスを初期化できません(forbidden-sandbox-reinit)。Linux では cplt の seccomp フィルターがそのサンドボックスが必要とする名前空間システムコールをブロックします。ライブラリとしての Playwright はすでに --no-sandbox で起動し、同じオプトインが Playwright MCP に対して PLAYWRIGHT_MCP_SANDBOX=false を設定します。そうでなければそれを再び有効にしてしまいます。他の Chromium ランチャーは自身で --no-sandbox が必要です。cplt は引き続き強制するカーネル境界ですが、侵害されたレンダラーは Chromium のより狭い子プロファイルではなく、完全な cplt Playwright プロファイルを受け取ります。Cache exec と SECURITY.md を参照してください。
Git コミットはすべてのエージェントで機能しますが、git push が HTTPS 経由で機能するかどうかはエージェントによって異なります。 3 つの前提条件: SSH ではなく HTTPS リモートを使用する(git remote set-url origin https://github.com/org/repo.git、または git config --global url."https://github.com/".insteadOf "[email protected]:" でグローバルに書き換える)、サンドボックス外で一度 gh auth login を実行する、そして認証情報ヘルパーがまだ設定されていない場合は gh auth setup-git を実行する。その後、プッシュは gh auth git-credential を実行し、これにはサンドボックス内から gh が到達できるトークンが必要です — これはエージェントごとに異なります。Git workflow を参照してください。デフォルトブランチへのプッシュとすべての強制プッシュはデフォルトで git ガードによって拒否されます。フィーチャーブランチをプッシュしてください。SSH エージェントソケットはブロックされます。これはすべてのロードされたキーを解放し、任意のホストに認証できるためです。一方、gh 認証情報ヘルパーは GitHub にスコープされています。
JVM はプロキシを認識するため、プライベート IP 上の内部 Maven リポジトリを許可する必要があります。 cplt は http(s).proxyHost/proxyPort を JAVA_TOOL_OPTIONS に注入するため、Gradle と Maven の依存関係解決は CONNECT プロキシを経由し、バイパスするのではなくプロキシログに現れます。プロキシの SSRF ガードは、curl、npm、pip に対してすでに行っているのとまったく同じように、プライベートアドレス空間に解決される社内 Nexus や Artifactory を拒否します。その DNS 名を proxy.allow_private_domains に追加してください。ベア IP リテラルとして書かれたリポジトリ URL(https://10.20.30.40/repository/maven-public/)はどのキーでも許可できません — そのチェックは許可リストが参照される前に実行されるため、そのようなリポジトリには DNS 名が必要です。WorkerExecutor プラグインフォーク、および cplt の外部で起動され内部で再利用される Gradle デーモンはプロキシされません。Internal Maven/Gradle repositories on private IPs を参照してください。
Gradle 9+ は自身のネストされたサンドボックスを実行し、cplt はそれを無効にします。 Gradle 8.8 以降、デーモンは自身を sandbox-exec でラップします(GRADLE_MACOS_SANDBOX で制御、以前は org.gradle.daemon.sandbox プロパティ)。macOS はネストされた sandbox-exec 呼び出しをサポートしていないため、内側のサンドボックスはソケット操作で「Operation not permitted」で失敗します。cplt はすでにカーネルレベルのサンドボックス化を提供しているため、GRADLE_MACOS_SANDBOX=off を注入します。これは、Gradle を外側のサンドボックスでラップするあらゆるツールに影響する既知の上流の問題です。Gradle 自身のサンドボックスを本当に望む場合は --pass-env GRADLE_MACOS_SANDBOX で上書きしてください。
Copilot CLI 1.0.83 は自身のネストされたサンドボックスを実行し、cplt はそれを無効にします。 Linux ではそのサンドボックスはネットワーク名前空間を構築し — slirp4netns、iptables、/dev/net/tun — cplt の seccomp フィルターはそれが取る unshare を拒否します。cplt はまた HTTP_PROXY/HTTPS_PROXY を設定し、これは 1.0.83 では要求したかどうかに関わらず Linux サンドボックスをプロキシ外向きパスに置くため、両者は起動のたびに衝突します。症状: [cplt] Starting Copilot in sandbox... の後に何も起こらない。cplt は Copilot 自身のオプトアウト COPILOT_CLI_SANDBOX_SUPPORT_OVERRIDE=unsupported を注入します。Copilot はセッション中スタンドダウンし、その旨を伝え、保存された sandbox.enabled はそのままにします。cplt が境界であり、Gradle や Chromium に対するのと同じです。--pass-env COPILOT_CLI_SANDBOX_SUPPORT_OVERRIDE で上書きしてください。サンドボックスを要求するエンタープライズ管理ポリシーはこのすべてを上書きします — Copilot CLI's own command sandbox を参照してください。
すべての影響、ツール別の表、JVM と Kotlin デーモンの注意事項、GPG のトラブルシューティング、およびプライベートレジストリのプラットフォーム差異: docs/known-impacts.md。
sandbox-exec は非推奨です。Apple はそれを削除していませんが、将来の macOS バージョンで削除する可能性があります。lsopen にもフィルターがないため、--allow-browser は Launch Services のすべてか無かです。これを有効にすると、エージェントはサンドボックス外の任意のアプリケーションを起動でき、どのラッパーもそれを狭めることはできません — docs/security.md を参照してください。.env の読み取り/書き込み/削除はカーネルで強制されません。.git/hooks への書き込みは Bubblewrap がアクティブなときにブロックされます。--deny-path には Bubblewrap が必要です。bwrap がアクティブなときはマウントマスクを通じて強制されます。これがない場合、Landlock は許可リストのみであり、cplt は拒否を適用する代わりに警告します。詳細: docs/security.md
コントリビューションを歓迎します。```bash git clone https://github.com/navikt/cplt.git && cd cplt git config core.hooksPath hack # enables pre-commit fmt + clippy checks mise run check # runs fmt, clippy, and tests
大きな変更を始める前に issue を開いてください。すべての PR は CI(fmt、clippy、テスト)を通過する必要があります。
## 参考資料
- [SECURITY.md](https://github.com/navikt/cplt/blob/main/SECURITY.md)、完全なセキュリティモデル、脅威分析、テスト戦略、および先行事例
- [Apple sandbox-exec(1)](https://keith.github.io/xcode-man-pages/sandbox-exec.1.html)
- [Chromium Seatbelt V2 Design](https://chromium.googlesource.com/chromium/src/sandbox/+show/refs/heads/main/mac/seatbelt_sandbox_design.md)
- [Landlock LSM documentation](https://docs.kernel.org/userspace-api/landlock.html)
- [seccomp-BPF documentation](https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html)
- [OWASP SSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html)
- [michaelneale/agent-seatbelt-sandbox](https://github.com/michaelneale/agent-seatbelt-sandbox)
## ライセンス
[MIT](https://github.com/navikt/cplt/blob/main/LICENSE)
1つのポートで localhost へのアウトバウンドを許可する。Localhostはデフォルトでブロックされる。MCPサーバーや開発サーバーに使用する。繰り返し指定可能 |
--allow-localhost-any | localhost へのアウトバウンドをすべてのポートで許可する。IPCにランダムなエフェメラルポートを使用するTurbopack(Next.js)やViteのようなビルドツールに必要 |
/private/var/folders--allow-cache-exec <SUBDIR> | 1つの ~/Library/Caches/<SUBDIR> からの実行を許可する。繰り返し指定可能。Playwrightやpnpm dlxのようにそこでコンパイル済みバイナリをキャッシュするツール向け |
--allow-cache-exec-any | ⚠️ 危険。~/Library/Caches 全体からの実行を許可する。--allow-cache-exec <SUBDIR> を優先すること |
--allow-browser | ⚠️ 危険。これをオンにすると、エージェントはサンドボックス外であなたのマシン上の任意のアプリケーションを起動できる。 許可されるのはLaunch Servicesであり、ブラウザではない: launchdはターゲットをSeatbeltプロファイルの外で起動するため、open -a Terminal /tmp/x.sh はサンドボックス外で実行される。これはURLにスコープを限定できない — SBPLの lsopen はフィルタを受け付けず、許可は open バイナリをまったく介さずに LSOpenCFURLRef() を通じて到達可能であるため、どのラッパーもそれを狭めることはできない(#251、および docs/security.md)。サインインプロンプトが実際に画面に表示されている間(MCPサーバーのOAuth、再認証)だけオンにし、その後オフに戻すこと。デフォルトはオフ |
--deny-clipboard | com.apple.pasteboard Machサービスを拒否することで、エージェントがmacOSクリップボード(pbpaste/pbcopy)を読み書きするのをブロックする。他のすべてのMachサービス(Keychain、DNS、Securityフレームワーク)は影響を受けない。デフォルトでオン — このフラグはデフォルトを再表明する |
--allow-clipboard | cpltがデフォルトで拒否するmacOSクリップボードをエージェントに返す。sandbox.deny_clipboard = false と等価 |
--use-bubblewrap | Linuxのみ。Landlockとseccompの上にbubblewrap名前空間レイヤー(PID、mount、IPC、UTS、cgroup、user名前空間とプライベートな /tmp)を要求する。bwrap がない場合はエラーになる。どちらのフラグも指定されない場合は自動検出される |
--no-bubblewrap | Linuxのみ。インストールされていてもbubblewrapを決して使用しない。Landlockとseccompにフォールバックする。bwrapが特定のツールを壊す場合に使用する |
MISE_* |
mise |