from __future__ import annotations from types import SimpleNamespace from unittest.mock import AsyncMock import pytest from src.api.v1 import webhooks from src.services.awooop_ansible_audit_service import ( _catalog_hints, build_ansible_decision_audit_payload, build_ansible_truth, ) from src.services.controlled_alert_target_router import ( build_controlled_recovery_handoff, build_controlled_recovery_promotion_contract, resolve_controlled_alert_target, ) def _cold_start_incident() -> dict: return { "incident_id": "INC-20260711-11C751", "project_id": "awoooi", "alertname": "ColdStartGateBlocked", "alert_category": "general", "affected_services": ["cold-start-gate"], "signals": [ { "alert_name": "ColdStartGateBlocked", "labels": { "component": "cold-start-gate", "namespace": "default", "host": "110", }, "annotations": { "summary": ( "full-stack cold-start recovery blocked; backup and " "Docker evidence must be checked" ) }, } ], } def test_normalizer_separates_source_namespace_from_execution_domain() -> None: route = resolve_controlled_alert_target( alertname="ColdStartGateBlocked", target_resource="cold-start-gate", namespace="default", ) assert route is not None assert route["source_namespace"] == "default" assert route["normalized_execution_namespace"] == "host_recovery" assert route["kubernetes_namespace_applicable"] is False assert route["executor"] == "Agent99" assert route["runtime_execution_authorized"] is False assert resolve_controlled_alert_target( alertname="SentryRpsZero", target_resource="sentry", namespace="awoooi-prod", ) is None def test_cold_start_contract_requires_same_run_receipts_before_closure() -> None: contract = build_controlled_recovery_promotion_contract( alertname="ColdStartGateBlocked", target_resource="cold-start-gate", namespace="default", incident_id="INC-20260711-11C751", ) assert contract is not None fields = {row["field"]: row for row in contract["fields"]} assert fields["target_selector"]["status"] == "ready" assert fields["controlled_apply_route"]["status"] == "ready" for required in ( "source_sensor_receipt", "check_mode_receipt", "dispatch_receipt", "post_apply_verifier", "incident_closure_receipt", "telegram_receipt", "km_writeback", "playbook_trust_writeback", ): assert fields[required]["status"] == "pending" assert contract["runtime_execution_authorized"] is False assert contract["owner_review_required"] is False assert contract["needs_human"] is False assert contract["completion_status"] == "partial" def test_cold_start_is_excluded_from_generic_ansible_keyword_catalog() -> None: hints = _catalog_hints(_cold_start_incident(), None) assert hints["match_mode"] == "domain_controlled_executor_route_v1" assert hints["decision_effect"] == "delegate_to_domain_executor" assert hints["candidates"] == [] assert hints["controlled_executor"]["executor"] == "Agent99" assert "ansible:110-devops" in hints["unmatched_catalog_ids"] assert "ansible:188-momo-backup-user" in hints["unmatched_catalog_ids"] truth = build_ansible_truth([], incident=_cold_start_incident(), drift=None) assert truth["not_used_reason"] == "non_kubernetes_control_plane_route" assert truth["candidate_catalog"]["controlled_executor"]["route_id"] == ( "agent99_recover_after_owner_review" ) def test_cold_start_does_not_emit_ansible_candidate_audit() -> None: incident = SimpleNamespace( incident_id="INC-20260711-11C751", project_id="awoooi", alertname="ColdStartGateBlocked", alert_category="general", notification_type="TYPE-3", severity=SimpleNamespace(value="P3"), affected_services=["cold-start-gate"], signals=[ SimpleNamespace( alert_name="ColdStartGateBlocked", labels={"component": "cold-start-gate", "namespace": "default"}, annotations={"summary": "full-stack cold-start blocked"}, ) ], ) payload = build_ansible_decision_audit_payload( incident=incident, proposal_data={"source": "test", "risk_level": "low"}, decision_path="alert_webhook_controlled_router", not_used_reason="test", ) assert payload is None def test_handoff_stays_partial_until_dispatch_verifier_and_learning() -> None: handoff = build_controlled_recovery_handoff( alertname="custom", target_resource="cold-start-gate", namespace="default", incident_id="INC-20260711-11C751", ) assert handoff is not None assert handoff["single_writer_executor"] == "Agent99" assert handoff["queued"] is False assert handoff["side_effect_performed"] is False assert handoff["runtime_execution_authorized"] is False assert handoff["owner_review_required"] is False assert handoff["needs_human"] is False assert handoff["active_blockers"] == [ "agent99_dispatch_receipt_readback_pending", "post_apply_verifier_missing", "km_playbook_writeback_missing", ] @pytest.mark.asyncio async def test_webhook_router_never_queues_generic_ansible_for_cold_start( monkeypatch: pytest.MonkeyPatch, ) -> None: queue = AsyncMock(side_effect=AssertionError("generic Ansible must not be queued")) append = AsyncMock() incident_lookup = AsyncMock(side_effect=AssertionError("incident lookup not needed")) bridge = AsyncMock( return_value={ "status": "dispatched", "dispatchPerformed": True, "identity": { "run_id": "7cf8fdf7-0966-5ac6-95b2-09e32808b248", "trace_id": "00-11111111111111111111111111111111-2222222222222222-01", "work_item_id": "agent99-dispatch:awoooi:INC-20260711-11C751:recovery", "idempotency_key": "agent99-controlled:stable-key", }, "dispatchReceipt": { "status": "accepted_inbox_triggered", "accepted": True, "inbox_triggered": True, }, "correlatedReceipt": { "status": "dispatch_accepted_verifier_pending", "receipt_persisted": True, "runtime_execution_authorized": False, "runtime_closure_verified": False, "verifier": {"status": "pending"}, "learning_writeback": {"status": "pending_verifier"}, }, } ) monkeypatch.setattr( "src.jobs.awooop_ansible_candidate_backfill_job.enqueue_ai_decision_ansible_candidate", queue, ) monkeypatch.setattr( "src.repositories.alert_operation_log_repository.get_alert_operation_log_repository", lambda: SimpleNamespace(append=append), ) monkeypatch.setattr( webhooks, "get_incident_service", lambda: SimpleNamespace(get_from_working_memory=incident_lookup), ) monkeypatch.setattr(webhooks, "bridge_alertmanager_to_agent99", bridge) handoff = await webhooks._try_auto_repair_background( incident_id="INC-20260711-11C751", approval_id="00000000-0000-0000-0000-000000000751", alert_type="custom", target_resource="cold-start-gate", namespace="default", risk_level="low", source_alert_id="alert-11c751", source_alertname="ColdStartGateBlocked", source_fingerprint="source-fingerprint", ) queue.assert_not_awaited() incident_lookup.assert_not_awaited() bridge.assert_awaited_once() assert handoff["single_writer_executor"] == "Agent99" assert handoff["execution_priority"] == 30 assert handoff["queued"] is True assert handoff["runtime_execution_authorized"] is False assert handoff["runtime_closure_verified"] is False assert handoff["automation_run_id"] == ( "7cf8fdf7-0966-5ac6-95b2-09e32808b248" ) append.assert_awaited_once() receipt = append.await_args.kwargs assert receipt["action_detail"] == "controlled_check_mode_queued" assert receipt["success"] is True assert receipt["context"]["safe_next_action"] == ( "run_independent_cold_start_verifier_then_km_playbook_writeback" ) assert receipt["context"]["runtime_closure_verified"] is False