from __future__ import annotations from src.services.telegram_gateway import ( _agent99_actionable_outbound_metadata, _agent99_alert_from_actionable_outbound, _agent99_alert_from_ai_automation_card, _merge_outbound_source_envelope_extra, _outbound_source_envelope, _sanitize_telegram_error, format_aiops_signal_alert_card, ) def test_telegram_gateway_sanitizes_bot_token_url() -> None: raw = "Client error for https://api.telegram.org/bot123456:SECRET/sendMessage" sanitized = _sanitize_telegram_error(raw) assert "SECRET" not in sanitized assert "bot" in sanitized def test_outbound_source_envelope_keeps_replay_context_without_raw_payload() -> None: payload = { "chat_id": "-100123", "text": ( "ACTION REQUIRED INC-20260513-9B082D " "7f858956 token " "1234567890:abcdefghijklmnopqrstuvwxyzABCDEFGH" ), "parse_mode": "HTML", "reply_markup": { "inline_keyboard": [ [ {"text": "批准", "callback_data": "approve:approval-id-secret"}, {"text": "詳情", "callback_data": "details:approval-id-secret"}, ] ] }, } envelope = _outbound_source_envelope("sendMessage", payload) assert envelope["adapter"] == "legacy_telegram_gateway" assert envelope["method"] == "sendMessage" assert envelope["payload_sha256"] assert envelope["payload_keys"] == ["chat_id", "parse_mode", "reply_markup", "text"] assert envelope["parse_mode"] == "HTML" assert envelope["reply_markup"]["button_count"] == 2 assert envelope["reply_markup"]["buttons"][0]["callback_prefix"] == "approve" assert envelope["reply_markup"]["buttons"][1]["callback_prefix"] == "details" assert envelope["source_refs"]["incident_ids"] == ["INC-20260513-9B082D"] assert envelope["source_refs"]["code_refs"] == ["7f858956"] assert "approval-id-secret" not in str(envelope) assert "1234567890:" not in str(envelope) assert "ACTION REQUIRED" not in str(envelope) def test_outbound_source_envelope_reads_incident_refs_from_buttons() -> None: payload = { "chat_id": "-100123", "text": "ACTION REQUIRED without incident id in visible text", "reply_markup": { "inline_keyboard": [ [ {"text": "詳情", "callback_data": "detail:INC-20260525-ABC123"}, {"text": "歷史", "callback_data": "history:INC-20260525-ABC123"}, ], [ {"text": "重診", "callback_data": "reanalyze:INC-20260525-DEF456"}, ], ], }, } envelope = _outbound_source_envelope("sendMessage", payload) assert envelope["source_refs"]["incident_ids"] == [ "INC-20260525-ABC123", "INC-20260525-DEF456", ] assert envelope["reply_markup"]["buttons"][0]["callback_prefix"] == "detail" assert "detail:INC-20260525-ABC123" not in str(envelope) def test_outbound_source_envelope_reads_meta_event_ref_from_text() -> None: payload = { "chat_id": "-100123", "text": ( "⚙️ META SYSTEM\n" "📋 META-20260525201300\n" "異常元件:AI 自健診異常" ), "parse_mode": "HTML", "reply_markup": { "inline_keyboard": [ [{"text": "靜默", "callback_data": "silence:opaque-secret"}] ], }, } envelope = _outbound_source_envelope("sendMessage", payload) assert envelope["source_refs"]["event_ids"] == ["META-20260525201300"] assert envelope["source_refs"]["incident_ids"] == [] assert envelope["reply_markup"]["buttons"][0]["callback_prefix"] == "silence" assert "opaque-secret" not in str(envelope) def test_outbound_source_envelope_reads_ai_advisory_refs_without_raw_callback() -> None: payload = { "chat_id": "-100123", "text": "Coverage 缺口分析", "reply_markup": { "inline_keyboard": [ [ { "text": "已處理", "callback_data": ( "ai_advisory_handled:coverage_gap:auto_rule_creation" ), }, { "text": "忽略", "callback_data": ( "ai_advisory_snooze:coverage_gap:auto_rule_creation" ), }, ] ], }, } envelope = _outbound_source_envelope("sendMessage", payload) assert envelope["source_refs"]["event_ids"] == [ "ai_advisory:coverage_gap:auto_rule_creation" ] assert envelope["source_refs"]["advisory_ids"] == [ "coverage_gap:auto_rule_creation" ] assert envelope["source_refs"]["alert_ids"] == ["coverage_gap"] assert envelope["source_refs"]["fingerprints"] == [ "ai_advisory:coverage_gap:auto_rule_creation" ] assert "ai_advisory_handled:coverage_gap:auto_rule_creation" not in str(envelope) def test_outbound_source_envelope_marks_wazuh_ai_alert_card_for_awooop_readback() -> None: raw_alert = """ wazuh_dashboard_api_readback_degraded dashboard agent list disappeared POST /api/check-stored-api status=429 POST /api/check-api status=500 https://127.0.0.1:55000 is unreachable manager registry readback blocked full_log=/var/ossec/logs/alerts/alerts.json Authorization: Bearer abcdefghijklmnopqrstuvwxyz """ card = format_aiops_signal_alert_card(raw_alert) payload = { "chat_id": "-100123", "text": card, "parse_mode": "HTML", } envelope = _outbound_source_envelope("sendMessage", payload) card_metadata = envelope["ai_automation_alert_card"] assert card_metadata["schema_version"] == "ai_automation_alert_card_mirror_v1" assert card_metadata["card_schema"] == "ai_automation_alert_card_v1" assert card_metadata["event_type"] == "wazuh_dashboard_api_readback_degraded" assert card_metadata["lane"] == "siem_observability_readback_degraded" assert card_metadata["target"] == "wazuh_dashboard_api" assert card_metadata["gates"] == [ "controlled_playbook_queue", "runtime_write_gate=controlled", ] assert card_metadata["controlled_playbook_queue"] is True assert card_metadata["runtime_write_gate_state"] == "controlled" assert card_metadata["runtime_write_gate_count"] == 1 assert card_metadata["delivery_receipt_readback_required"] is True assert envelope["source_refs"]["alert_ids"] == [ "wazuh_dashboard_api_readback_degraded" ] assert envelope["source_refs"]["fingerprints"] == [ "ai_automation_alert_card:wazuh_dashboard_api_readback_degraded:siem_observability_readback_degraded" ] assert "127.0.0.1:55000" not in str(envelope) assert "/var/ossec" not in str(envelope) assert "abcdefghijkl" not in str(envelope) def test_ai_alert_card_builds_agent99_provider_freshness_signal() -> None: raw_alert = """ SourceProviderIngestionStale provider_freshness_signal freshness window timeout Sentry / SigNoz provider freshness last seen missing direct ref verifier readback Authorization: Bearer abcdefghijklmnopqrstuvwxyz """ card = format_aiops_signal_alert_card(raw_alert) payload = _agent99_alert_from_ai_automation_card( card, source="unit-test", ) assert payload is not None assert payload["source"] == "awoooi-api-telegram-gateway" assert str(payload["id"]).startswith( "awoooi-telegram-alert-card-provider_freshness_signal-" ) assert payload["kind"] == "provider_freshness_signal" assert payload["suggestedMode"] == "ProviderFreshness" assert payload["controlledApply"] is False assert payload["routing"]["routeSource"] == "structured_kind" assert payload["awoooi"]["alertCategory"] == "source_provider_freshness_triage" assert payload["awoooi"]["notificationType"] == "ai_automation_alert_card_v1" assert "component=telegram_gateway" in payload["labels"] assert "source=unit-test" in payload["labels"] assert "provider-freshness" in payload["labels"] assert "no-false-green" in payload["labels"] assert "abcdefghijklmnopqrstuvwxyz" not in str(payload) def test_action_required_cold_start_card_routes_to_agent99_recover() -> None: card = ( "ℹ️ ACTION REQUIRED | 低風險\n" "──────────────────────\n" "📋 INC-20260710-5700F7\n" "🎯 資源:cold-start-gate\n" "🏷️ 分類:general\n" "🧭 處置狀態:AI 選擇不執行修復\n" "🤖 AI 自動化鏈路" ) metadata = _agent99_actionable_outbound_metadata(card) payload = _agent99_alert_from_actionable_outbound(card, source="unit-test") assert metadata is not None assert metadata["card_schema"] == "awooop_action_required_v1" assert metadata["incident_id"] == "INC-20260710-5700F7" assert metadata["target"] == "cold-start-gate" assert payload is not None assert payload["kind"] == "host_recovery" assert payload["suggestedMode"] == "Recover" assert payload["controlledApply"] is True assert payload["resolution"]["policy"] == "mode_verifier_can_resolve" assert payload["awoooi"]["incidentId"] == "INC-20260710-5700F7" def test_failed_cicd_card_routes_to_agent99_status_with_commit_receipt() -> None: card = ( "❌ [AWOOOI CI/CD] | build-and-deploy\n" "📦 AWOOOI 部署失敗\n" "📋 85159f25\n" "📝 fix(security): restrict executor SSH egress\n" "🔗 Workflow" ) metadata = _agent99_actionable_outbound_metadata(card) payload = _agent99_alert_from_actionable_outbound(card, source="unit-test") assert metadata is not None assert metadata["card_schema"] == "awoooi_cicd_failure_v1" assert metadata["commit_sha"] == "85159f25" assert payload is not None assert payload["kind"] == "cicd_failure" assert payload["suggestedMode"] == "Status" assert payload["controlledApply"] is False assert payload["resolution"]["policy"] == "external_source_receipt_required" assert payload["awoooi"]["commitSha"] == "85159f25" assert "gitea.example.invalid" not in str(payload) def test_agent99_dispatch_receipt_is_persisted_without_raw_transport_body() -> None: envelope = _outbound_source_envelope( "sendMessage", { "chat_id": "chat", "text": ( "ℹ️ ACTION REQUIRED | 低風險\n" "📋 INC-20260710-5700F7\n" "🎯 資源:cold-start-gate\n" "🤖 AI 自動化鏈路" ), }, ) receipt = { "schema_version": "telegram_agent99_dispatch_receipt_v1", "status": "accepted_inbox_triggered", "transport": "relay", "alert_id": "awoooi-telegram-actionable-awooop_action_required-safehash", "kind": "host_recovery", "suggested_mode": "Recover", "accepted": True, "inbox_triggered": True, "stores_raw_response": False, } merged = _merge_outbound_source_envelope_extra( envelope, {"agent99_dispatch_receipt": receipt}, ) assert merged["agent99_dispatch_receipt"] == receipt assert merged["agent99_actionable_outbound"]["incident_id"] == ( "INC-20260710-5700F7" ) assert "incomingFile" not in str(merged) assert "private-path" not in str(merged)