fix(aiops): persist emergency intervention traces
This commit is contained in:
@@ -15,6 +15,7 @@ Phase 5 Sprint 5.0-5.1 Callback Dispatcher 單元測試
|
||||
|
||||
import pytest
|
||||
|
||||
from src.services import callback_dispatcher as callback_dispatcher_module
|
||||
from src.services.callback_dispatcher import (
|
||||
dispatch_action,
|
||||
get_action_spec,
|
||||
@@ -269,6 +270,36 @@ class TestInternalActions:
|
||||
assert result.success is True
|
||||
assert "12345" in result.result_text
|
||||
|
||||
async def test_record_authorization_persists_audit_intent(self, monkeypatch):
|
||||
captured = {}
|
||||
|
||||
async def fake_record_authorization_audit(*, spec, params, incident_id, user_id):
|
||||
captured["spec"] = spec
|
||||
captured["params"] = params
|
||||
captured["incident_id"] = incident_id
|
||||
captured["user_id"] = user_id
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(
|
||||
callback_dispatcher_module,
|
||||
"_record_authorization_audit",
|
||||
fake_record_authorization_audit,
|
||||
)
|
||||
|
||||
result = await dispatch_action(
|
||||
action_name="secops_isolate",
|
||||
incident_id="INC-SEC-AUTH",
|
||||
user_id=67890,
|
||||
labels={"instance": "192.168.0.110"},
|
||||
)
|
||||
|
||||
assert result.success is True
|
||||
assert "已寫入審計與時間線" in result.result_text
|
||||
assert captured["spec"].name == "secops_isolate"
|
||||
assert captured["params"]["action"] == "request_network_isolation"
|
||||
assert captured["incident_id"] == "INC-SEC-AUTH"
|
||||
assert captured["user_id"] == 67890
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Sprint 5.2 — MCP 呼叫失敗路徑(Provider 未註冊)
|
||||
|
||||
71
apps/api/tests/test_emergency_escalation_service.py
Normal file
71
apps/api/tests/test_emergency_escalation_service.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from src.services import emergency_escalation_service as service
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_drift_emergency_escalation_writes_aol_and_timeline(monkeypatch):
|
||||
sent_cards = []
|
||||
aol_calls = []
|
||||
timeline_calls = []
|
||||
|
||||
async def fake_dedup(*args, **kwargs):
|
||||
return True
|
||||
|
||||
class FakeGateway:
|
||||
async def send_escalation_card(self, **kwargs):
|
||||
sent_cards.append(kwargs)
|
||||
|
||||
class FakeRepo:
|
||||
async def append(self, *args, **kwargs):
|
||||
aol_calls.append((args, kwargs))
|
||||
return object()
|
||||
|
||||
class FakeTimeline:
|
||||
async def add_event(self, **kwargs):
|
||||
timeline_calls.append(kwargs)
|
||||
return {"id": "timeline-1"}
|
||||
|
||||
monkeypatch.setattr(service, "_dedup_first_send", fake_dedup)
|
||||
monkeypatch.setattr(
|
||||
"src.services.telegram_gateway.get_telegram_gateway",
|
||||
lambda: FakeGateway(),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"src.repositories.alert_operation_log_repository.get_alert_operation_log_repository",
|
||||
lambda: FakeRepo(),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"src.services.approval_db.get_timeline_service",
|
||||
lambda: FakeTimeline(),
|
||||
)
|
||||
|
||||
report = SimpleNamespace(
|
||||
report_id="drift-123",
|
||||
namespace="awoooi-prod",
|
||||
high_count=1,
|
||||
medium_count=2,
|
||||
items=[
|
||||
SimpleNamespace(is_allowlisted=False),
|
||||
SimpleNamespace(is_allowlisted=True),
|
||||
],
|
||||
)
|
||||
interpretation = SimpleNamespace(
|
||||
intent=SimpleNamespace(value="emergency_hotfix"),
|
||||
confidence=0.72,
|
||||
risk="high",
|
||||
)
|
||||
|
||||
await service.escalate_drift_auto_adopt_blocked(
|
||||
report=report,
|
||||
reason="unsafe drift",
|
||||
interpretation=interpretation,
|
||||
)
|
||||
|
||||
assert sent_cards and sent_cards[0]["incident_id"] == "drift-123"
|
||||
assert aol_calls and aol_calls[0][0][0] == "APPROVAL_ESCALATED"
|
||||
assert aol_calls[0][1]["actor"] == "drift_auto_adopt"
|
||||
assert aol_calls[0][1]["context"]["intent"] == "emergency_hotfix"
|
||||
assert timeline_calls and timeline_calls[0]["actor_role"] == "emergency_intervention"
|
||||
Reference in New Issue
Block a user