f1b2ed909f
本輪跑迴歸測試時實撞兩次,兩次都把這台機器的磁碟寫滿:
$ bash hooks/tests/main-and-prod-push-guard.test.sh "$PWD"
REAL="$1" 要的是「那支 hook 的檔案路徑」,我傳了 repo 根目錄
⇒ hook_sandbox 不驗參數,直接 cp -R "$(dirname "$1")"
⇒ dirname 變成 ~/Documents/tech_projects(上一層)
⇒ 整個 tech_projects(所有 repo、所有 worktree)被搬進 mktemp
實測:第一次 13 GB + 10 GB,第二次 23 GB。
磁碟可用 25 GB → 462 MB,cp 一路吐 "No space left on device"。
兩次都是我手動 rm -rf 才回來的(27 GB)。
🔴 而它印出來的只有一句「❌ 沙盒建不起來」——
沒說是參數傳錯,也沒說它已經把磁碟寫滿了。
⇒ 這跟本票在講的是同一句話:**閘/工具給的下一步,沒有人照著打過一次**,
差別只在這次壞的不是逃生門,是「它壞掉時說的話」。
改法(判準是「要求某個東西在場」,不是關鍵字比對):
① $1 要指到一個真的檔案(空字串、目錄、不存在的路徑都不算)
② 它的上一層目錄名要叫 hooks(沙盒的前提就是複製一整個 hooks/)
任一不成立 ⇒ 在 mktemp 之前 return 1,並印出走得通的那一行。
順手補上 docs/TESTING.md 之前沒寫過的一件事:**有五支測試要傳參數**,
而不傳的後果不是報錯是假綠——prod-write-guard.test.sh 的 HOOK="$1" 空掉時
每一條都執行空指令回 0 ⇒「該擋」全變成「實得 pass」,19 條假紅
(傳對參數:通過 37 / 失敗 0)。
測試:hooks/tests/hook-sandbox.test.sh 10 條(A30),通過 10 失敗 0
①③⑤⑥ 驗的是「收手在複製之前」,不是「訊息好不好看」
⑧⑨⑩ 驗正常用法沒被弄壞、複本裡沒混進 hooks/ 以外的東西
既有兩支沙盒測試複驗:
scripts/test-main-and-prod-push-guard.sh 13/13
hooks/tests/main-and-prod-push-guard.test.sh 通過 10 / 失敗 0
hooks/tests/main-and-prod-push-guard-cross-repo.test.sh 通過 19 / 失敗 0
📌 這顆跟 0.22.0 的三件事無關,是本輪路上撞到的。要拆票或丟掉這顆都行,
它獨立於前面兩顆,而且只動 hooks/tests/(沒有任何 hook 的執行行為改變)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
75 lines
4.2 KiB
Bash
Executable File
75 lines
4.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# hooks/tests/lib/hook-sandbox.sh 的迴歸測試(inkstone/ISEP#122)
|
||
#
|
||
# 🔴 為什麼有這支(2026-09-02 實撞,證據在票上):
|
||
# `hook_sandbox` 的第一個參數是「那支 hook 的檔案路徑」,傳錯時舊版不檢查就
|
||
# `cp -R "$(dirname "$1")"` ⇒ 複製的是上一層。傳 repo 根目錄進去,
|
||
# 複製的就是**整個 tech_projects**:兩次吃掉 23 GB,磁碟剩 462 MB,
|
||
# 而它只印一句「沙盒建不起來」——**沒說參數錯,也沒說它已經把磁碟寫滿**。
|
||
#
|
||
# 所以這支測的不是「錯誤訊息好不好看」,是**收手的時機**:
|
||
# ④⑤ 兩條驗「複製之前就 return 1」——暫存區裡不准留下任何東西。
|
||
#
|
||
# 用法:bash hooks/tests/hook-sandbox.test.sh
|
||
set -u
|
||
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||
ROOT=$(CDPATH= cd -- "$HERE/.." && pwd) # …/hooks
|
||
REPO=$(CDPATH= cd -- "$ROOT/.." && pwd)
|
||
PASS=0; FAIL=0
|
||
ok(){ printf ' ✅ %s\n' "$1"; PASS=$((PASS+1)); }
|
||
no(){ printf ' ❌ %s —— %s\n' "$1" "$2"; FAIL=$((FAIL+1)); }
|
||
|
||
# 每一條都在自己的子殼裡跑:hook_sandbox 會設全域變數,不隔離會互相污染。
|
||
run(){ # run <參數> → 印 "rc|沙盒路徑|訊息"
|
||
( . "$HERE/lib/hook-sandbox.sh"
|
||
msg=$(hook_sandbox "$1" 2>&1); rc=$?
|
||
printf '%s|%s|%s' "$rc" "${HOOK_SANDBOX:-}" "$(printf '%s' "$msg" | tr '\n' ' ')"
|
||
)
|
||
}
|
||
|
||
echo "── 該收手(傳錯參數)──────────────────────────────────────"
|
||
|
||
r=$(run "$REPO"); rc=${r%%|*}; rest=${r#*|}; sb=${rest%%|*}; msg=${rest#*|}
|
||
[ "$rc" = "1" ] && ok "① 傳 repo 根目錄(本票的實撞)→ return 1" \
|
||
|| no "① 傳 repo 根目錄(本票的實撞)→ return 1" "實得 rc=$rc"
|
||
case "$msg" in *"hooks/main-and-prod-push-guard.sh"*)
|
||
ok "② 訊息給得出一行**真的跑得起來**的用法" ;;
|
||
*) no "② 訊息給得出一行**真的跑得起來**的用法" "訊息:$msg" ;;
|
||
esac
|
||
if [ -z "$sb" ] || [ ! -d "$sb" ]; then ok "③ 收手在 mktemp 之前,暫存區沒有殘骸"
|
||
else no "③ 收手在 mktemp 之前,暫存區沒有殘骸" "留下了 $sb"; fi
|
||
|
||
r=$(run ""); [ "${r%%|*}" = "1" ] && ok "④ 空參數 → return 1(不是拿空字串去 dirname)" \
|
||
|| no "④ 空參數 → return 1" "實得 rc=${r%%|*}"
|
||
|
||
r=$(run "$REPO/scripts/ticket"); rc=${r%%|*}; rest=${r#*|}; sb=${rest%%|*}
|
||
if [ "$rc" = "1" ]; then ok "⑤ 檔案存在但上一層不是 hooks/ → 一樣收手"
|
||
else no "⑤ 檔案存在但上一層不是 hooks/ → 一樣收手" "實得 rc=$rc"; fi
|
||
if [ -z "$sb" ] || [ ! -d "$sb" ]; then ok "⑥ ⑤ 這條也沒把 scripts/ 複製出去"
|
||
else no "⑥ ⑤ 這條也沒把 scripts/ 複製出去" "留下了 $sb"; fi
|
||
|
||
r=$(run "$ROOT/沒有這支.sh"); [ "${r%%|*}" = "1" ] && ok "⑦ 路徑不存在 → return 1" \
|
||
|| no "⑦ 路徑不存在 → return 1" "實得 rc=${r%%|*}"
|
||
|
||
echo "── 不准把本來會過的弄壞(誤攔比漏擋嚴重)────────────────────"
|
||
( . "$HERE/lib/hook-sandbox.sh"
|
||
hook_sandbox "$ROOT/main-and-prod-push-guard.sh"; rc=$?
|
||
if [ "$rc" != "0" ]; then echo "RC=$rc"; exit 0; fi
|
||
[ -f "$HOOK_SANDBOX_HOOK" ] && echo "HOOKOK"
|
||
[ -d "$HOOK_SANDBOX/hooks/lib" ] && echo "LIBOK"
|
||
# 只複製 hooks/,不該把 repo 的其他目錄帶進來
|
||
[ -d "$HOOK_SANDBOX/hooks/scripts" ] && echo "LEAK"
|
||
hook_sandbox_cleanup
|
||
) > /tmp/.hs-ok.$$ 2>&1
|
||
grep -q HOOKOK /tmp/.hs-ok.$$ && ok "⑧ 正常用法照樣建得起來,複本裡有那支 hook" \
|
||
|| no "⑧ 正常用法照樣建得起來" "$(cat /tmp/.hs-ok.$$)"
|
||
grep -q LIBOK /tmp/.hs-ok.$$ && ok "⑨ 整個 hooks/(含 lib/)都在複本裡" \
|
||
|| no "⑨ 整個 hooks/(含 lib/)都在複本裡" "$(cat /tmp/.hs-ok.$$)"
|
||
grep -q LEAK /tmp/.hs-ok.$$ && no "⑩ 只複製 hooks/,沒有把 repo 其他目錄帶進去" "複本裡出現 scripts/" \
|
||
|| ok "⑩ 只複製 hooks/,沒有把 repo 其他目錄帶進去"
|
||
rm -f /tmp/.hs-ok.$$
|
||
|
||
echo
|
||
echo "通過 $PASS 條,失敗 $FAIL 條(共 $((PASS+FAIL)) 條)"
|
||
[ "$FAIL" -eq 0 ]
|