如何防止 Hook 誤刪)
從形狀正則到顯式白名單get-shit-done 安裝器 #3628 修復(fù)如何防止 Hook 誤刪【免費(fèi)下載鏈接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by T?CHES.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done本文基于倉庫變更集文檔 3628-bundled-hook-whitelist.md類型標(biāo)記為 Security關(guān)聯(lián) issue #3628解析 get-shit-done 安裝器遷移層的一次關(guān)鍵安全修復(fù)bundled-gsd-hook分類器為何不能依賴命名形狀正則自動(dòng)刪除用戶目錄下的hooks/gsd-*文件以及顯式白名單BUNDLED_GSD_HOOK_FILES CI 漂移守衛(wèi)如何保證自動(dòng)刪除范圍 實(shí)際發(fā)布文件集合。讀完本文你能理解該安裝器prompt-user阻塞流程的完整決策鏈并掌握白名單 雙向漂移測(cè)試這一可復(fù)用的防誤刪模式。背景#3610 修復(fù)了升級(jí)中斷卻引入了靜默誤刪要理解 #3628需要先理解它修補(bǔ)的對(duì)象。get-shit-done 提供一層**安裝器遷移installer migration**架構(gòu)見 docs/installer-migrations.md其設(shè)計(jì)目標(biāo)第一條就是Protect user data by default并區(qū)分三類文件Managed fileGSD 安裝并記錄在安裝清單manifest中的文件未被修改時(shí)可自動(dòng)替換User-owned file用戶自己創(chuàng)建的文件絕不能因?yàn)榍『梦挥?GSD 目錄下就被刪除Unknown file既不在清單中、又未被歸類為用戶所有的文件除非有明確證據(jù)被遷移顯式歸類否則一律保留。此前 #3610 解決了一個(gè)升級(jí)硬中斷問題全新執(zhí)行npx get-shit-done-cclatest --codex時(shí)目標(biāo)目錄如~/.codex/hooks/里殘留著上一版本 GSD 自帶的 hook 文件安裝器清單無法證明這些文件受管理于是被歸類為GSD 風(fēng)格文件但無清單證據(jù)需要用戶顯式選擇assertInstallerMigrationsUnblocked直接拋錯(cuò)終止升級(jí)見 tests/bug-3610-installer-migration-bundled-hooks-classification.test.cjs 的文件頭注釋。#3610 的修復(fù)是在分類器classifyPromptUserAction中新增bundled-gsd-hook類別凡是形如hooks/gsd-name.{js,sh,cjs,mjs}的文件都自動(dòng)判定為官方自帶 hook默認(rèn)為remove安裝器隨后會(huì)寫入新版本覆蓋。問題在于它使用的是形狀正則/^hooks\/gsd-[^/]\.(?:js|sh|cjs|mjs)$/這條正則匹配的是任何符合該命名形狀的文件而不是 npm 包中實(shí)際發(fā)布的 13 個(gè) hook。變更集文檔 3628-bundled-hook-whitelist.md 明確指出受害對(duì)象有兩類用戶自寫的自定義 hook例如hooks/gsd-personal-experiment.js舊版本 GSD 發(fā)布、但當(dāng)前版本已退役的 hook 文件。這兩類文件在首次基線掃描first-time-baseline scan時(shí)會(huì)被靜默自動(dòng)分類并刪除——屬于無聲的數(shù)據(jù)丟失silent data loss這正是該變更集被標(biāo)記為type: Security的原因。修復(fù)實(shí)現(xiàn)從匹配形狀改為白名單精確命中修復(fù)落在 get-shit-done/bin/lib/installer-migration-report.cjs。分類器不再依賴正則形狀而是查詢一個(gè)凍結(jié)的顯式白名單集合與 npm 發(fā)行版中hooks/目錄下實(shí)際發(fā)布的 13 個(gè)文件一一對(duì)應(yīng)// #3628: explicit whitelist of bundled hook files shipped in the npm // distribution under hooks/. const BUNDLED_GSD_HOOK_FILES Object.freeze(new Set([ hooks/gsd-check-update-worker.js, hooks/gsd-check-update.js, hooks/gsd-context-monitor.js, hooks/gsd-graphify-update.sh, hooks/gsd-phase-boundary.sh, hooks/gsd-prompt-guard.js, hooks/gsd-read-guard.js, hooks/gsd-read-injection-scanner.js, hooks/gsd-session-state.sh, hooks/gsd-statusline.js, hooks/gsd-update-banner.js, hooks/gsd-validate-commit.sh, hooks/gsd-workflow-guard.js, ]));可以核對(duì)倉庫根目錄 hooks/ 目錄其中 13 個(gè)gsd-*.{js,sh}文件與白名單完全一致另有l(wèi)ib/子目錄兩個(gè)輔助文件不會(huì)被[^/]的形狀約束誤匹配。兩個(gè)實(shí)現(xiàn)細(xì)節(jié)值得注意Object.freeze(new Set([...]))白名單是模塊級(jí)不可變常量single point of truth測(cè)試會(huì)斷言它必須以Set類型導(dǎo)出保證調(diào)用方可以用has()做 O(1) 成員探測(cè)且運(yùn)行期無法被意外篡改白名單條目強(qiáng)制使用 POSIX 斜杠且?guī)ooks/前綴與分類器接收的relPath規(guī)范化形態(tài)嚴(yán)格對(duì)齊見下文測(cè)試斷言。分類器的完整決策鏈哪些文件自動(dòng)處理哪些交還用戶classifyPromptUserActioninstaller-migration-report.cjs對(duì)每個(gè)被阻塞的prompt-user動(dòng)作按relPath做三類判定未命中任何一類則返回null落入既有的阻塞或提示block-or-prompt流程用戶保留控制權(quán)判定條件返回類別 / 默認(rèn)選擇過期的 SDK 構(gòu)建產(chǎn)物relPath匹配^get-shit-done/sdk/(dist|src)/stale-sdk-build-artifact→remove每次安裝都會(huì)重新生成刪除無損用戶可見的 skill 錨點(diǎn)relPath匹配^skills/gsd-[^/]/SKILL\.md$user-facing-skill→keep用戶自有內(nèi)容必須保留官方自帶 hook#3628 白名單BUNDLED_GSD_HOOK_FILES.has(relPath)bundled-gsd-hook→remove以上皆否——null不自動(dòng)分類走人工確認(rèn)修復(fù)后白名單分支的注釋把安全邊界寫得很直白與形狀匹配但不在白名單內(nèi)的文件用戶自寫 hook、舊版本退役 hookfall through 到 block-or-prompt 流程。當(dāng)白名單命中后動(dòng)作由materializeResolutioninstaller-migration-report.cjs具體化keep→baseline-preserve-user冪等保留remove→backup-and-remove——?jiǎng)h除前先在遷移日志目錄gsd-migration-journal/runId-backups/留一份回滾備份。即使自動(dòng)刪除也不是物理抹除這一點(diǎn)與 docs/installer-migrations.md 中backup-and-remove動(dòng)作類型的定義用戶會(huì)得到清晰報(bào)告并可檢查備份一致。非交互non-TTY場(chǎng)景由resolveInstallerMigrationPromptsForNonTtyinstaller-migration-report.cjs驅(qū)動(dòng)當(dāng)安裝器無法交互式提問時(shí)優(yōu)先讀取環(huán)境變量GSD_INSTALLER_MIGRATION_RESOLVE取值keep/remove作為操作者覆寫未設(shè)置時(shí)才走上述分類器安全默認(rèn)值。無法安全默認(rèn)的動(dòng)作會(huì)被過濾回result.blocked最終由assertInstallerMigrationsUnblocked拋出按原因分組的錯(cuò)誤信息每組最多展示 3 條示例路徑并提示設(shè)置GSD_INSTALLER_MIGRATION_RESOLVEchoice可在非交互環(huán)境下解決。換言之白名單機(jī)制把可無腦處理的文件和必須人來拍板的文件切開了白名單內(nèi)的 13 個(gè)文件自動(dòng)清理白名單外的一切文件升級(jí)不會(huì)靜默動(dòng)、而是阻塞并給出可操作的解決途徑。CI 漂移守衛(wèi)白名單必須與磁盤上的hooks/雙向一致變更集文檔強(qiáng)調(diào)了配套防線tests/bug-3628-bundled-hook-classifier-whitelist.test.cjs 是一個(gè)漂移守衛(wèi)任何方向的漂移都會(huì)讓 CI 失敗白名單 → 磁盤方向test 第 66-79 行遍歷BUNDLED_GSD_HOOK_FILES每個(gè)條目斷言對(duì)應(yīng)的hooks/文件名在磁盤上真實(shí)存在——防止刪除了某個(gè) hook 文件卻忘了從白名單移除磁盤 → 白名單方向test 第 81-93 行用readdirSync掃描hooks/下所有g(shù)sd-*.{js,sh,cjs,mjs}文件斷言每個(gè)都在白名單內(nèi)——防止新增發(fā)布 hook 卻忘了加白名單后果是該 hook 在升級(jí)時(shí)反而會(huì)被當(dāng)作未知文件阻塞或者在舊版本邏輯下被誤當(dāng)用戶文件結(jié)構(gòu)約束test 第 37-64 行白名單必須是Set、非空且每個(gè)條目都以hooks/開頭、使用 POSIX 斜杠、包含gsd-前綴。測(cè)試還覆蓋了負(fù)向與邊界情形確保修復(fù)沒有破壞 #3610 既有邊界test 第 108-139 行hooks/gsd-personal-experiment.js、hooks/gsd-my-custom-guard.sh、hooks/gsd-team-policy.cjs、hooks/gsd-retired-hook.js、hooks/gsd-old-statusline.js、hooks/gsd-experimental.mjs這 6 個(gè)用戶自有/退役樣例必須返回null不得自動(dòng)分類嵌套目錄hooks/gsd-helpers/index.js不得被分類保留 #3610 引入的層級(jí)邊界非gsd-前綴的hooks/my-custom-hook.js不得被分類。正向測(cè)試則遍歷白名單全部 13 項(xiàng)斷言每一項(xiàng)的分類結(jié)果恰好是{ category: bundled-gsd-hook, choice: remove }。小結(jié)一條值得借鑒的自動(dòng)刪除安全邊界#3628 的教訓(xùn)可以濃縮為一句話任何自動(dòng)刪除/覆蓋邏輯的判定依據(jù)必須是發(fā)行版實(shí)際發(fā)布物清單而不是命名形狀相似性。形狀正則hooks/gsd-*.js只能回答它看起來像官方文件白名單才能回答它就是官方文件。其工程組合是單一事實(shí)來源Object.freeze的顯式Set白名單與發(fā)行版hooks/目錄一一對(duì)應(yīng)分類器未命中即返回null把控制權(quán)交還 block-or-prompt 流程用戶文件永不靜默消失即使命中白名單刪除路徑也是backup-and-remove遷移日志保留回滾備份雙向漂移守衛(wèi)測(cè)試鎖死白名單 ? 磁盤發(fā)行物的同步關(guān)系任何一方改動(dòng)都會(huì)立刻在 CI 暴露。相關(guān)延伸閱讀安裝器遷移架構(gòu) docs/installer-migrations.md、非 TTY 解析的早期規(guī)格變更集 3541-installer-migration-prompt-user-resolution.md、上游問題修復(fù)測(cè)試 tests/bug-3610-installer-migration-bundled-hooks-classification.test.cjs 與 #3610 變更集 3610-codex-install-bundled-hooks-blocker.md?!久赓M(fèi)下載鏈接】get-shit-doneA light-weight and powerful meta-prompting, context engineering and spec-driven development system for Claude Code by T?CHES.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/getshi/get-shit-done創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考