from __future__ import annotations from pathlib import Path from govoplan_audit.backend.db import models as audit_models # noqa: F401 - populate Audit ORM metadata from govoplan_core.core.access import ( CAPABILITY_AUDIT_RECORDER, CAPABILITY_AUDIT_RETENTION, CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER, ) from govoplan_core.core.module_guards import drop_table_retirement_provider, persistent_table_uninstall_guard from govoplan_core.core.modules import DocumentationTopic, FrontendModule, MigrationSpec, ModuleContext, ModuleManifest from govoplan_core.core.provider_governance import declared_module_architecture from govoplan_core.core.events import CAPABILITY_PLATFORM_EVENT_OUTBOX from govoplan_core.core.views import ViewSurface from govoplan_core.db.base import Base def _route_factory(context: ModuleContext): del context from govoplan_audit.backend.api.v1.routes import router return router def _audit_recorder(context: ModuleContext): del context from govoplan_audit.backend.recording import SqlAuditRecorder return SqlAuditRecorder() def _audit_retention(context: ModuleContext): del context from govoplan_audit.backend.retention import SqlAuditRetentionProvider return SqlAuditRetentionProvider() def _event_outbox(context: ModuleContext): from govoplan_audit.backend.outbox import SqlAuditOutbox return SqlAuditOutbox( max_attempts=getattr( context.settings, "platform_event_outbox_max_attempts", 8, ) ) manifest = ModuleManifest( id="audit", name="Audit", version="0.1.16", required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR), route_factory=_route_factory, documentation=( DocumentationTopic( id="audit.read-authorized-evidence", title="Read authorized audit evidence", summary="Audit history explains who performed a governed action, when it happened, and which resource and trace context were involved.", body="Audit views are permission- and tenant-scoped. Entries are evidence, not editable business records. Sensitive payloads may be redacted while stable resource, actor, outcome, request, run, and trace references remain available for investigation.", documentation_types=("user",), audience=("auditor", "tenant_admin", "operator"), metadata={ "kind": "reference", "help_contexts": [ "audit.admin.system", "audit.admin.tenant", "audit.event-details", ], "surfaces": ["audit.admin.system", "audit.admin.tenant"], }, ), DocumentationTopic( id="audit.recording-retention-and-outbox", title="Operate audit recording and event delivery", summary="Audit owns durable audit records, retention operations, and the transactional platform-event outbox.", body="Modules record bounded audit facts through the Audit capability. Governed platform events are committed to the outbox with retry and delivery metadata so a failed consumer does not erase the originating transaction. Worker dispatch is partitioned by tenant entitlement; an unavailable consumer retains its durable delivery and records an operator-required outcome instead of acknowledging the event. Retention and destructive retirement must preserve the configured evidence and recovery guarantees.", documentation_types=("admin",), audience=("auditor", "security_officer", "operator"), related_modules=("policy", "ops"), metadata={ "kind": "reference", "help_contexts": [ "audit.recording", "audit.retention", "audit.event-outbox", ], }, ), ), frontend=FrontendModule( module_id="audit", package_name="@govoplan/audit-webui", view_surfaces=( ViewSurface(id="audit.admin.system", module_id="audit", kind="section", label="System audit", order=90), ViewSurface(id="audit.admin.tenant", module_id="audit", kind="section", label="Tenant audit", order=100), ), ), migration_spec=MigrationSpec( module_id="audit", metadata=Base.metadata, script_location=str( Path(__file__).with_name("migrations") / "versions" ), retirement_supported=True, retirement_provider=drop_table_retirement_provider( audit_models.AuditLog, audit_models.AuditOutboxDelivery, audit_models.AuditOutboxEvent, label="Audit", ), retirement_notes="Destructive retirement drops audit-owned database tables after the installer captures a database snapshot.", ), uninstall_guard_providers=( persistent_table_uninstall_guard( audit_models.AuditLog, audit_models.AuditOutboxDelivery, audit_models.AuditOutboxEvent, label="Audit", ), ), capability_factories={ CAPABILITY_AUDIT_RECORDER: _audit_recorder, CAPABILITY_AUDIT_RETENTION: _audit_retention, CAPABILITY_PLATFORM_EVENT_OUTBOX: _event_outbox, }, architecture=declared_module_architecture( layer="governance_accountability", kind="governance", maturity="vertical_slice", documentation_ref="docs/AUDIT_TRACE_CONTEXT.md", test_ref="tests/test_audit_module_contract.py", known_limits=("Cross-deployment archival and evidentiary export profiles are not yet reference-ready.",), owned_concepts=("audit record", "audit retention", "transactional event outbox"), non_owned_concepts=("domain record", "policy decision", "external effect"), recovery_docs=("README.md",), security_docs=("docs/AUDIT_TRACE_CONTEXT.md",), operations_docs=("README.md",), ), ) def get_manifest() -> ModuleManifest: return manifest