From f31b4e31ba330187b00b09e8005960617f8d0ae1 Mon Sep 17 00:00:00 2001 From: OG T Date: Wed, 15 Apr 2026 19:08:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(approval):=20create=5Fapproval=5Fwith=5Ffin?= =?UTF-8?q?gerprint=20=E8=A3=9C=E6=B3=A8=2048h=20expires=5Fat=20=E9=A0=90?= =?UTF-8?q?=E8=A8=AD=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因(盤點後確認): 所有 webhook 建立 approval 的路徑(webhooks.py:908/1426/1566)均未傳 expires_at,DB 欄位為 NULL。get_pending_approvals() 的自動過期邏輯 WHERE expires_at < now 對 NULL 永遠為 False → 殭屍 PENDING 永不清理。 修正策略: 在 create_approval_with_fingerprint()(告警 approval 唯一共用入口) 注入預設 48h TTL,一次覆蓋全部 3 個 webhook 呼叫點。 手動 API 建立(approvals.py)自行傳 expires_at,不受影響。 與 2026-04-15 24h PENDING_TTL_HOURS 補丁協同工作: - 24h: find_by_fingerprint 不再收斂過期 PENDING → 新告警重新觸發通知 - 48h: get_pending_approvals auto-expire → UI 殭屍記錄自動清除 2026-04-15 ogt + Claude Sonnet 4.6(亞太):完整盤點後補完 Co-Authored-By: Claude Sonnet 4.6 --- apps/api/src/services/approval_db.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/api/src/services/approval_db.py b/apps/api/src/services/approval_db.py index 14ec07dd..1cdd4442 100644 --- a/apps/api/src/services/approval_db.py +++ b/apps/api/src/services/approval_db.py @@ -237,8 +237,22 @@ class ApprovalDBService: """ 建立帶指紋的授權請求 (戰略 B) - 用於告警收斂:相同指紋的告警會被聚合 + 用於告警收斂:相同指紋的告警會被聚合。 + + ADR-073 補丁 2026-04-15 ogt + Claude Sonnet 4.6: + 所有 webhook 路徑都未傳 expires_at,導致 DB 欄位為 NULL, + get_pending_approvals() 的自動過期邏輯 (WHERE expires_at < now) + 永遠不觸發,殭屍 PENDING 記錄無限堆積。 + 修正:凡未傳 expires_at,自動注入 48h 預設值。 """ + DEFAULT_APPROVAL_TTL_HOURS = 48 # 給人類 48h 決定視窗 + + if not request.expires_at: + now = datetime.now(UTC) + request = request.model_copy( + update={"expires_at": now + timedelta(hours=DEFAULT_APPROVAL_TTL_HOURS)} + ) + risk_level = classify_risk( action=request.action, blast_radius=request.blast_radius,