from __future__ import annotations from typing import Any import pytest from src.services import mcp_audit_service class _FakeDb: def __init__(self) -> None: self.executed_params: list[dict[str, Any]] = [] self.statements: list[str] = [] async def execute(self, _statement: Any, params: dict[str, Any]) -> None: self.statements.append(str(_statement)) self.executed_params.append(params) class _FakeDbContext: def __init__(self, db: _FakeDb) -> None: self.db = db async def __aenter__(self) -> _FakeDb: return self.db async def __aexit__(self, *_args: Any) -> None: return None @pytest.mark.asyncio async def test_record_mcp_call_normalizes_long_session_id(monkeypatch) -> None: db = _FakeDb() monkeypatch.setattr( mcp_audit_service, "get_db_context", lambda _project_id=None: _FakeDbContext(db), ) await mcp_audit_service.record_mcp_call( mcp_server="k8s_provider", tool_name="get_pods", input_params={ "_mcp_audit": { "session_id": "incident:INC-20260505-E8033A:pre_decision", "agent_role": "pre_decision_investigator", }, }, output_result={"ok": True}, duration_ms=12, success=True, error_message=None, ) audit_insert_params = db.executed_params[0] assert audit_insert_params["session_id"] == "inc:INC-20260505-E8033A:pre" assert len(audit_insert_params["session_id"]) <= 36 @pytest.mark.asyncio async def test_record_mcp_call_bridges_legacy_direct_path_to_awooop_audit(monkeypatch) -> None: db = _FakeDb() monkeypatch.setattr( mcp_audit_service, "get_db_context", lambda _project_id=None: _FakeDbContext(db), ) await mcp_audit_service.record_mcp_call( mcp_server="ssh_host", tool_name="ssh_get_docker_logs", input_params={ "_mcp_audit": { "session_id": "incident:INC-20260512-B6C589:pre_decision", "incident_id": "INC-20260512-B6C589", "agent_role": "pre_decision_investigator", "gateway_path": "legacy_direct_provider", }, "project_id": "awoooi", "secret": "must-not-leak", }, output_result={"ok": True}, duration_ms=37, success=True, error_message=None, ) bridge_params = db.executed_params[2] assert "INSERT INTO awooop_mcp_gateway_audit" in db.statements[2] assert bridge_params["project_id"] == "awoooi" assert bridge_params["run_id"] is None assert bridge_params["trace_id"] == "INC-20260512-B6C589" assert bridge_params["agent_id"] == "pre_decision_investigator" assert bridge_params["tool_name"] == "legacy:ssh_host:ssh_get_docker_logs" assert bridge_params["result_status"] == "success" assert bridge_params["block_reason"] is None assert bridge_params["latency_ms"] == 37 assert "legacy_mcp_bridge_v1" in bridge_params["gate_result"] assert "legacy direct provider path; bridge audit only" in bridge_params["gate_result"] @pytest.mark.asyncio async def test_record_mcp_call_skips_bridge_for_first_class_awooop_gateway(monkeypatch) -> None: db = _FakeDb() monkeypatch.setattr( mcp_audit_service, "get_db_context", lambda _project_id=None: _FakeDbContext(db), ) await mcp_audit_service.record_mcp_call( mcp_server="kubernetes", tool_name="kubectl_get", input_params={ "_mcp_audit": { "project_id": "awoooi", "run_id": "9d769d02-a036-4c9d-b659-5656c8d1bd5d", "agent_id": "openclaw-sre", "trace_id": "trace-1", "gateway_path": "awooop_mcp_gateway", }, }, output_result={"items": []}, duration_ms=18, success=True, error_message=None, ) assert len(db.executed_params) == 2 assert all("awooop_mcp_gateway_audit" not in statement for statement in db.statements)