from __future__ import annotations import pytest from audit_core.interface import ( AuditBackend, AuditEvent, EventValidationError, RetentionPolicy, SCHEMA_VERSION_V1ALPHA1, validate_event, ) from audit_core.mock_file_backend import MockFileAuditBackend def test_validate_event_accepts_minimal_event(): event = AuditEvent( source="openbao", action="audit.verify", resource="openbao/openbao-0", outcome="success", ) validate_event(event) @pytest.mark.parametrize( "field_name,value", [ ("source", ""), ("action", " "), ("resource", ""), ("outcome", ""), ], ) def test_validate_event_rejects_empty_required_fields(field_name, value): kwargs = { "source": "openbao", "action": "audit.verify", "resource": "openbao/openbao-0", "outcome": "success", field_name: value, } with pytest.raises(EventValidationError, match=field_name): validate_event(AuditEvent(**kwargs)) def test_validate_event_rejects_unsupported_schema_version(): event = AuditEvent( source="openbao", action="audit.verify", resource="openbao/openbao-0", outcome="success", schema_version="audit-core.event.v99", ) with pytest.raises(EventValidationError, match="unsupported schema_version"): validate_event(event) def test_mock_backend_satisfies_audit_backend_protocol(): backend = MockFileAuditBackend() assert isinstance(backend, AuditBackend) def test_mock_backend_retention_policy_is_development(): backend = MockFileAuditBackend(retention_days=7) policy = backend.retention_policy assert policy == RetentionPolicy( custody_class="development", retention_days=7, immutable=False, tamper_evidence=False, durable=False, ) def test_mock_backend_retention_policy_none_when_cleanup_disabled(): backend = MockFileAuditBackend(retention_days=-1) assert backend.retention_policy.retention_days is None def test_audit_event_record_uses_v1alpha1_schema(): event = AuditEvent( source="audit-core", action="audit_core.contract.smoke", resource="audit-core/tests", outcome="success", ) record = event.as_record() assert record["schema_version"] == SCHEMA_VERSION_V1ALPHA1 assert set(record) == { "schema_version", "event_id", "observed_at", "tenant", "scope", "source", "actor", "action", "resource", "outcome", "reason", "details", } def test_mock_backend_emit_rejects_invalid_event(tmp_path): backend = MockFileAuditBackend(base_dir=tmp_path) event = AuditEvent( source="", action="audit.verify", resource="openbao/openbao-0", outcome="success", ) with pytest.raises(ValueError, match="source must be a non-empty string"): backend.emit(event)