From bffd2ec7018183afa6f16a2d7a84c7b5f4aca518 Mon Sep 17 00:00:00 2001 From: Chaim Date: Sat, 30 May 2026 21:27:54 +0000 Subject: [PATCH] test(audit): failing tests for audit-trail + provenance (FU-7) --- mcp-server/tests/test_audit_provenance.py | 74 +++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 mcp-server/tests/test_audit_provenance.py diff --git a/mcp-server/tests/test_audit_provenance.py b/mcp-server/tests/test_audit_provenance.py new file mode 100644 index 0000000..f1c8073 --- /dev/null +++ b/mcp-server/tests/test_audit_provenance.py @@ -0,0 +1,74 @@ +"""FU-7: audit-trail + provenance (offline, monkeypatched I/O).""" +from __future__ import annotations + +import asyncio +from uuid import uuid4 + +import pytest + +from legal_mcp.services import audit, db + + +def _run(coro): + return asyncio.run(coro) + + +# ── GAP-18: log_action_safe is non-fatal ─────────────────────────────── +def test_log_action_safe_swallows_db_error(monkeypatch): + async def _boom(*a, **k): + raise RuntimeError("db down") + monkeypatch.setattr(audit, "log_action", _boom) + # must NOT raise + _run(audit.log_action_safe("write_block", details={"x": 1})) + + +def test_log_action_safe_forwards_args(monkeypatch): + seen = {} + async def _capture(action, case_id=None, document_id=None, details=None, user="system"): + seen.update(action=action, details=details) + monkeypatch.setattr(audit, "log_action", _capture) + _run(audit.log_action_safe("export_docx", details={"path": "/x"})) + assert seen["action"] == "export_docx" and seen["details"] == {"path": "/x"} + + +# ── GAP-20: structural citation resolver ──────────────────────────────── +def test_resolve_citation_case_law_ids_splits(monkeypatch): + good = uuid4() + bad = uuid4() + + class _Conn: + async def fetchval(self, q, cid): + return cid == good + async def __aenter__(self): return self + async def __aexit__(self, *a): return False + + class _Pool: + def acquire(self): return _Conn() + + async def _pool(): + return _Pool() + monkeypatch.setattr(db, "get_pool", _pool) + + out = _run(db.resolve_citation_case_law_ids([good, bad])) + assert good in out["resolved"] and bad in out["unresolved"] + + +# ── GAP-17: blocks_stale helper ──────────────────────────────────────── +def test_mark_blocks_stale_executes_update(monkeypatch): + seen = {} + + class _Conn: + async def execute(self, q, *a): + seen["q"] = q; seen["args"] = a + async def __aenter__(self): return self + async def __aexit__(self, *a): return False + + class _Pool: + def acquire(self): return _Conn() + + async def _pool(): return _Pool() + monkeypatch.setattr(db, "get_pool", _pool) + + cid = uuid4() + _run(db.mark_blocks_stale(cid, True)) + assert "blocks_stale" in seen["q"] and seen["args"][0] is True and seen["args"][1] == cid