fix(p34): cd.yaml 加 SPA Shadow 偵測 — 防 nginx fallback 偽綠
Some checks failed
CD Pipeline / deploy (push) Has been cancelled

過去 5 個 deploy(run 273-277)全 success 但 prod 上 Flask 從未接到請求 —
nginx 對所有路徑 fallback 到 SPA index.html (7480 byte / etag e167a58a...) —
原健康檢查只看 HTTP 200,被 SPA shell 200 騙過。

新增第 3 階段檢查(接在原 HTTP 200 retry + 三容器驗證之後):
驗 /health response 三條 fingerprint 任一不符 SPA shell 即 Flask 真接到:
  (a) Content-Length != 7480
  (b) etag != e167a58a1baf907f55a2925a2e8665d1
  (c) x-process-time header 存在(Flask middleware 加的,nginx static 不會帶)

三條全失敗 = SPA 攔截 → 推 Telegram + exit 1(CD 紅)。
TELEGRAM secrets 未設時跳過告警不阻 deploy。

修了過去那種「我推 commit、CD 全綠、實際 prod 0 影響」的盲點。
This commit is contained in:
OoO
2026-05-04 14:21:42 +08:00
parent 86f1fd5f50
commit 927d7072ce

View File

@@ -291,8 +291,12 @@ jobs:
echo " Monitoring 設定未變更,略過重新載入"
fi
# ── 健康檢查H3: HTTP + 三容器狀態雙重驗證) ─────────────────────────
# ── 健康檢查H3: HTTP + 三容器 + Phase 34 SPA Shadow 偵測) ──────────
- name: 健康檢查
env:
COMMIT_SHA: ${{ steps.commit.outputs.short_sha }}
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
run: |
echo "⏳ 等待服務啟動30s..."
sleep 30
@@ -320,6 +324,40 @@ jobs:
echo "✅ 三容器均正常運行($RUNNING/3"; \
fi'
# ── Phase 34 SPA Shadow 偵測 — 防 nginx fallback 偽綠 ───────────────
# 過去 5 個 deployrun 273-277全 success 但 prod 上 Flask 從未接到請求,
# 因為 nginx 對 /admin/* 等路徑全 fallback 到 SPA index.html7480 byte
# 三條 fingerprint 任一不符 SPA = Flask 真接到:
# (a) Content-Length != 7480
# (b) etag != e167a58a1baf907f55a2925a2e8665d1
# (c) x-process-time header 存在Flask middleware
echo "🔍 SPA Shadow 偵測(驗 Flask 真接到請求)..."
SPA_ETAG='e167a58a1baf907f55a2925a2e8665d1'
SPA_LEN='7480'
# 用 /health純 Flask不會被 SPA 路徑攔)做基準探針
HDR=$(curl -sS -D - -o /dev/null --max-time 10 https://mo.wooo.work/health 2>/dev/null || echo "")
ETAG=$(echo "$HDR" | grep -i '^etag:' | tr -d '"\r' | awk '{print $2}' | tr 'A-Z' 'a-z')
CLEN=$(echo "$HDR" | grep -i '^content-length:' | awk '{print $2}' | tr -d '\r')
XPT=$(echo "$HDR" | grep -i '^x-process-time:' | awk '{print $2}' | tr -d '\r')
FLASK_OK=0
[ -n "$XPT" ] && [ "$XPT" != "0" ] && FLASK_OK=1
[ -n "$ETAG" ] && [ "$ETAG" != "$SPA_ETAG" ] && FLASK_OK=1
[ -n "$CLEN" ] && [ "$CLEN" != "$SPA_LEN" ] && FLASK_OK=1
if [ "$FLASK_OK" != "1" ]; then
echo "❌ SPA Shadow 偵測:/health 看似 200 但 nginx fallback 攔截"
echo " etag=$ETAG (SPA=$SPA_ETAG)"
echo " content-length=$CLEN (SPA=$SPA_LEN)"
echo " x-process-time=$XPT Flask 應 > 0"
# Telegram 告警(如 secrets 已設)
if [ -n "${TELEGRAM_BOT_TOKEN}" ] && [ -n "${TELEGRAM_CHAT_ID}" ]; then
MSG="🚨 EwoooC SPA Shadow 偵測警告%0A├ commit ${COMMIT_SHA}%0A├ /health 被 nginx SPA fallback 攔截%0A└ 立即查 nginx upstream / Flask container"
curl -sS -m 5 -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d "chat_id=${TELEGRAM_CHAT_ID}" -d "text=${MSG}" -d "parse_mode=HTML" >/dev/null || true
fi
exit 1
fi
echo "✅ SPA Shadow OK — Flask 真接到請求etag=$ETAG xpt=$XPT clen=$CLEN"
# ── 觸發 Post-Deploy Code Review ─────────────────────────────────────
- name: 觸發 AI Code Review
if: success()