| """ |
| Append-only audit log for sensitive operations (identity resolution, |
| reverse image search, gallery mutations). |
| |
| Format: one JSON object per line (JSONL). |
| """ |
|
|
| from __future__ import annotations |
|
|
| import json |
| from datetime import datetime, timezone |
| from pathlib import Path |
| from typing import Any |
|
|
| from config import settings |
| from loguru import logger |
|
|
|
|
| def audit_log( |
| action: str, |
| actor: str = "anonymous", |
| target: str | None = None, |
| outcome: str = "success", |
| details: dict[str, Any] | None = None, |
| ) -> None: |
| """Append a structured audit entry.""" |
| entry = { |
| "timestamp": datetime.now(timezone.utc).isoformat(), |
| "action": action, |
| "actor": actor, |
| "target": target, |
| "outcome": outcome, |
| "details": details or {}, |
| } |
| path = Path(settings.audit_log_path) |
| path.parent.mkdir(parents=True, exist_ok=True) |
| try: |
| with open(path, "a", encoding="utf-8") as f: |
| f.write(json.dumps(entry, ensure_ascii=False) + "\n") |
| except OSError as e: |
| logger.warning(f"Audit log write failed: {e}") |
|
|