fix(hooks): 讓四支閘認得出「指令位置」跟「heredoc/引號裡的文字」

inkstone/InkStoneCo#23、#56 同一個病:閘對整條指令字串做關鍵字掃描,
把「檔案內容/留言引用裡剛好提到某個關鍵字」當成「真的在執行」,
同時放過包一層讀取指令、或藏在 heredoc body 裡的真動作。

- 新增共用輔助 hooks/lib/strip_heredoc.py:heredoc body 是資料不是指令,
  四支閘(github-contact / main-and-prod-push / stage-before-prod /
  kbdb-api-wall 的 Bash 分支)呼叫前一律先拿掉 body 再比對。
- main-and-prod-push-guard.sh:修掉跟 release-tag-guard.sh 同款的
  「開頭是讀取工具就整條放行」前綴繞過洞;git push 的偵測改成指令位置比對;
  main/master 目標改用單字邊界,不再誤中 "domain" 這種子字串。
- github-contact-guard.sh:拿掉 gh CLI/git push 判準裡「前面隨便一個空白
  就算數」的鬆散邊界,只認真正的指令分隔符。
- kbdb-api-wall-guard.sh:Bash 分支原本引用不存在的 kbdb_cmd_check.py,
  python3 找不到檔案就吃掉錯誤印 "OK",該分支形同虛設——任何
  `wrangler d1 execute` 直打 kbdb 都會被放行。邏輯搬進新檔
  hooks/lib/kbdb_cmd_check.py(shlex 分詞、quote-aware),把 .sh 的
  參照路徑改過去,補回 Bash 分支的 kbdb-sql-ok 逃生口。

四支各補 InkStoneCo#40 §1 要求的三行中文檔頭。

新增四支可重跑測試(scripts/test-*.sh),共 69 條斷言全過,
含 #23/#56 票上實撞的原始形狀(寫 docs/TESTING.md 的 heredoc、
貼引用 #56 敘述的留言、`grep git push`)。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 18:51:52 +08:00
parent b5c4ef3540
commit 0cdb6f2c05
10 changed files with 490 additions and 75 deletions
+13 -3
View File
@@ -1,4 +1,7 @@
#!/bin/bash
# 管什麼: 對外接觸 GitHub 的寫入動作(gh CLI 高頻 API、git push/remote add 指向 github.com)——一律先擋,要 leo 手動解保險才放行。
# 為什麼: D202026-07-02)——兩個帳號因高頻寫入被 GitHub flag 永久拿不回;讀不設限(讀不是 abuse),只擋寫。
# 誤觸時怎麼關: 讀取(clone/fetch/pull/curl 抓檔)一律放行;真要寫 GitHubleo 跑 scripts/github-arm.sh 解保險;純粹提到 github.com 的文字(heredoc/commit message/留言)不算數,見下方判準。
# github-contact-guard.sh — GitHub 接觸保險(D202026-07-02
# 背景:兩個帳號因高頻動作被 flag 拿不回(幾十顆星+issues 全損)。
# 設計:戰鬥機武器保險模式——平時所有 github.com 接觸一律機械擋下(exit 2),
@@ -33,6 +36,13 @@ except Exception:
[ -z "$CMD" ] && exit 0
# 2026-08-20inkstone/InkStoneCo#23 comment, #56):a heredoc body is data, not an
# instruction. Writing docs/TESTING.md (one example line of a real push command,
# meant for a human to try later) got blocked because the whole heredoc body was
# scanned for keywords. Strip heredoc bodies before matching; on failure fall back
# to the original string (fail-open on "did this helper run", not on the verdict).
CMD=$(printf '%s' "$CMD" | python3 "$(dirname "$0")/lib/strip_heredoc.py" 2>/dev/null || printf '%s' "$CMD")
# 命中判定(D20 邊界,2026-07-05 leo 拍板——Facebook 比喻定調):
# GitHub 不在乎你「讀」(clone/fetch/抓 release,不管實名匿名、自己的還別人的——那是它原本的功能,
# 像 FB 不禁你讀貼文)。它 abuse-detect 的是「機器人一直改/寫」(高頻 push、Actions fan-out、API 寫)
@@ -43,10 +53,10 @@ except Exception:
# 放行:git clone/fetch/pull/ls-remote(任何 repo,帶不帶認證都是讀)、curl/wget、go get/pip。
HIT=""
# ① gh CLI —— 高頻 API,全擋(讀寫混雜且走你 token,保守全擋;真要唯讀查詢個案 arm)
if printf '%s' "$CMD" | grep -qE '(^|[;&|(]|\s)gh\s+(api|repo|issue|pr|auth|search|release|run|workflow|gist|browse)\b'; then
if printf '%s' "$CMD" | grep -qE '(^|[;&|(`]|&&|\|\|)[[:space:]]*gh[[:space:]]+(api|repo|issue|pr|auth|search|release|run|workflow|gist|browse)\b'; then
HIT="gh CLI(高頻 API,走你的 token"
# ② git 寫入動詞指向 githubpush / remote add 為 push 鋪路)—— 寫入,擋
elif printf '%s' "$CMD" | grep -qiE 'git\s+(push|remote\s+add)([^|;&]*)(github\.com)'; then
elif printf '%s' "$CMD" | grep -qiE '(^|[;&|(`]|&&|\|\|)[[:space:]]*git[[:space:]]+(push|remote[[:space:]]+add)([^|;&]*)(github\.com)'; then
HIT="git 寫入 → githubpush/remote add"
# ②b 🔴 2026-08-05 補漏:上面那條只認指令裡的 **github.com 字面**
# ⇒ `git push origin main`remote 名指向 GitHub**完全不會被攔**。
@@ -60,7 +70,7 @@ elif printf '%s' "$CMD" | grep -qiE 'git\s+(push|remote\s+add)([^|;&]*)(github\.
# 不必等 remote 名稱解析成功才判斷得出來,而 remote 名稱解析在某些 cwd 下會失敗
# (見檔頭「2026-08-10 leo 簡化」那段的實撞紀錄)。字面查得到就直接判定,
# 查不到才退回舊的「解 remote 名稱」那條路——兩條路都失手才會誤放行。
elif printf '%s' "$CMD" | grep -qiE '(^|[;&|(]|\s)git\s+([^|;&]*\s)?push(\s|$)'; then
elif printf '%s' "$CMD" | grep -qiE '(^|[;&|(`]|&&|\|\|)[[:space:]]*git[[:space:]]+([^|;&]*[[:space:]])?push([[:space:]]|$)'; then
# 🔴 總管 2026-08-10 收窄:原版寫成「整串裡有 github.com 就擋」,
# 於是**連 commit message 提到那個網址都會被擋**(我自己第一次要 commit 就撞到)。
# ⇒ 改成必須是「push 的目標」:github.com 要出現在 push 之後、且中間不跨命令分隔符。