Spaces:
Running
Running
File size: 2,196 Bytes
c1d887c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | import logging
import traceback
from datetime import datetime, timezone
from typing import Optional, Dict, Any
from firebase_admin import firestore
logger = logging.getLogger("audit_logger")
async def log_audit_event(
action: str,
actor_uid: str,
actor_name: str,
actor_email: str,
actor_role: str,
description: str,
target_type: Optional[str] = None,
target_id: Optional[str] = None,
target_name: Optional[str] = None,
route: Optional[str] = None,
module: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
success: bool = True,
) -> None:
"""
Log an audit event to the accessAuditLogs collection.
Fails safely - will not crash the app if logging fails.
"""
try:
# Sanitize metadata to remove potential secrets
safe_metadata = {}
if metadata:
for k, v in metadata.items():
if "password" in k.lower() or "token" in k.lower() or "secret" in k.lower():
safe_metadata[k] = "[REDACTED]"
else:
safe_metadata[k] = v
db = firestore.client()
log_entry = {
"timestamp": firestore.SERVER_TIMESTAMP,
"action": action,
"actorUid": actor_uid,
"actorName": actor_name,
"actorEmail": actor_email,
"actorRole": actor_role,
"description": description,
"success": success,
}
if target_type is not None:
log_entry["targetType"] = target_type
if target_id is not None:
log_entry["targetId"] = target_id
if target_name is not None:
log_entry["targetName"] = target_name
if route is not None:
log_entry["route"] = route
if module is not None:
log_entry["module"] = module
if safe_metadata:
log_entry["metadata"] = safe_metadata
db.collection("accessAuditLogs").add(log_entry)
except Exception as e:
logger.error(f"Failed to write audit log ({action}): {str(e)}")
# We catch and log, but do not raise, so the main app flow continues
|