claude plugin evalがDocker入りMacでBash付き実行を拒否する原因と対処
Docker Desktopを入れたMacで、claude plugin evalがBashを許可した実行だけを費用0で拒否する問題の原因と、v2.1.293での修正、更新できないときの回避策をまとめます。
Docker Desktopを入れたMacでclaude plugin evalに--allow-tools Bashを付けると、モデルを一度も呼ばずに終了することがあります。原因は~/.dockerの中にシンボリックリンクがあることです。この拒否はClaude Code v2.1.293で修正されました。更新できない環境向けの回避策は、後半で扱います。
症状: 費用0・約1秒で終わり、Editだけなら通る
GitHub issueの報告では、次のコマンドが実行前に終了しました。環境はClaude Code 2.1.270、macOS、Docker Desktopの標準構成です。同じ機械にはColimaも入っていましたが、報告はDocker Desktopのリンクを原因として挙げています。
claude plugin eval <プラグインのディレクトリ> --case <ケース名> \
--runs 1 --ablation none \
--allow-tools Bash Edit Write \
--scaffold --trust-plugin --no-publish --json out.json--scaffoldはケースのセットアップ用スクリプトを実行する指定で、--trust-pluginは初回の信頼確認を省く指定です。どちらも拒否の原因ではなく、自分や自組織が書いたスイートでのみ付けるフラグです。拒否はBashの許可そのものに反応しています。
結果のerror欄には、次の文が入っていました。
the Docker (~/.docker, DOCKER_CONFIG) credential store on this machine holds a
symbolic link inside it, so the Bash sandbox cannot reliably exclude it — a
Bash-granting evaluation cannot run here; keep the store's contents in one
plain directory (its root may be a link)特徴は3つあります。
- 費用は0、所要時間は1秒ほどで、モデル呼び出しの前に止まる
- 同じケースを
--allow-tools Edit Writeだけにすると通る - Bashを許可する実行は、ケースの中身に関係なくすべて止まる
つまり、プラグインやケースの書き方の問題ではありません。Bashを許可した実行の事前チェックで弾かれています。
なぜDocker Desktopだと必ず当たるのか
claude plugin evalはBashを許可すると、すべてのコマンドをOSレベルのサンドボックスの中で動かします。サンドボックスでは、実行ごとのワークスペース以外への書き込みが禁じられ、ホームディレクトリとClaude Codeの設定は読めなくなります。この前提はプラグインevalの使い方や、サンドボックスの設計の記事にある通常のサンドボックスと同じ考え方です。
問題は、読ませたくない場所の1つにDockerの認証情報ストアが含まれる点です。エラー文のとおり、ストアの中にシンボリックリンクがあると、サンドボックスは中身を確実に除外できません。そこでevalは実行そのものを断ります。
一方でDocker Desktop for Macは、~/.dockerの中にリンクを大量に作ります。issueの報告者が挙げた内訳は次のとおりです。
| 場所 | 中身 |
|---|---|
~/.docker/cli-plugins/docker-* | 中身/Applications/Docker.app内のプラグイン(buildx、compose、scout、sbomなど)へのリンク |
~/.docker/bin/ | 中身docker、docker-compose、kubectl、docker-credential-desktopなどへのリンク |
~/.docker/bin/lib/*.dylib | 中身Docker Model Runner用のバージョン別名のリンク |
認証情報そのもの(config.json、credsStore: desktop)にはリンクがなく、リンクを持つのは周辺のディレクトリだけです。しかもDocker Desktopが管理しているため、リンクを消しても再生成されます。標準の構成で入れた人は誰でも該当します。
バージョンごとの経緯: cli-pluginsからbinへ、そしてv2.1.293で修正
issueには、拒否される対象がバージョンごとに変わった様子が残っています。
拒否の対象とその修正
- v2.1.268〜270cli-pluginsのリンクで拒否
最初の報告です。
~/.docker/cli-pluginsの16個ほどのリンクが原因でした。 - v2.1.280残るのは~/.docker/binだけ
別の報告者が確認した状態です。
cli-pluginsでは止まらなくなり、~/.docker/binの22個のリンクだけが拒否の引き金でした。 - v2.1.293修正
changelogに「Docker Desktopが入ったMacで、
~/.docker/bin配下のリンクのせいでevalがBashを許可する実行をすべて拒否する問題を修正」と載りました。あわせて、拒否メッセージがストアのどの部分にリンクがあったかを示すようになりました。
v2.1.280での調査では、チェックが認証情報ストアを歩き、名前ごとの除外リストに載っていない場所でリンクを見つけたら拒否する仕組みだと推測されています。Dockerの除外リストにはcli-plugins、buildx、desktop、mutagen、scan、run、features.json、daemon.json、desktop-buildが入っていたという読みです。これは実行ファイルの中身を読んだ推測で、報告者自身も「確実ではない」と断っています。binが除外リストに無かったことが、v2.1.280でも止まっていた説明になります。
v2.1.293の詳細はv2.1.293のリリースノートにあります。issueにはv2.1.293以降での再確認の報告がなく、修正後に完全に通るかは、手元の環境で試して確かめることになります。
まず切り分ける: 自分の環境が該当するか
当てはまるのは、エラー文にDocker (~/.docker, DOCKER_CONFIG)が出る場合です。次の2つで状況を見ます。
claude --version
find ~/.docker -type l | wc -l1行目で2.1.293未満なら、修正前の版です。2行目は~/.dockerの中のリンクの数で、0以外なら拒否の候補になります。どこにあるかを見るには、先頭の階層ごとに数えます。
find ~/.docker -type l | awk -F/ '{print $5}' | sort | uniq -c$5は/Users/<名前>/.docker/<ここ>の位置を指します。ホームの深さが違う環境では番号を調整してください。出力には、リンクを抱えている先頭ディレクトリ(binやcli-pluginsなど)が並びます。
v2.1.280で調べた報告者の環境では、リンクは全部で37本ありました。内訳は~/.docker/binに22本、残る15本は除外リストにあるとされるフォルダの中です。合計が多くても、拒否の引き金になるのは除外されない場所にあるリンクだけという読みです。したがって数が0でない場合は、binのように除外リスト外のフォルダにあるかを見てください。ただしこの除外リストは実行ファイルを読んだ推測なので、フォルダ名で原因を断定せず、最終的には対処1の更新後の動きで確かめるのが確実です。
対処1: Claude Codeを更新する
v2.1.293以降なら、~/.docker/binのリンクでは止まらないはずです。更新後に同じコマンドで再実行します。
claude update
claude plugin eval . --allow-tools "Bash(npm test *)"それでも拒否される場合、メッセージが「認証情報ストアのどの部分にリンクがあったか」を示すので、その部分を見て原因を絞れます。
対処2: 更新できないときの回避策
Bashを外し、EditとWriteだけで回す
issueの報告では、同じケースが--allow-tools Edit Writeなら通りました。ケースがシェル実行を必要としないなら、これが最も副作用の少ない選択肢です。Bashが要るケース(ビルドやテストの実行を確かめるもの)は、この方法では測れません。
~/.docker/binを一時的に外へ移す
v2.1.280の報告では、~/.docker/binを~/.dockerの外に移すとBash付きの実行が完走し、3回の実行すべてが1.0で採点されました。移動先は~/.dockerの外でなければなりません。
mv ~/.docker/bin ~/docker-bin-parked
claude plugin eval . --allow-tools "Bash(python3 *)"
mv ~/docker-bin-parked ~/.docker/binDocker Desktopはこのフォルダにツールのリンクを置いているため、移している間はdockerコマンドが使えなくなる場合があります。実行が終わったらすぐ戻してください。この手順は一時的なものです。
効かなかった方法
issueには、試して失敗した方法も書かれています。時間を使う前に避けられます。
| 試したこと | 結果 |
|---|---|
DOCKER_CONFIGを空の通常ディレクトリにする | 結果同じ拒否。チェックは~/.dockerを読み続ける |
~/.docker/binをbin.offにリネーム(~/.docker内) | 結果拒否のまま。除外リストにない名前でリンクが残るため |
HOMEを空ディレクトリにしてCLAUDE_CONFIG_DIR=~/.claudeを指す | 結果事前チェックは通るが、認証が401(OAuthトークン期限切れ)で失敗し、設定ディレクトリに余計な.claude.jsonができる |
| Dockerのリンクを消す | 結果Docker Desktopが再作成するため長続きしない |
通常のサンドボックスは止まらない
issueの報告者は、同じ機械で通常のClaude Codeのサンドボックス(sandbox.enabledとdenyReadルール)は問題なく動いたと書いています。この結果を踏まえ、報告者はevalの事前チェックのほうがサンドボックス本体より厳しい、と指摘しています。つまり、同じ機械でも普段の開発は止まらないのにevalだけが止まる、という食い違いが起きます。拒否はevalの事前チェックに固有で、普段の開発でBashがサンドボックスに入らなくなるわけではありません。書き込み範囲の調整はsandbox-runtimeの起動設定にまとめています。
Docker以外でBash付きevalが拒否されるケースとの見分け方
「Bashを許可すると実行が止まる」という症状は、Docker以外の原因でも起こります。プラグインevalの要件には、次のような別の止まり方が書かれています。
| 手がかり | 原因 | 対処 |
|---|---|---|
エラー文にDocker (~/.docker, DOCKER_CONFIG)とシンボリックリンクの話が出る | 原因~/.docker内のリンク | 対処前半の対処1・2 |
| BashやPowerShellを許可した実行が、実行エラーとなりスコア0になる | 原因その環境にサンドボックスのバックエンドがない | 対処下記のとおり環境を整える |
| ネイティブWindowsでシェルを許可する | 原因Windowsにはバックエンドがない | 対処WSL2の中で実行する |
| Linuxでシェルを許可する | 原因bubblewrapとsocatが未導入 | 対処2つを先にインストールする |
| Bashを許可しなくても、どのケースも実行前に止まる | 原因gitが2.31より古い | 対処git --versionで確認して更新する |
端末でない環境や--json付きの実行が、終了コード1で拒否される | 原因初回の信頼確認に答えられない | 対処自分で動かすプラグインに限り--trust-pluginを付ける |
claude plugin eval自体が使えない | 原因Claude Codeがv2.1.269より古い | 対処claude updateで更新する |
バックエンドがない環境では、サンドボックスなしで動かすことはせず、実行ごとに断る仕組みになっています。Dockerの場合は、エラー文がDockerの認証情報ストアを名指しし、Editだけの実行は通る点が決め手です。gitの古さは、Bashの有無に関係なく全ケースを止めます。
確認の順は、まずclaude --versionとgit --version、次にエラー文にDockerの名前があるか、最後に実行する環境のOSです。Macで~/.dockerのリンクが0本なら、Dockerは原因から外れます。Linuxなら、bubblewrapとsocatが入っているかを見ます。
issueの報告者が望んだ挙動
報告者は、直し方の候補を3つ挙げています。リンクを解決してから拒否ルールを作る、~/.docker全体ではなくconfig.jsonと認証ヘルパーのパスだけを拒否する、Docker Desktopが上書きしない構成を文書化する、の3つです。v2.1.293の実際の修正内容は、changelogの1文以上は公表されていません。
判断の目安
- v2.1.293以上: 更新後に再実行する。拒否が出れば、メッセージのリンク位置を手がかりにする
- 更新できず、Bashが不要:
--allow-tools Edit Writeで回す - 更新できず、Bashが必要:
~/.docker/binを一時的に~/.dockerの外へ移して実行し、終わったら戻す