AI仕事術

自分のhooksを数えたら26個、止める役目は2つだけ。壊れた入力を流したら番人は素通しだった

自分のhooksを数えたら26個、止める役目は2つだけ。壊れた入力を流したら番人は素通しだった

自分のClaude Codeに入れている「危ないコマンドを止める番人」に、壊れた入力を3通り流してみたら、3通りのうち2通りで素通しだった。番人を作った本人の環境でも、止める仕組みが「止められなかったとき」にどう動くかは決めていなかった。

きっかけは10月のhooks関連の更新だった

10月14〜23日の更新で、hooksが「失敗したときに通すか止めるか」の扱いが何度か直されていた。

公式の変更履歴(changelog)を読むと、hooks(ツールを使う前後に自動で走る小さなプログラム)まわりで次の記載があった。

  • v2.1.299(10月14日):プラグインのhookが止める役目を持つ場面で、hookに渡せない・応答が返らないときは「通す」でなく拒否になった
  • v2.1.309(10月22日):PowerShell上のhookが終了コード2で終わっても止まらない問題を修正
  • v2.1.310(10月23日):WindowsでGit Bashが無いとき、PreToolUse(ツール実行前に走るhook)がツール呼び出しを通してしまう問題を修正

在庫に入れていた「v2.1.295でhooksが失敗したら動作をブロックできるように」という情報は、今回読めた範囲のchangelogでは確認できなかった(295〜298の記載は読めていない)。この記事では確認できた3件だけを使う。

共通しているのは、「止める仕組みが壊れたとき、通すのか止めるのか」が、ツール側でも繰り返し直されている点だった。自分のhooksはどうなっているか、気になって調べた。

自分のhooksを数えたら26個、止められるのは2つだけだった

settings.jsonに26個のhookが入っていたが、実際に「止める」役目を持つのは2つだけだった。

settings.json(Claude Codeの設定ファイル)を開いて数えた結果は次のとおり。

  • hookの総数:26個(15種類のタイミングに分散)
  • 通知アプリへの連絡用:大半。末尾が「終了コード0で抜ける」書き方で、失敗しても必ず「通す」作りにしてある
  • 止める役目:2つ(Bashコマンドの番人 bash-guard.sh と、返答の最後にリンク切れを調べる link-check.py)

通知用が「必ず通す」なのは意図どおりで、通知が失敗して作業が止まっては困る。問題は、止める役目の2つが壊れたときにも通す作りになっていないかだった。

fail open と fail closed

fail openは「番人が壊れたら通す」、fail closedは「番人が壊れたら止める」。通知は前者、危険コマンドの番人は後者が向いている。

番人に壊れた入力を流したら、3通り中2通りが素通しだった

正常な入力では止まったが、壊れたJSONと、jqという部品が見つからない状態では、どちらも終了コード0(通す)を返した。

bash-guard.shは、Claude Codeから受け取ったJSONをjq(JSONから値を取り出すコマンド)で読み、コマンド文字列を取り出して危険な書き方に当たらないか調べる。取り出せなかったときの行は 「コマンド文字列が空なら終了コード0で抜ける」という1行 で、つまり「読めなければ通す」。危険な強制プッシュを模した文字列で試した。

  • 正常な入力+危険コマンド:終了コード2(ブロック)
  • 正常な入力+無害なコマンド(ls):終了コード0(通す)
  • 壊れたJSON+危険コマンド:終了コード0(素通し)
  • jqの場所を存在しないパスに差し替え+危険コマンド:終了コード0(素通し)

番人は「読めた入力」には強かった。一方で「読めなかった入力」は丸ごと通していた。macOSに入っているjqに頼っているので、更新で場所が変わった日に番人は黙って役目を終える。

ちなみに最初のテストは、番人自身に止められた。テスト用のコマンド文字列に危険な書き方をそのまま入れたため、実行前に番人が反応した。正常なときの番人は、ちゃんと働いている。

今回は動作確認だけで、bash-guard.shは書き換えていない。直すと、jqが入っていない環境でも作業が全部止まる副作用がある。止めるのか通すのかは、このあと決める。

今日からできること:番人の「壊れたとき」を一度だけ試す

自分の止める役目のhookに、壊れた入力を1回流して、終了コードを見るだけでいい。

止める役目のhookを入れている人は、Claude Codeに次のように頼むと、手順を代わりに実行してくれる。

settings.json の hooks のうち、ツールの実行を止める役目のもの(PreToolUse、PermissionRequest、UserPromptSubmit、Stop)を一覧にして。それぞれについて、①壊れたJSONを渡した場合 ②中で使っているコマンド(jqなど)が見つからない場合に、終了コードが0(通す)か2(止める)かを実際に流して確認し、表にして。ファイルの書き換えはしないで。

表を見て、「通す」になっていた行が危険コマンドの番人なら、そこだけ直す候補になる。通知用なら、そのままでいい。