dda4852938
在此之前 36 支閘裡只有 2 支會記錄自己擋了什麼,六種逃生口 (NOT_MY_BRANCH_OK=1/no-ticket-needed/wiki-secret-ok/credential-ok/ solo-ok/kbdb-down)用了完全不留痕 ⇒ 擋對 100 次跟擋錯 100 次在資料上 一模一樣 ⇒ 規則只會累積不會被淘汰。 機制:hooks/lib/gate-log-wrap.sh 包在每一支閘外面(hooks.json 的 82 條 gate command 全部前綴這支 wrapper;2 條 scripts/ refresher 不是閘、不包)。 它從不 exit 2,只把真正那支閘的離開碼原樣傳出去 ⇒ 記錄壞掉最多漏記一筆, 不可能誤攔(票紅線:寧可漏記,不可擋錯)。每次留一筆中繼資料: 哪支閘/何時/對什麼工具/判成什麼/(若繞過)用了哪個逃生口。 - 只記中繼資料,完全不寫入指令原文或 payload ⇒ 金鑰在結構上進不了帳本(D36) - 純 POSIX shell 記錄,不另起 python ⇒ 不讓閘變慢變脆 - 紀錄長在既有閘動作上,零輪詢/零 cron(D20) - 帳本沿用 milestone-account 慣例(不寫進會被 plugin update 換掉的目錄) 報告:scripts/gate-report all 回答票上三題(誤擋嫌疑排序/最近沒擋過的規則/ 同一 session 反覆撞同一支閘)。基線與反面驗證見票留言。 測試:hooks/tests/gate-log.test.sh 22 條(透明/留痕/反面驗證/不變脆/不外洩) + scripts/test-gate-report.sh 8 條(三題數字對不對)。 hooks 檔數 61、hooks.json 註冊 84 均不變(wrapper 住 hooks/lib,非 gate .sh)。 版本:待總管定版(改了會被載入的東西需升版才傳得到,但 tag 由總管打)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TNfNypeDaCVEZQW1Wqwfxq
67 lines
4.0 KiB
Bash
Executable File
67 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# scripts/gate-report 的迴歸測試(inkstone/InkStoneCo#48 驗收 #2)
|
||
#
|
||
# 用一份寫死的 fixture 帳本,驗這三題「查得出來、答得對」,不是憑印象:
|
||
# Q1 哪支閘擋最多?其中多少被繞過?
|
||
# Q2 哪條規則最近 N 天一次都沒擋過?
|
||
# Q3 同一個 session 反覆撞同一支閘幾次?
|
||
# 🔴 出路要真的走得通(mistakes.md #158):這裡不驗「有沒有印字」,
|
||
# 驗「印出來的數字對不對」。
|
||
set -u
|
||
REPORT="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/gate-report}"
|
||
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
|
||
LED="$TMP/gate-log.jsonl"
|
||
PASS=0; FAIL=0; N=0
|
||
ok() { N=$((N+1)); printf ' ✅ %s\n' "$1"; PASS=$((PASS+1)); }
|
||
bad() { N=$((N+1)); printf ' ❌ %s\n' "$1"; FAIL=$((FAIL+1)); shift; for l in "$@"; do printf ' %s\n' "$l"; done; }
|
||
|
||
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||
OLD=$(python3 -c "import datetime as d;print((d.datetime.now(d.timezone.utc)-d.timedelta(days=30)).strftime('%Y-%m-%dT%H:%M:%SZ'))")
|
||
row() { printf '{"ts":"%s","gate":"%s","event":"PreToolUse","tool":"Bash","verdict":"%s","bypass":"%s","sid":"%s","child":%s}\n' \
|
||
"$1" "$2" "$3" "$4" "$5" "${6:-0}" >> "$LED"; }
|
||
|
||
# gateA:擋 3 次、繞過 2 次(誤擋嫌疑最高);session sA 撞它 3 次
|
||
row "$NOW" gateA block "" sA 0
|
||
row "$NOW" gateA block "" sA 0
|
||
row "$NOW" gateA block "" sA 0 # sA 撞 gateA 共 3 次(Q3)
|
||
row "$NOW" gateA bypass NOT_MY_BRANCH_OK sB 1
|
||
row "$NOW" gateA bypass NOT_MY_BRANCH_OK sB 1
|
||
# gateB:擋 1 次
|
||
row "$NOW" gateB block "" sC 0
|
||
# gateC:最近只有放行,從沒擋過(Q2 該點名)
|
||
row "$NOW" gateC pass "" sC 0
|
||
row "$NOW" gateC pass "" sD 0
|
||
# gateD:只有 30 天前擋過,最近 7 天沒擋(Q2 該點名)
|
||
row "$OLD" gateD block "" sE 0
|
||
|
||
echo "── Q1:擋最多的是 gateA,且看得出被繞過 2 次 ────────────────"
|
||
Q1=$(ISEP_GATE_LOG="$LED" "$REPORT" q1 2>&1)
|
||
FIRST=$(printf '%s' "$Q1" | grep -E '^\s+gate[A-Z]' | head -n1)
|
||
case "$FIRST" in *gateA*) ok "① 誤擋嫌疑排序第一名是 gateA" ;; *) bad "① 排序第一名不是 gateA" "$Q1" ;; esac
|
||
# gateA 那行:擋下 3、被繞過 2、本要擋 5
|
||
if printf '%s' "$Q1" | grep -E 'gateA' | grep -qE '\b3\b.*\b2\b.*\b5\b'; then
|
||
ok "② gateA 的數字對:擋下3 / 被繞過2 / 本要擋5"
|
||
else bad "② gateA 數字不對" "$(printf '%s' "$Q1" | grep gateA)"; fi
|
||
|
||
echo "── Q2:最近 7 天沒擋過的是 gateC(只放行)與 gateD(30天前才擋)─"
|
||
Q2=$(ISEP_GATE_LOG="$LED" "$REPORT" q2 --days 7 2>&1)
|
||
printf '%s' "$Q2" | grep -q 'gateC' && ok "③ gateC(活著但只放行)被點名" || bad "③ 沒點名 gateC" "$Q2"
|
||
printf '%s' "$Q2" | grep -q 'gateD' && ok "④ gateD(最近7天沒擋)被點名" || bad "④ 沒點名 gateD" "$Q2"
|
||
printf '%s' "$Q2" | grep -qE '^\s+·\s+gateA' && bad "⑤ 誤點名 gateA(它最近有擋)" "$Q2" || ok "⑤ 有擋過的 gateA 不被點名"
|
||
|
||
echo "── Q3:sA 反覆撞 gateA 3 次 ─────────────────────────────────"
|
||
Q3=$(ISEP_GATE_LOG="$LED" "$REPORT" q3 2>&1)
|
||
if printf '%s' "$Q3" | grep -E 'gateA' | grep -q 'sA'; then
|
||
if printf '%s' "$Q3" | grep -E 'sA' | grep -qE '\b3\b'; then ok "⑥ sA 撞 gateA 記成 3 次"; else bad "⑥ 次數不是 3" "$Q3"; fi
|
||
else bad "⑥ 沒抓到 sA×gateA" "$Q3"; fi
|
||
# sC 撞 gateB 只 1 次,不該出現在 Q3
|
||
printf '%s' "$Q3" | grep -E 'gateB' | grep -q 'sC' && bad "⑦ 撞1次的 sC×gateB 不該出現" "$Q3" || ok "⑦ 只撞1次的不入 Q3"
|
||
|
||
echo "── 基線:空帳本也要能跑(不爆炸)───────────────────────────"
|
||
EMPTY="$TMP/empty.jsonl"; : > "$EMPTY"
|
||
if ISEP_GATE_LOG="$EMPTY" "$REPORT" all >/dev/null 2>&1; then ok "⑧ 空帳本跑 all 不報錯"; else bad "⑧ 空帳本跑 all 爆了"; fi
|
||
|
||
echo ""
|
||
echo "通過 $PASS 條,失敗 $FAIL 條(共 $N)"
|
||
[ "$FAIL" = 0 ]
|