"""AUDIT-WP-0013-T02: wire compatibility, never live sender admission. Fixture field mapping is pinned in docs/flex-auth-secrets-engine-admission.md. All identities/tokens below exist only in the isolated test receiver. """ from datetime import datetime, timedelta, timezone from urllib.parse import urlencode import pytest from audit_core.ingestion import IngestionApplication from audit_core.senders import SenderIdentity, SenderRegistry from audit_core.sqlite_backend import SQLiteAuditBackend from audit_core.stream_findings import evaluate, NEVER_HEARTBEAT from test_stream_findings import invoke SOURCE = "flex-auth.secrets-engine" RARE = tuple("flex-auth.decision." + name for name in ("deny", "redact", "not_applicable", "audit_only")) CLASSES = RARE + ("flex-auth.decision.allow",) @pytest.fixture def receiver(tmp_path): writer = SenderIdentity(name=SOURCE, tokens=("fixture-writer",), sources=frozenset({SOURCE}), tenants=frozenset({"tenant:platform"}), may_read=False, evidence_kind="load-bearing", heartbeat_classes=tuple((c, 86400) for c in RARE)) reader = SenderIdentity(name="fixture-independent-reader", tokens=("fixture-reader",), sources=frozenset({SOURCE}), tenants=frozenset({"tenant:platform"}), may_write=False, may_read=True) return IngestionApplication(SQLiteAuditBackend(str(tmp_path / "events.db")), SenderRegistry([writer, reader])), writer def envelope(kind, event_id="fixture-event"): # outbox.go Event + event(): no receiver-derived fields or invented sequence. return dict(id=event_id, type=kind, source=SOURCE, subject="openbao/metadata/fixture", tenant="tenant:platform", correlation_id="fixture-decision", occurred_at="2026-10-16T00:00:00.123456789Z", data={"id": "fixture-decision", "effect": kind.rsplit(".", 1)[-1]}) def post(app, event): return invoke(app, "/v1/events", token="fixture-writer", method="POST", payload=event, key=event["id"]) def count(app, since, until, source=SOURCE, tenant="tenant:platform"): return invoke(app, "/v1/reconciliation?" + urlencode(dict(source=source, tenant=tenant, since=since, until=until)), token="fixture-writer") @pytest.mark.parametrize("kind", CLASSES) def test_exact_pin_wire_duplicate_and_independent_readback(receiver, kind): app, _ = receiver event = envelope(kind) assert post(app, event)[0].startswith("202") assert post(app, event)[0].startswith("200") assert post(app, dict(event, subject="changed"))[0].startswith("409") assert invoke(app, "/v1/events/fixture-event", token="fixture-writer")[0].startswith("403") status, retained = invoke(app, "/v1/events/fixture-event", token="fixture-reader") assert status.startswith("200") assert (retained["source"], retained["tenant"], retained["action"]) == (SOURCE, "tenant:platform", kind) assert retained["details"]["data"] == event["data"] accepted = datetime.fromisoformat(retained["accepted_at"]) before, after = ((accepted + timedelta(seconds=n)).isoformat() for n in (-1, 1)) status, counts = count(app, before, after) assert status.startswith("200") assert counts["counts"] == [{"class": kind, "count": 1}] # Acceptance-time [since, until): source occurred_at is deliberately older. assert count(app, before, accepted.isoformat())[1]["counts"] == [] assert count(app, accepted.isoformat(), after)[1]["counts"] == [{"class": kind, "count": 1}] def test_wrong_scope_refusals_are_not_empty_counts(receiver): app, _ = receiver assert post(app, dict(envelope(CLASSES[0]), source="flex-auth.other"))[0].startswith("400") assert post(app, dict(envelope(CLASSES[0]), tenant="tenant:other"))[0].startswith("400") window = ("2026-10-15T00:00:00Z", "2027-01-01T00:00:00Z") assert count(app, *window, source="flex-auth.other")[0].startswith("403") assert count(app, *window, tenant="tenant:other")[0].startswith("403") def test_each_rare_class_must_have_its_own_positive_claim(receiver): app, writer = receiver now = datetime.now(timezone.utc) covered = RARE[0] event = dict(envelope("audit-core.heartbeat"), subject=SOURCE, data={"class": covered, "assertion": "nothing-to-report", "committed": 0, "released_uncommitted": 0}) assert post(app, event)[0].startswith("202") # Source/class finding evaluator; a heartbeat for deny cannot cover redact. findings = evaluate([writer], {(SOURCE, covered): now.isoformat()}, now=now) assert {f.event_class for f in findings} == set(RARE) - {covered} assert all(f.kind == NEVER_HEARTBEAT for f in findings)