guanghu-ice-heart/modules/guanghu-panel-kit/hooks/pre-receive-review.template

95 lines
3.7 KiB
Text
Raw Normal View History

#!/bin/bash
# mm-review · maomao-fifth-domain pre-receive 自动审核 · 铸渊 2026-08-06
# ⊢ 明文密钥必拦 ⊢ 破坏现有必拦 ⊢ 写入窗口必验 ⊢ 每次写入留痕
LOG_DIR=/srv/guanghu/mm-gz-001/access/logs
GRANTS=/srv/guanghu/mm-gz-001/access/grants.json
PUSHER="${GITEA_PUSHER_NAME:-unknown}"
VERDICT=PASS
REASONS=()
COMMITS=0
REFSLIST=""
PUSHER_ATTR=""
ZERO=0000000000000000000000000000000000000000
mkdir -p "$LOG_DIR"
active_grant() {
python3 - "$GRANTS" <<'PY'
import json,sys,datetime
try: g=json.load(open(sys.argv[1]))
except Exception: print("none"); sys.exit()
now=datetime.datetime.now(datetime.timezone.utc)
for x in g:
if x.get("status")=="active":
try: exp=datetime.datetime.fromisoformat(x["expiresAt"])
except Exception: continue
if exp>now: print(x.get("persona","persona")); sys.exit()
print("none")
PY
}
while read -r old new ref; do
REFSLIST="$REFSLIST $ref"
branch=${ref#refs/heads/}
if [ "$new" = "$ZERO" ]; then
case "$branch" in
guanghu/main|deploy) VERDICT=REJECT; REASONS+=("禁止删除受保护分支: $branch");;
esac
continue
fi
if [ "$PUSHER" = "mm-writer" ]; then
W=$(active_grant)
if [ "$W" = "none" ]; then
VERDICT=REJECT
REASONS+=("无有效写入窗口3小时授权已过期或未申请。人格体请先 POST https://maomao.guanghulab.com/api/access-request 申请,等苍耳审批")
continue
fi
PUSHER_ATTR="$W"
fi
if [ "$old" != "$ZERO" ]; then
if ! git merge-base --is-ancestor "$old" "$new" 2>/dev/null; then
VERDICT=REJECT; REASONS+=("禁止历史重写(非快进推送): $branch")
continue
fi
fi
for c in $(git rev-list "$old".."$new" 2>/dev/null || git rev-list -n 20 "$new" 2>/dev/null); do
COMMITS=$((COMMITS+1))
for f in $(git diff-tree --root --no-commit-id --name-only --diff-filter=AM -r "$c" 2>/dev/null | head -60); do
if git show "$c:$f" 2>/dev/null | head -c 400000 | grep -qE "sk-[A-Za-z0-9]{16,}|AKIA[A-Z0-9]{16}|-----BEGIN [A-Z ]*PRIVATE KEY-----|gh[pousr]_[A-Za-z0-9]{20,}|xox[baprs]-[A-Za-z0-9-]{10,}|(api[_-]?key|apikey|secret[_-]?key|access[_-]?token|password|passwd)[\"']?[[:space:]]*[:=][[:space:]]*[\"'][A-Za-z0-9+/=_.-]{12,}"; then
VERDICT=REJECT; REASONS+=("文件疑似包含明文密钥: $f提交 ${c:0:8})。密钥必须移出仓库")
fi
done
if [ "$PUSHER" != "maomao" ]; then
for f in $(git diff-tree --root --no-commit-id --name-only --diff-filter=D -r "$c" 2>/dev/null); do
case "$f" in
REPO-MAP.hdlp|GLW-ENTRY.hdlp|INDEX.hdlp|README.md|AGENTS.md|guanghu-nodes/MM-GZ-001/machine/NAVIGATION.json|guanghu-nodes/MM-GZ-001/recovery/WAKE-UP-ROUTE.json|guanghu-nodes/MM-GZ-001/personas/registry.json)
VERDICT=REJECT; REASONS+=("人格体不得删除入口文件: $f");;
esac
done
fi
done
done
python3 - "$LOG_DIR" "$PUSHER" "$PUSHER_ATTR" "$VERDICT" "$COMMITS" "$REFSLIST" "$(printf '%s|' "${REASONS[@]}")" <<'PY'
import json,sys,datetime,os
logdir,pusher,attr,verdict,commits,refs,reasons=sys.argv[1:8]
rec={"ts":datetime.datetime.now(datetime.timezone.utc).isoformat(),
"pusher":pusher,"persona":attr or None,"verdict":verdict,
"commits":int(commits),"refs":refs.split(),
"reasons":[r for r in reasons.split("|") if r]}
os.makedirs(logdir,exist_ok=True)
p=os.path.join(logdir,"PUSH-%s.json"%datetime.datetime.now().strftime("%Y%m%dT%H%M%S%f"))
open(p,"w").write(json.dumps(rec,ensure_ascii=False,indent=1))
PY
if [ "$VERDICT" = "REJECT" ]; then
echo "── 守望自动审核REJECT ──"
for r in "${REASONS[@]}"; do echo " ✗ $r"; done
exit 1
fi
echo "── 守望自动审核PASS$COMMITS 提交 · 推送者 $PUSHER${PUSHER_ATTR:+ · 人格 $PUSHER_ATTR})──"
exit 0