fix(p34): cd.yaml 加 SPA Shadow 偵測 — 防 nginx fallback 偽綠
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
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:
@@ -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 個 deploy(run 273-277)全 success 但 prod 上 Flask 從未接到請求,
|
||||
# 因為 nginx 對 /admin/* 等路徑全 fallback 到 SPA index.html(7480 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()
|
||||
|
||||
Reference in New Issue
Block a user