inital commit
This commit is contained in:
91
server/app/audit/logging.py
Normal file
91
server/app/audit/logging.py
Normal file
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.auth.dependencies import ApiPrincipal
|
||||
from app.db.models import AuditLog
|
||||
|
||||
|
||||
SENSITIVE_DETAIL_KEYS = {
|
||||
"password",
|
||||
"smtp_password",
|
||||
"imap_password",
|
||||
"secret",
|
||||
"api_key",
|
||||
"token",
|
||||
}
|
||||
|
||||
|
||||
def _sanitize_details(value: Any) -> Any:
|
||||
if isinstance(value, dict):
|
||||
sanitized: dict[str, Any] = {}
|
||||
for key, item in value.items():
|
||||
if str(key).lower() in SENSITIVE_DETAIL_KEYS:
|
||||
sanitized[key] = "<redacted>"
|
||||
else:
|
||||
sanitized[key] = _sanitize_details(item)
|
||||
return sanitized
|
||||
if isinstance(value, list):
|
||||
return [_sanitize_details(item) for item in value]
|
||||
return value
|
||||
|
||||
|
||||
def audit_event(
|
||||
session: Session,
|
||||
*,
|
||||
tenant_id: str | None,
|
||||
action: str,
|
||||
user_id: str | None = None,
|
||||
api_key_id: str | None = None,
|
||||
object_type: str | None = None,
|
||||
object_id: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
commit: bool = False,
|
||||
) -> AuditLog:
|
||||
"""Persist one audit event.
|
||||
|
||||
The function deliberately accepts primitive IDs so it can be used from API
|
||||
handlers, CLI commands and worker code without coupling the lower-level
|
||||
services to FastAPI request objects.
|
||||
"""
|
||||
|
||||
item = AuditLog(
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
api_key_id=api_key_id,
|
||||
action=action,
|
||||
object_type=object_type,
|
||||
object_id=object_id,
|
||||
details=_sanitize_details(details or {}),
|
||||
)
|
||||
session.add(item)
|
||||
if commit:
|
||||
session.commit()
|
||||
else:
|
||||
session.flush()
|
||||
return item
|
||||
|
||||
|
||||
def audit_from_principal(
|
||||
session: Session,
|
||||
principal: ApiPrincipal,
|
||||
*,
|
||||
action: str,
|
||||
object_type: str | None = None,
|
||||
object_id: str | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
commit: bool = False,
|
||||
) -> AuditLog:
|
||||
return audit_event(
|
||||
session,
|
||||
tenant_id=principal.tenant_id,
|
||||
user_id=principal.user.id,
|
||||
api_key_id=principal.api_key.id,
|
||||
action=action,
|
||||
object_type=object_type,
|
||||
object_id=object_id,
|
||||
details=details,
|
||||
commit=commit,
|
||||
)
|
||||
Reference in New Issue
Block a user