"""Audit-trail helper. Single entry point for recording write operations. Callers pass the *active* session so the audit row commits in the same transaction as the mutation it describes (platform security baseline: audit on every write). """ from __future__ import annotations from typing import Any from sqlalchemy.orm import Session from app.common.json_logger import redact_secrets from app.db.models import AuditLog def record_audit( db: Session, *, action: str, actor: str | None = None, actor_id: str | None = None, app_code: str | None = None, entity_type: str | None = None, entity_id: str | None = None, details: dict[str, Any] | None = None, ) -> AuditLog: """Add an :class:`AuditLog` row to ``db`` (not committed here). ``details`` is passed through :func:`redact_secrets` so an accidental secret in the payload is never persisted. """ entry = AuditLog( action=action, actor=actor, actor_id=actor_id, app_code=app_code, entity_type=entity_type, entity_id=entity_id, details=redact_secrets(details or {}), ) db.add(entry) return entry __all__ = ["record_audit"]