Claude Codeの安全設計、Pythonスクリプト3本を捨ててdeny rulesに一本化した判断
「設定が3箇所に散らばっている」問題
Claude Codeで安全設計を組んでいると、こんな状態になりがちだ。
-
settings.jsonのdenyリストに静的パターンを追加 - PreToolUse Hookに動的チェック用のPythonスクリプトを登録
- auto-approve用のスクリプトで安全なコマンドの承認ダイアログをスキップ
自分の環境では、protect-branches.py(refspec解析で保護ブランチへのpushをブロック)、auto-approve-git-safe.py(安全なgitコマンドの自動承認)、auto-approve-gh-mcp.py(gh MCPツールの安全判定)の3本、合計200行超のPythonスクリプトがPreToolUseに登録されていた。
事故はゼロ。ちゃんと動いていた。でも、新しい保護パターンを追加するたびに「denyリストに追加すればいいのか、Pythonにも手を入れるべきか」を毎回判断する必要があり、設定の一覧性が悪い。
deny rulesのワイルドカードで十分だった
結論として、3本のPythonスクリプトを全削除し、permissions.denyのワイルドカードパターンだけで安全設計を完結させた。
たとえばprotect-branches.pyが80行かけてやっていたrefspec解析は、これで代替できる。
"Bash(git push *:main)",
"Bash(git push *:master)",
"Bash(git push *:dev)",
"Bash(git push *:refs/heads/main)",
"Bash(git push *:refs/heads/dev)"
*:mainのワイルドカードが「任意のローカルブランチからmainにpushする」パターンを全てキャッチする。git push feature:mainもgit push +HEAD:refs/heads/mainも引っかかる。
force pushも同様に網羅できる。
"Bash(git push --force:*)",
"Bash(git push -f:*)",
"Bash(git push --force-with-lease origin HEAD:refs/heads/main)"
なぜこれで十分と判断したか
Pythonスクリプトには「コマンド文字列を動的に解析して判定する」柔軟性があるが、実際に運用してみると、ブロックしたいパターンはほぼ全て文字列のパターンマッチで表現できるものだった。
| 方法 | メリット | デメリット |
|---|---|---|
| deny rulesワイルドカード | 設定1ファイル完結、メンテ容易、依存なし | 動的な判定は不可能 |
| PreToolUse + Python | 動的解析可能、外部API連携可能 | 設定分散、Python依存、デバッグ箇所が増える |
判断の分岐点は「外部APIの呼び出しやランタイム情報が必要かどうか」。パターンマッチで済む操作のブロックにPythonを使うのは、オーバーエンジニアリングだった。
auto-approveスクリプトも不要になった理由
permissions.allowに"Bash"を含めると、Bashコマンドはデフォルトで許可される。危険なコマンドだけpermissions.denyでブロックすればいい。
"permissions": {
"allow": ["Bash", "Read", "Write", "Edit", "MultiEdit", ...],
"deny": ["... 危険なパターンだけを列挙 ..."]
}
「denyが常にallowより優先される」という仕様を活かして、allowは広く取り、denyで穴を塞ぐ。この設計なら、auto-approve用Hookの出番はない。
Hooksを全廃したわけではない
PreToolUseの3スクリプトは消したが、Hooks自体は使い続けている。
- SessionStart: コンテキスト圧縮後のリマインダー、ゾンビプロセス自動kill
- PostToolUse: メモリ使用量モニタリング
「ブロック/許可」はdeny rules、「通知/監視/初期化」はHooks。守備範囲が違う。deny rulesで「イベント通知」はできないし、Hooksで「静的パターンのブロック」をやるのは冗長。
まとめ: 自分はこう判断している
安全設計で迷ったら、まずdeny rulesのワイルドカードで表現できないかを考える。パターンマッチで済むなら、Pythonスクリプトを書く必要はない。
Hooksが必要になるのは「外部API呼び出し」「ランタイム情報に基づく判定」「イベント通知・監視」の3パターンだけ。それ以外のブロック処理をHooksに書いているなら、deny rulesへの移行を検討する価値がある。
元記事
この記事は 【Claude Code 安全設計】HooksからPermissionsへ — 3つのPythonスクリプトを捨てた理由と移行ガイド のコア部分を再構成したものです。元記事ではさらに:
- Before/After の設定差分と実際のコミット履歴(段階的移行の4コミット)
- 移行判断フローチャートとチェックリスト
- force push・ブランチ削除など全deny rulesパターンの網羅的な解説
を扱っています。
この記事は playpark Blog からの転載です。
Discussion