- Translate all 101 markdown files: P1 core, all 10 modules, examples, auxiliary docs (CONTRIBUTING, CODE_OF_CONDUCT, SECURITY, CLAUDE.md, etc.), peripheral docs (.github/, docs/, resources/, scripts/) - Translate comments and user-facing messages in 06-hooks/*.sh examples - Copy 05-mcp/*.json examples (standard JSON, no comments) - Update root README.md language switcher to include 日本語 - Add ja/TRANSLATION_NOTES.md (glossary + style guide) All translations pass pre-commit quality gates (markdown-lint, cross-references, mermaid-syntax, link-check, build-epub).
129 lines
5.5 KiB
Bash
129 lines
5.5 KiB
Bash
#!/bin/bash
|
||
# Bash コマンドの事前安全チェック
|
||
# フック:PreToolUse(matcher: Bash)
|
||
#
|
||
# このフックは Bash ツールが実行されるたびに走り、破壊的またはハイリスクなシェル
|
||
# コマンドをブロック/警告する。
|
||
#
|
||
# セットアップ:
|
||
# cp 06-hooks/pre-tool-check.sh ~/.claude/hooks/
|
||
# chmod +x ~/.claude/hooks/pre-tool-check.sh
|
||
#
|
||
# ~/.claude/settings.json の設定例:
|
||
# {
|
||
# "hooks": {
|
||
# "PreToolUse": [
|
||
# {
|
||
# "matcher": "Bash",
|
||
# "hooks": [
|
||
# {
|
||
# "type": "command",
|
||
# "command": "~/.claude/hooks/pre-tool-check.sh"
|
||
# }
|
||
# ]
|
||
# }
|
||
# ]
|
||
# }
|
||
# }
|
||
#
|
||
# 入力:以下の形式の JSON を標準入力から受け取る:
|
||
# { "tool_name": "Bash", "tool_input": { "command": "..." } }
|
||
#
|
||
# 出力規約(Claude Code フックプロトコルに準拠):
|
||
# - exit 0 → 許可。stdout には JSON(hookSpecificOutput)を出力可能。stderr は
|
||
# 黙って捨てられるため、stderr への警告出力は表示されない。許可された
|
||
# コマンドの可観測性を担保するには、監査ログファイルに書き出す。
|
||
# - exit 2 → ブロック。stderr が Claude にブロック理由として返される。
|
||
# ブロック理由を説明する echo は必ず `>&2` で stderr にリダイレクトする。
|
||
# さもないと Claude Code は「No stderr output」と報告する。
|
||
#
|
||
# 監査ログ:すべての呼び出しを以下に記録する
|
||
# $CLAUDE_PROJECT_DIR/.claude/hooks/audit.log
|
||
# 判定(BLOCK/WARN/ALLOW)と一緒に保存するため、stderr が Claude Code に捨てられる
|
||
# WARN 階層のマッチも観測できる。
|
||
|
||
# 標準入力から JSON 全体を読み取る
|
||
INPUT=$(cat)
|
||
|
||
# 移植性のある sed でコマンドを抽出(macOS / Linux 双方互換)
|
||
COMMAND=$(echo "$INPUT" | sed -n 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
||
|
||
# 抽出に失敗した場合は生の入力にフォールバック
|
||
if [ -z "$COMMAND" ]; then
|
||
COMMAND="$INPUT"
|
||
fi
|
||
|
||
# ── 監査ログ ─────────────────────────────────────────────────────────────────
|
||
# すべての呼び出しを最終判定とともに記録する。Claude Code は exit 0 のときに
|
||
# stderr を黙って捨てるため、WARN 階層を確実に観測できる唯一の手段がこれ。
|
||
# Claude Code 外(ローカルテスト等)では $(pwd) にフォールバックする。
|
||
LOG_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}/.claude/hooks"
|
||
LOG_FILE="$LOG_DIR/audit.log"
|
||
mkdir -p "$LOG_DIR" 2>/dev/null
|
||
log_decision() {
|
||
echo "$(date -u +%FT%TZ) [$1] $COMMAND" >> "$LOG_FILE"
|
||
}
|
||
|
||
# ── ブロックパターン ─────────────────────────────────────────────────────────
|
||
# 自動化された文脈ではほぼ確実に破壊的かつ意図的でないため、無条件にブロックする。
|
||
|
||
BLOCKED_PATTERNS=(
|
||
# `rm -rf /` を厳密に判定するため、`/` の後に空白か行末を要求する。
|
||
# 部分一致だと `rm -rf /tmp/foo` のような正当ケースを誤検出してしまう。
|
||
"rm -rf /([[:space:]]|$)"
|
||
"rm -rf \*"
|
||
"dd if=/dev/zero"
|
||
"dd if=/dev/random"
|
||
":\(\)\{:\|:&\};:" # フォーク爆弾(正規表現メタ文字をエスケープ)
|
||
"mkfs\." # ファイルシステムのフォーマット
|
||
"format c:" # Windows のディスクフォーマット
|
||
)
|
||
|
||
for pattern in "${BLOCKED_PATTERNS[@]}"; do
|
||
if echo "$COMMAND" | grep -qE "$pattern"; then
|
||
log_decision "BLOCK:$pattern"
|
||
# ここの echo は必ず stderr へ — Claude Code は exit 2 のとき stderr を
|
||
# ブロック理由として表面化する。stdout に書くと「No stderr output」と表示される。
|
||
echo "❌ ブロック:破壊的な可能性のあるコマンドを検出: $pattern" >&2
|
||
echo " コマンド: $COMMAND" >&2
|
||
exit 2
|
||
fi
|
||
done
|
||
|
||
# ── 警告パターン ─────────────────────────────────────────────────────────────
|
||
# リスクは高いが意図的な場合もある。警告を記録して許可する。
|
||
|
||
WARNING_PATTERNS=(
|
||
"rm -rf"
|
||
"git push --force"
|
||
"git reset --hard"
|
||
"git clean -f"
|
||
"chmod -R 777"
|
||
"sudo rm"
|
||
"DROP TABLE"
|
||
"DROP DATABASE"
|
||
"truncate"
|
||
)
|
||
|
||
MATCHED_WARNINGS=""
|
||
for pattern in "${WARNING_PATTERNS[@]}"; do
|
||
if echo "$COMMAND" | grep -qi "$pattern"; then
|
||
MATCHED_WARNINGS="${MATCHED_WARNINGS:+$MATCHED_WARNINGS,}$pattern"
|
||
# フックを手動実行する人間向けに stderr へも警告を出す。
|
||
# Claude Code は exit 0 のときこれを捨てるため、確実な記録は監査ログ
|
||
# (WARN エントリ)参照のこと。
|
||
echo "⚠️ 警告:ハイリスクな操作を検出: $pattern" >&2
|
||
fi
|
||
done
|
||
|
||
if [ -n "$MATCHED_WARNINGS" ]; then
|
||
log_decision "WARN:$MATCHED_WARNINGS"
|
||
echo " コマンド: $COMMAND" >&2
|
||
echo " 続行します — 上記の警告を確認してから続けてください。" >&2
|
||
else
|
||
log_decision "ALLOW"
|
||
fi
|
||
|
||
# ── 許可 ────────────────────────────────────────────────────────────────────
|
||
exit 0
|