scripts/ai_guard/commit_msg_hook.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
# git commit-msg hook: enforce [MANUAL-OVERRIDE] tag when protected files are staged.
#
# Why this hook (and not pre-commit):
# - pre-commit runs BEFORE prepare-commit-msg creates COMMIT_EDITMSG.
# Trying to grep the message in pre-commit always fails (file doesn't exist yet).
# - commit-msg runs AFTER prepare-commit-msg. Git passes the commit message file
# path as $1. This is the earliest point where we can read the message.
#
# Behavior:
# - If protected files are staged AND commit message lacks [MANUAL-OVERRIDE]:
# exit 1 (block commit).
# - If protected files are staged AND message has [MANUAL-OVERRIDE]: allow with warning.
# - If no protected files staged: pass through silently.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT"
. "$ROOT/scripts/ai_guard/protected_files.sh"
COMMIT_MSG_FILE="$1"
if [ -z "$COMMIT_MSG_FILE" ] || [ ! -f "$COMMIT_MSG_FILE" ]; then
echo "❌ commit-msg hook invoked without message file (arg \$1 empty or not a file)"
exit 1
fi
# Detect protected files in staged
PROTECTED_HITS=()
for pf in "${PROTECTED_FILES[@]}"; do
if git diff --cached --name-only | grep -q "^${pf}$"; then
PROTECTED_HITS+=("$pf")
fi
done
if [ "${#PROTECTED_HITS[@]}" -eq 0 ]; then
exit 0
fi
# Protected files staged — require [MANUAL-OVERRIDE] tag in message
if grep -q "\[MANUAL-OVERRIDE\]" "$COMMIT_MSG_FILE"; then
echo "⚠️ [MANUAL-OVERRIDE] detected — allowing protected file commit"
for pf in "${PROTECTED_HITS[@]}"; do
echo " ✓ $pf"
done
exit 0
fi
# Block + list protected files with explanation
echo "❌ BLOCKED: 受保护文件被修改 without [MANUAL-OVERRIDE]:"
for pf in "${PROTECTED_HITS[@]}"; do
echo " - $pf"
done
echo ""
echo "如需人工覆盖,请在 commit message 中添加 [MANUAL-OVERRIDE] 标记。"
echo "或使用 --no-verify 跳过所有 hooks(紧急情况 / 真有 rationale)。"
exit 1