fix(hooks): 讓四支閘認得出「指令位置」跟「heredoc/引號裡的文字」 #39
Reference in New Issue
Block a user
Delete Branch "fix/group0-gates"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
服務哪張票
inkstone/InkStoneCo#23、inkstone/InkStoneCo#56(同屬inkstone/ISEP#30這個 hub:讓閘擋對東西)。這條分支解掉什麼
同一個病的兩面:該擋的沒擋(假陰性)、不該擋的一直擋(假陽性)。
heredoc body 是資料不是指令——新增共用輔助
hooks/lib/strip_heredoc.py,四支閘(
github-contact-guard.sh/main-and-prod-push-guard.sh/stage-before-prod-guard.sh/kbdb-api-wall-guard.sh的 Bash 分支)呼叫前一律先拿掉 heredoc body 再比對關鍵字。解掉 #23 comment(2026-08-20 寫
docs/TESTING.md被github-contact-guard.sh誤擋)與 #56 comment(貼一則引用 #56 自己敘述的 Gitea 留言,被
main-and-prod-push-guard.sh誤擋)。main-and-prod-push-guard.sh補回跟release-tag-guard.sh同款、已驗證過的洞:舊版「命令開頭是讀取工具(echo/cat/grep…)就整條放行」——
echo x && git push gitea HEAD:main會被整條放走,真的推 main 完全不看。改成「危險關鍵字出現在任何位置都不吃開頭豁免」,
git push的偵測本身也從「整串找子字串」改成「指令位置」(
^/;&|(&&/||之後才算數)。順手把
*main*|*master*改成單字邊界比對——舊版連分支名裡的 "domain"(d-o-m-a-i-n)都會誤中。
github-contact-guard.sh拿掉一個鬆散邊界:ghCLI/git push的判準原本用
\s(任意一個空白)當「指令位置」的替代品,等於「只要前面有個空格就算數」——散文裡幾乎處處都有空格。改成只認真正的指令分隔符。
kbdb-api-wall-guard.sh的 Bash 分支是個真的漏擋:原本引用hooks/kbdb_cmd_check.py,這個檔案在這個 repo 從未存在過(git log --all查證,origin/main 上也是同樣的斷引用)。
python3找不到檔案就非零結束,呼叫端寫成
... || echo "OK",於是這個分支永遠印 "OK"——任何wrangler d1 execute直打arcrun-kbdb都會被放行,完全沒有機會擋下。邏輯搬進新檔
hooks/lib/kbdb_cmd_check.py(shlex 分詞、quote-aware,heredoc-strip 前置),把
.sh的參照路徑改過去,並補回 Bash 分支原本就該有、但從沒真正生效過的
kbdb-sql-ok逃生口。四支閘各補
InkStoneCo#40§1 要求的三行中文檔頭(管什麼/為什麼/誤觸時怎麼關)。沒動什麼
.sh閘(InkStoneCo#40§7:手寫 hook 只減不增);新檔都是hooks/lib/下的共用輔助程式(.py,不是閘)。真的碰 prod/真的繞過 KBDB」的案例,全部仍然擋下。
docs/、labels.yaml、.claude-plugin/。怎麼驗(雙向都要)
四支新測試,
scripts/test-{github-contact,main-and-prod-push,stage-before-prod,kbdb-api-wall-guard-bash}.sh,共 69 條斷言全過(貼在票的留言裡有完整輸出)。另外兩支既有測試
(
test-release-tag-guard.sh/test-ticket-api-bypass-guard.sh)跑過,仍然 8/8、13/13——沒有因為這次改動而回歸。
誠實列出:還漏得過去的形狀
PreToolUse:Bash掛勾,看得到的只有「Claude Code 的 Bash 工具呼叫本身的指令字串」。若某支程式
(如
installer/scripts/ship.mjs)自己用node:child_process直接spawn('git', ['push', ...]),那個 push 是子行程,不會產生新的 Bash 工具呼叫,這四支從頭到尾看不到它——這是
github-contact-guard.sh檔頭早就寫明的架構限制,不是這次能在 ISEP 這邊解掉的(
github-contact-guard.sh檔頭已指向對應的 in-process 解法
installer/scripts/d20-guard.mjs,那是 arcrun-rag 那個 repo 的事)。
github-contact-guard.sh用 hook payload 的
cwd解 remote,雲端 session 的 cwd 是薄殼,會把任何repo 的 origin 都誤判成 GitHub。這次沒動這段(不是 heredoc/指令位置這兩個
已驗證判準能覆蓋的問題,需要另外從指令本身的
git -C <path>/cd解析目標,範圍更大,留給下一輪或另開票處理)。
git commit -m "..."裡若真的出現「git」與「push」被同一段非;&|文字隔開,且 push 後面剛好是空白(例如
git commit -m "mentions git push to origin"),目前的正則仍可能誤觸——因為判準是正則模式比對,不是完整的shell 語法解析,沒有真正的引號邊界概念。用
scripts/test-main-and-prod-push-guard.sh裡的 case 6/7 驗過幾種常見寫法(帶標點、加引號提及規則本身)目前都過得去,
但沒有窮舉。
kbdb-api-wall-guard.sh的 Bash 分支用 shlex 分詞做到了真正quote-aware,是比較徹底的做法;其餘三支仍是正則比對,這是刻意的取捨
(範圍小、風險低,避免大改一個歷史包袱很重的檔案)。
相關
closes(部分)
inkstone/InkStoneCo#23、inkstone/InkStoneCo#56;hubinkstone/ISEP#30。🤖 Generated with Claude Code