From a92562d65c113e175b58bcdab531844514388e67 Mon Sep 17 00:00:00 2001 From: OG T Date: Tue, 14 Apr 2026 21:40:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(Phase=205=20Sprint=205.4):=20=E5=88=86?= =?UTF-8?q?=E9=A1=9E=E6=8C=89=E9=88=95=E5=BE=9E=20registry=20=E5=8B=95?= =?UTF-8?q?=E6=85=8B=E7=94=A2=E7=94=9F=20=E2=80=94=20=E6=8C=89=E9=88=95?= =?UTF-8?q?=E9=87=8D=E5=95=9F=E4=B8=8A=E7=B7=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _build_inline_keyboard() 改寫: - 原 hardcode _CATEGORY_BUTTONS dict (28 按鈕) 已下架 - 改從 callback_action_spec.yaml registry 動態產生 - spec.callback_format 決定格式: * nonce (寫類) → self._security.generate_callback_nonce(approval_id, action_name) * info (查類) → {action_name}:{incident_id} - 新按鈕只需改 yaml,零改 code 分類覆蓋 (從 yaml 自動推算): - kubernetes: 6 按鈕 (4 寫 + 2 查) - host_resource: 3 按鈕 (1 查 + 2 寫) - secops: 4 按鈕 (全寫類 + Multi-Sig) - database: 3 按鈕 - storage: 2 按鈕 - network: 3 按鈕 - devops_tool: 2 按鈕 - external_site: 2 按鈕 - business: 1 按鈕 - flywheel_health: 1 按鈕 - ssl_cert: 1 按鈕 這次按鈕不是鬼魂 — 每個都有: ✅ callback_format 正確 (4-part nonce / 2-part info) ✅ Sprint 5.3 dispatch handler 接收 ✅ Sprint 5.2 MCP registry 執行 ✅ audit log + reply_to 原卡片 回歸: 188/188 Co-Authored-By: Claude Haiku 4.5 --- apps/api/src/services/telegram_gateway.py | 36 +++++++++++++++-------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/api/src/services/telegram_gateway.py b/apps/api/src/services/telegram_gateway.py index eea36f89..0c1abb7c 100644 --- a/apps/api/src/services/telegram_gateway.py +++ b/apps/api/src/services/telegram_gateway.py @@ -1376,16 +1376,26 @@ class TelegramGateway: alert_category: 告警類別 (ADR-071-E: 決定 TYPE-3 按鈕組合) notification_type: 通知類型 (TYPE-1/2/3/4/4D) """ - # 2026-04-14 Claude Sonnet 4.6 首席架構師裁示: - # 原 _CATEGORY_BUTTONS (28 個分類按鈕) 全部下架 — 信任 > 功能 - # 盤查證據(統帥 2026-04-14 20:00 完整 audit): - # - callback_data 格式全錯 (3-part action:xxx:id 不符合 parser 4-part nonce / 2-part info) - # - 後端 0 個 handler(grep apps/api/src 無任何 dispatch elif 分支) - # - 從 2026-04-11 commit 325b3851 起死了 3 天 - # - 統帥今天真踩到:點「查程序」沒反應 → 信任破壞 - # 正式下架改用通用按鈕 (approve/reject/silence/detail/history/reanalyze) - # 補完計畫:MASTER 藍圖 Phase 5「分類按鈕完整化」(另立 ADR) - _CATEGORY_BUTTONS: dict[str, list[tuple[str, str]]] = {} # 臨時空,fallback 通用按鈕 + # 2026-04-14 Claude Sonnet 4.6 (Phase 5 Sprint 5.4): + # 從 callback_action_spec registry 動態產生按鈕(原 _CATEGORY_BUTTONS hardcode 已下架) + # 優點:新增按鈕只需改 yaml,callback_data 格式由 spec.callback_format 決定 + # 安全:yaml 裡每個 action 都有對應 MCP dispatcher handler(Sprint 5.2/5.3 實作) + from src.services.callback_dispatcher import list_actions_for_category as _list_actions + + def _build_category_buttons_for(category: str) -> list[tuple[str, str]]: + """從 registry 產生 (label, callback_data) list""" + actions = _list_actions(category) + btns: list[tuple[str, str]] = [] + for spec_it in actions: + emoji_label = f"{spec_it.emoji} {spec_it.label}".strip() + if spec_it.callback_format == "nonce": + # 寫類:產生 4-part nonce + cb = self._security.generate_callback_nonce(approval_id, spec_it.name) + else: + # 查類:2-part info + cb = f"{spec_it.name}:{incident_id}" + btns.append((emoji_label, cb)) + return btns # 產生 Nonce (防重放,用於寫操作) approve_nonce = self._security.generate_callback_nonce(approval_id, "approve") @@ -1394,11 +1404,13 @@ class TelegramGateway: is_type3 = notification_type in ("TYPE-3", NotificationType.TYPE_3, "") - if is_type3 and alert_category and alert_category in _CATEGORY_BUTTONS: + _dynamic_buttons = _build_category_buttons_for(alert_category) if alert_category else [] + + if is_type3 and _dynamic_buttons: # TYPE-3 動態操作按鈕:第一行為類別專屬操作 category_btns = [ {"text": text, "callback_data": cb_data} - for text, cb_data in _CATEGORY_BUTTONS[alert_category] + for text, cb_data in _dynamic_buttons ] # 每行最多 3 個,超過換行 rows = [category_btns[i:i+3] for i in range(0, len(category_btns), 3)]