from types import SimpleNamespace from unittest.mock import AsyncMock import pytest from src.models.approval import RiskLevel from src.services.executor import OperationType from src.services.approval_execution import ApprovalExecutionService class _FakeAutoRepairRepo: def __init__(self) -> None: self.created: list[dict] = [] async def list_by_incident(self, incident_id: str) -> list: return [] async def create(self, **kwargs): self.created.append(kwargs) return SimpleNamespace(id="are-1", **kwargs) @pytest.mark.asyncio async def test_finalize_auto_approved_execution_persists_incident_link(monkeypatch): repo = _FakeAutoRepairRepo() timeline = SimpleNamespace(add_event=AsyncMock()) incident_service = SimpleNamespace(resolve_incident=AsyncMock()) write_km = AsyncMock() run_verify = AsyncMock() monkeypatch.setattr( "src.repositories.audit_log_repository.get_auto_repair_execution_repository", lambda: repo, ) monkeypatch.setattr( "src.services.approval_execution.get_timeline_service", lambda: timeline, ) monkeypatch.setattr( "src.services.incident_service.get_incident_service", lambda: incident_service, ) monkeypatch.setattr( "src.core.feature_flags.aiops_flags", SimpleNamespace(is_sub_flag_enabled=lambda _: True), ) monkeypatch.setattr( ApprovalExecutionService, "write_execution_result_to_km", write_km, ) monkeypatch.setattr( ApprovalExecutionService, "_run_post_execution_verify", run_verify, ) approval = SimpleNamespace( id="11111111-1111-1111-1111-111111111111", incident_id="INC-20260513-001", action="kubectl rollout restart deployment/api -n awoooi-prod", requested_by="auto_approve_rule_engine", matched_playbook_id="pb-auto-001", risk_level=RiskLevel.LOW, ) await ApprovalExecutionService().finalize_auto_approved_execution( approval, success=True, ) assert repo.created == [ { "incident_id": "INC-20260513-001", "playbook_id": "pb-auto-001", "playbook_name": "approval_auto_execute:RESTART_DEPLOYMENT:api", "success": True, "executed_steps": ["kubectl rollout restart deployment/api -n awoooi-prod"], "error_message": None, "triggered_by": "auto_approve_rule_engine", "risk_level": "low", } ] timeline.add_event.assert_awaited_once() write_km.assert_awaited_once_with(approval, True, None) run_verify.assert_awaited_once() assert run_verify.await_args.kwargs["action_taken"].startswith( "auto_repair_playbook:pb-auto-001:RESTART_DEPLOYMENT:api" ) incident_service.resolve_incident.assert_awaited_once_with("INC-20260513-001") @pytest.mark.asyncio async def test_finalize_auto_approved_execution_skips_no_action(monkeypatch): repo = _FakeAutoRepairRepo() write_km = AsyncMock() run_verify = AsyncMock() monkeypatch.setattr( "src.repositories.audit_log_repository.get_auto_repair_execution_repository", lambda: repo, ) monkeypatch.setattr( ApprovalExecutionService, "write_execution_result_to_km", write_km, ) monkeypatch.setattr( ApprovalExecutionService, "_run_post_execution_verify", run_verify, ) approval = SimpleNamespace( id="22222222-2222-2222-2222-222222222222", incident_id="INC-20260513-002", action="NO_ACTION: observe only", requested_by="auto_approve_rule_engine", matched_playbook_id="pb-auto-002", risk_level=RiskLevel.LOW, ) await ApprovalExecutionService().finalize_auto_approved_execution( approval, success=True, ) assert repo.created == [] write_km.assert_not_awaited() run_verify.assert_not_awaited() @pytest.mark.asyncio async def test_record_approved_repair_execution_persists_human_approved_trace(monkeypatch): repo = _FakeAutoRepairRepo() monkeypatch.setattr( "src.repositories.audit_log_repository.get_auto_repair_execution_repository", lambda: repo, ) approval = SimpleNamespace( id="77777777-7777-7777-7777-777777777777", incident_id="INC-20260611-HUMAN", action="kubectl rollout restart deployment/api -n awoooi-prod", requested_by="OpenClaw (ollama_gcp_a)", matched_playbook_id="pb-human-001", risk_level=RiskLevel.MEDIUM, ) await ApprovalExecutionService()._record_approved_repair_execution( approval=approval, success=True, error_message=None, operation_type=OperationType.RESTART_DEPLOYMENT, resource_name="api", namespace="awoooi-prod", duration_ms=1234, ) assert repo.created == [ { "incident_id": "INC-20260611-HUMAN", "playbook_id": "pb-human-001", "playbook_name": "approval_execute:RESTART_DEPLOYMENT:api", "success": True, "executed_steps": [ "kubectl rollout restart deployment/api -n awoooi-prod" ], "error_message": None, "triggered_by": "human_approved", "risk_level": "medium", "execution_time_ms": 1234, } ]