From 543d239d8f013a6c7edf23361b216a5a219a56dc Mon Sep 17 00:00:00 2001 From: ogt Date: Fri, 17 Jul 2026 09:26:21 +0800 Subject: [PATCH] fix(sre): route callback ingress to Host188 executor --- apps/api/alert_rules.yaml | 24 ++++++++++++++ apps/api/src/api/v1/webhooks.py | 6 ++++ apps/api/src/services/incident_service.py | 9 ++++++ .../tests/test_alertmanager_rule_bypass.py | 31 +++++++++++++++++++ apps/api/tests/test_classify_alert_early.py | 11 +++++++ 5 files changed, 81 insertions(+) diff --git a/apps/api/alert_rules.yaml b/apps/api/alert_rules.yaml index 8515d74c1..e66d6086f 100644 --- a/apps/api/alert_rules.yaml +++ b/apps/api/alert_rules.yaml @@ -614,6 +614,30 @@ rules: # ── 告警鏈路監控 ──────────────────────────────────────────── + - id: telegram_callback_ingress_host188 + priority: 108 + description: Telegram callback ingress requires the exact Host188 OpenClaw overlay + match: + alertname: + - TelegramCallbackIngressUnverified + - TelegramCallbackForwarderDrift + response: + action_title: "受控收斂 Host188 Telegram callback ingress" + description: "權威路由: 僅允許 service:openclaw:host188 的 callback-forwarder PlayBook,先 check-mode,再 bounded apply 與獨立 verifier。" + suggested_action: CONTROLLED_APPLY + kubectl_command: "" + estimated_downtime: "0s; additive Compose overlay with rollback" + risk: medium + execution_risk_independent_of_incident_severity: true + responsibility: INFRA + responsibility_reasoning: "Telegram callback ingress 唯一 owner 為 Host188 OpenClaw;禁止 generic Kubernetes、跨主機或跨 domain fallback" + secondary_teams: [BE] + optimization: + - type: INDEPENDENT_VERIFIER + description: "驗證 Host188 overlay identity、callback receiver health、fresh durable ingress receipt 與 interactive button readiness" + command: "" + reasoning: "[權威規則] 固定路由 service:openclaw:host188 -> ansible:188-openclaw-callback-forwarder;不允許 LLM 改寫 domain。" + - id: alert_chain_broken_alertmanager priority: 109 description: Alertmanager webhook delivery chain degraded diff --git a/apps/api/src/api/v1/webhooks.py b/apps/api/src/api/v1/webhooks.py index f164b095e..c0f4de027 100644 --- a/apps/api/src/api/v1/webhooks.py +++ b/apps/api/src/api/v1/webhooks.py @@ -278,6 +278,12 @@ def _should_use_alertmanager_rule_first( and suggested_action == "INVESTIGATE" and not command ) + if alert_category == "ai_agent": + return ( + rule_id == "telegram_callback_ingress_host188" + and suggested_action == "CONTROLLED_APPLY" + and not command + ) if alert_category not in {"host_resource", "backup_failure"}: return False return ( diff --git a/apps/api/src/services/incident_service.py b/apps/api/src/services/incident_service.py index c9845dbf1..0b9ea02a4 100644 --- a/apps/api/src/services/incident_service.py +++ b/apps/api/src/services/incident_service.py @@ -190,6 +190,15 @@ def classify_alert_early( ): return "alertchain_health", "TYPE-8M" + # Host188 OpenClaw owns the Telegram callback ingress. Keep this exact + # repair signal out of the general/Kubernetes fallback path so the typed + # router can select only the bounded Host188 Ansible catalog. + if alertname in ( + "TelegramCallbackIngressUnverified", + "TelegramCallbackForwarderDrift", + ): + return "ai_agent", "TYPE-3" + # 3. 資安告警(高優先,防止被 severity/prefix 規則覆蓋) # ADR-075 TYPE-5S (2026-04-12 ogt) if any(alertname.startswith(p) for p in ( diff --git a/apps/api/tests/test_alertmanager_rule_bypass.py b/apps/api/tests/test_alertmanager_rule_bypass.py index 520d574c3..29b9eca35 100644 --- a/apps/api/tests/test_alertmanager_rule_bypass.py +++ b/apps/api/tests/test_alertmanager_rule_bypass.py @@ -132,6 +132,37 @@ def test_exact_alertmanager_chain_rule_precedes_llm() -> None: ) is True +def test_exact_host188_callback_rule_precedes_llm() -> None: + rule_response = { + "rule_id": "telegram_callback_ingress_host188", + "suggested_action": "CONTROLLED_APPLY", + "kubectl_command": "", + } + + assert _should_use_alertmanager_rule_first( + rule_response, + "ai_agent", + ) is True + + +def test_host188_callback_rule_has_no_generic_kubernetes_action() -> None: + rule_response = match_rule( + { + "labels": {"alertname": "TelegramCallbackIngressUnverified"}, + "alert_type": "custom", + "message": "callback ingress receipt is not fresh", + "severity": "warning", + "target_resource": "openclaw", + } + ) + + assert rule_response is not None + assert rule_response["rule_id"] == "telegram_callback_ingress_host188" + assert rule_response["risk_level"] == "medium" + assert rule_response["suggested_action"] == "CONTROLLED_APPLY" + assert rule_response["kubectl_command"] == "" + + def test_critical_alertmanager_incident_keeps_bounded_execution_risk_medium() -> None: rule_response = match_rule( { diff --git a/apps/api/tests/test_classify_alert_early.py b/apps/api/tests/test_classify_alert_early.py index 970de6c66..533bf220a 100644 --- a/apps/api/tests/test_classify_alert_early.py +++ b/apps/api/tests/test_classify_alert_early.py @@ -15,6 +15,17 @@ import pytest from src.services.incident_service import classify_alert_early + +def test_telegram_callback_ingress_routes_to_ai_agent_controlled_lane(): + for alertname in ( + "TelegramCallbackIngressUnverified", + "TelegramCallbackForwarderDrift", + ): + assert classify_alert_early(alertname, "warning", {"host": "188"}) == ( + "ai_agent", + "TYPE-3", + ) + # --------------------------------------------------------------------------- # # TYPE-4D: Config Drift # --------------------------------------------------------------------------- #