From 53328bfbe926cd31925c8f18ed7efc0c8f43b909 Mon Sep 17 00:00:00 2001 From: claude-code Date: Sun, 23 Aug 2026 20:55:59 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E4=B8=89=E6=94=AF=E9=96=98=E7=9A=84?= =?UTF-8?q?=E6=88=B3=E8=A8=98=E9=87=8B=E6=94=BE=E5=9C=A8=20Linux=20?= =?UTF-8?q?=E6=B0=B8=E9=81=A0=E5=A4=B1=E6=95=88=EF=BC=9Astat=20-c=20%Y=20?= =?UTF-8?q?=E8=A6=81=E6=8E=92=E5=9C=A8=20stat=20-f=20%m=20=E5=89=8D?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 三支閘的 stamp_ok/退回機制都用 `stat -f %m … || stat -c %Y …` 取 mtime。 GNU (Linux) 的 `stat -f` 是 --file-system,%m 被當成檔名 ⇒ 把整張檔案系統表印到 stdout(被 $() 收進去)且 exit 1 ⇒ MT 變非數字 ⇒ case *[!0-9]* 命中 ⇒ 釋放章永遠失效。 dev 在 macOS(BSD `-f %m` 正常)所以本機測不出來,一到雲端 Linux 就咬。 實際後果(2026-08-23 雲端 cloud-worker 實撞): - prod-write-guard:總管 touch /tmp/.prod-write-ok 也放行不了 ⇒ routine 的心跳打不出去 - main-and-prod-push-guard:arm 章在 Linux 形同虛設 - stage-before-prod-guard:stage 已驗的退回機制失效 改法:GNU 先、BSD 後(stat -c %Y … || stat -f %m …),兩平台都正確。 驗證(Linux):抽出 patched stamp_ok 實跑—— 新戳記→rc=0(釋放、單次消耗)/無戳記→rc=1(擋)/逾時>900s→rc=1(過期)。 反證:舊順序帶新戳記→rc=2(確認舊版在 Linux 是壞的)。 --- hooks/main-and-prod-push-guard.sh | 4 +++- hooks/prod-write-guard.sh | 6 +++++- hooks/stage-before-prod-guard.sh | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/hooks/main-and-prod-push-guard.sh b/hooks/main-and-prod-push-guard.sh index 87f9d3e..90a8a88 100755 --- a/hooks/main-and-prod-push-guard.sh +++ b/hooks/main-and-prod-push-guard.sh @@ -87,7 +87,9 @@ STAMP="/tmp/.main-push-ok" stamp_ok() { [ -f "$STAMP" ] || return 1 NOW=$(date +%s 2>/dev/null || echo 0) - MT=$(stat -f %m "$STAMP" 2>/dev/null || stat -c %Y "$STAMP" 2>/dev/null || echo 0) + # 🔴 GNU (Linux) 先、BSD (macOS) 後——順序反了戳記在雲端永遠失效(見 prod-write-guard.sh 同段註解): + # GNU 的 `stat -f` 是 --file-system,`%m` 被當成檔名 ⇒ 印出檔案系統表且 exit 1 ⇒ MT 非數字 ⇒ arm 章在 Linux 永不生效。 + MT=$(stat -c %Y "$STAMP" 2>/dev/null || stat -f %m "$STAMP" 2>/dev/null || echo 0) case "$NOW$MT" in *[!0-9]*) return 1 ;; esac [ "$NOW" -gt 0 ] && [ "$MT" -gt 0 ] || return 1 [ $((NOW - MT)) -lt 900 ] || return 1 diff --git a/hooks/prod-write-guard.sh b/hooks/prod-write-guard.sh index 437d424..135fa8d 100755 --- a/hooks/prod-write-guard.sh +++ b/hooks/prod-write-guard.sh @@ -52,7 +52,11 @@ STAMP="/tmp/.prod-write-ok" stamp_ok() { [ -f "$STAMP" ] || return 1 NOW=$(date +%s 2>/dev/null || echo 0) - MT=$(stat -f %m "$STAMP" 2>/dev/null || stat -c %Y "$STAMP" 2>/dev/null || echo 0) + # 🔴 GNU (Linux) 先、BSD (macOS) 後——順序反了戳記在雲端永遠失效: + # GNU 的 `stat -f` 是 --file-system,`%m` 被當成檔名 ⇒ 把整張檔案系統表印到 + # stdout(被 $() 收進去)且 exit 1 ⇒ MT 變非數字 ⇒ 這道閘的釋放章在 Linux 永不生效。 + # dev 在 macOS(BSD `-f %m` 正常)所以沒被抓到,一到雲端 Linux 就咬(實測 2026-08-23)。 + MT=$(stat -c %Y "$STAMP" 2>/dev/null || stat -f %m "$STAMP" 2>/dev/null || echo 0) case "$NOW$MT" in *[!0-9]*) return 1 ;; esac [ "$NOW" -gt 0 ] && [ "$MT" -gt 0 ] || return 1 [ $((NOW - MT)) -lt 900 ] || return 1 diff --git a/hooks/stage-before-prod-guard.sh b/hooks/stage-before-prod-guard.sh index 8eecbab..ff9d86a 100755 --- a/hooks/stage-before-prod-guard.sh +++ b/hooks/stage-before-prod-guard.sh @@ -172,7 +172,8 @@ for STAMP in /tmp/.stage-ok-by-leo /tmp/.stage-verified; do # 抽數字會得到天文數字 ⇒ `now - t` 是**負數** ⇒ `< 21600` 成立 ⇒ **永遠放行**。 # ⇒ 只有「不晚於現在」的時間戳才算數;不合理就退回 mtime,別當成通過。 if [ "$t" -eq 0 ] || [ "$t" -gt "$now" ]; then - t=$(stat -f %m "$STAMP" 2>/dev/null || stat -c %Y "$STAMP" 2>/dev/null || echo 0) + # 🔴 GNU (Linux) 先、BSD (macOS) 後(見 prod-write-guard.sh 同段註解):反了 stat -f %m 會在 Linux 印檔案系統表 ⇒ t 非數字 ⇒ 退回機制失效。 + t=$(stat -c %Y "$STAMP" 2>/dev/null || stat -f %m "$STAMP" 2>/dev/null || echo 0) fi [ "$t" -gt 0 ] && [ "$((now - t))" -lt 21600 ] && exit 0 # 6 小時內驗過 stage → 放行 done