Files
claude-howto/ja/06-hooks/dependency-check.sh
T
Luong NGUYEN b9a973bf32 docs: accuracy pass against Claude Code v2.1.220 (#155)
Internal accuracy pass against v2.1.220 — no missing upstream features, but broken example code, disagreeing counts, and metadata drift.

Functional fixes: pre-commit.sh now exits 2 so it actually blocks; dependency-check.sh reads file_path from stdin JSON instead of $1; database-mcp.json uses ${DATABASE_URL}; broken fences repaired; three command templates had invalid skill names.

Factual corrections: /fork and /subtask unswapped and /subtask added; /fewer-permission-prompts; permissions.defaultMode; dontAsk/auto unreversed; 31 hook events verified name-by-name; subagent depth 3; skill precedence enterprise > project > personal; /output-style removed not deprecated; permissionDecision gained defer.

Follow-up review fixed defects the pass left behind: zh/vi headers claiming 31 events above 25-name lists, a surviving hardcoded DB credential in the MCP README examples, an unbalanced fence swallowing a metadata footer, and non-canonical tool names. All four translated CATALOG summary tables were recounted so their arithmetic holds.

Full detail in CHANGELOG.md under v2.1.220-r2.
2026-08-04 15:41:12 +07:00

163 lines
6.4 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# マニフェストファイルが変更された後に、依存関係の既知の脆弱性をチェックする。
# フック:PostToolUsematcher: Write
#
# 対象ファイルパスは標準入力の JSON から読み取る(Claude Code フックプロトコル)。
# 出典:https://code.claude.com/docs/en/hooks
# Claude Code フックプロトコルに従い、標準入力から JSON を読み取る
INPUT=$(cat)
# sed で file_path を抽出(全プラットフォーム互換)
FILE=$(echo "$INPUT" | sed -n 's/.*"file_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
if [ -z "$FILE" ]; then
exit 0
fi
# マッチング用に basename を使う — file_path は絶対パスの可能性がある
BASENAME=$(basename "$FILE")
# 依存関係マニフェストが書き換えられた場合のみ実行
case "$BASENAME" in
package.json|package-lock.json|yarn.lock|pnpm-lock.yaml| \
requirements.txt|Pipfile|Pipfile.lock|pyproject.toml| \
go.mod|go.sum| \
Cargo.toml|Cargo.lock| \
Gemfile|Gemfile.lock| \
composer.json|composer.lock| \
pom.xml|build.gradle|build.gradle.kts)
echo "📦 依存関係マニフェストを更新: $FILE — 脆弱性をスキャンしています..."
;;
*)
exit 0
;;
esac
ISSUES_FOUND=0
# ── npm / yarn / pnpm ────────────────────────────────────────────────────────
if [[ "$BASENAME" == package*.json || "$BASENAME" == yarn.lock || "$BASENAME" == pnpm-lock.yaml ]]; then
if command -v npm &>/dev/null; then
echo "🔍 npm audit を実行中..."
if ! npm audit --audit-level=high --json 2>/dev/null | \
python3 -c "
import sys, json
data = json.load(sys.stdin)
vulns = data.get('metadata', {}).get('vulnerabilities', {})
high = vulns.get('high', 0) + vulns.get('critical', 0)
if high:
print(f' ⚠️ {high} 件の高/致命的な npm 脆弱性を検出。実行: npm audit fix')
sys.exit(1)
" 2>/dev/null; then
ISSUES_FOUND=1
else
echo " ✅ 高/致命的な npm 脆弱性なし"
fi
fi
if command -v yarn &>/dev/null && [[ "$BASENAME" == yarn.lock ]]; then
echo "🔍 yarn audit を実行中..."
if ! yarn audit --level high --json 2>/dev/null | \
grep -q '"type":"auditAdvisory"' 2>/dev/null; then
echo " ✅ 高レベルの yarn 脆弱性なし"
else
echo " ⚠️ yarn audit が脆弱性を検出。実行: yarn audit --level high"
ISSUES_FOUND=1
fi
fi
fi
# ── Python ───────────────────────────────────────────────────────────────────
if [[ "$BASENAME" == requirements.txt || "$BASENAME" == Pipfile* || "$BASENAME" == pyproject.toml ]]; then
if command -v pip-audit &>/dev/null; then
echo "🔍 pip-audit を実行中..."
if pip-audit --format=json 2>/dev/null | \
python3 -c "
import sys, json
data = json.load(sys.stdin)
vulns = [d for d in data.get('dependencies', []) if d.get('vulns')]
if vulns:
for dep in vulns:
for v in dep['vulns']:
print(f' ⚠️ {dep[\"name\"]} {dep[\"version\"]}: {v[\"id\"]} — {v[\"fix_versions\"]}')
sys.exit(1)
" 2>/dev/null; then
echo " ✅ Python の脆弱性なし"
else
ISSUES_FOUND=1
echo " 詳細は実行: pip-audit"
fi
elif command -v safety &>/dev/null; then
echo "🔍 safety check を実行中..."
OUTPUT=$(safety check --short-report 2>&1)
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
echo " ✅ Python の脆弱性なし"
elif echo "$OUTPUT" | grep -qiE "vulnerability|CVE|insecure"; then
echo "$OUTPUT"
ISSUES_FOUND=1
else
echo " ⚠️ safety check が完了できなかった(ネットワークまたは設定エラー)" >&2
fi
fi
fi
# ── Go ───────────────────────────────────────────────────────────────────────
if [[ "$BASENAME" == go.mod || "$BASENAME" == go.sum ]]; then
if command -v govulncheck &>/dev/null; then
echo "🔍 govulncheck を実行中..."
OUTPUT=$(govulncheck ./... 2>&1)
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
echo " ✅ Go の脆弱性なし"
elif echo "$OUTPUT" | grep -q "Vulnerability #"; then
echo "$OUTPUT"
ISSUES_FOUND=1
else
echo " ⚠️ govulncheck が完了できなかった: $OUTPUT" >&2
fi
fi
fi
# ── Rust ─────────────────────────────────────────────────────────────────────
if [[ "$BASENAME" == Cargo.toml || "$BASENAME" == Cargo.lock ]]; then
if command -v cargo-audit &>/dev/null; then
echo "🔍 cargo audit を実行中..."
if ! cargo audit 2>/dev/null; then
ISSUES_FOUND=1
else
echo " ✅ Rust の脆弱性なし"
fi
fi
fi
# ── Ruby ─────────────────────────────────────────────────────────────────────
if [[ "$BASENAME" == Gemfile || "$BASENAME" == Gemfile.lock ]]; then
if command -v bundler-audit &>/dev/null; then
echo "🔍 bundler-audit を実行中..."
bundler-audit check --update 2>/dev/null || ISSUES_FOUND=1
fi
fi
# ── 汎用フォールバック:trivy ───────────────────────────────────────────────
if command -v trivy &>/dev/null; then
echo "🔍 trivy fs scan を実行中..."
if ! trivy fs --exit-code 1 --severity HIGH,CRITICAL --quiet . 2>/dev/null; then
ISSUES_FOUND=1
else
echo " ✅ trivy は HIGH/CRITICAL の問題を検出せず"
fi
fi
if [ "$ISSUES_FOUND" -eq 0 ]; then
echo "✅ 依存関係チェック合格 — 脆弱性は検出されませんでした"
else
echo ""
echo "⚠️ 脆弱性が検出されました。コミット前に依存関係を確認・更新してください。"
echo " このフックは助言のみで、ワークフローをブロックしません。"
fi
# 常に exit 0 — このフックは警告のみで、ブロックしない
exit 0