from __future__ import annotations import json import time from datetime import datetime, UTC from yuxi.utils.logging_config import logger class SecurityAuditLogger: _audit_logger = logger _output_format: str = "text" @classmethod def set_output_format(cls, fmt: str) -> None: cls._output_format = fmt @classmethod def _log(cls, event_type: str, details: dict) -> None: entry = { "timestamp": datetime.now(UTC).isoformat(), "event_type": event_type, "unix_ts": time.time(), **details, } if cls._output_format == "json": cls._audit_logger.warning(f"[SECURITY_AUDIT] {json.dumps(entry, ensure_ascii=False)}") else: cls._audit_logger.warning(f"[SECURITY_AUDIT] {entry}") @classmethod def log_dm_policy_blocked(cls, user_id: str, reason: str, policy: str) -> None: cls._log( "dm_policy_blocked", {"user_id": user_id, "reason": reason, "dm_policy": policy}, ) @classmethod def log_group_access_blocked(cls, group_id: str, user_id: str, reason: str) -> None: cls._log( "group_access_blocked", {"group_id": group_id, "user_id": user_id, "reason": reason}, ) @classmethod def log_mention_required_blocked(cls, group_id: str, user_id: str) -> None: cls._log( "mention_required_blocked", {"group_id": group_id, "user_id": user_id, "reason": "missing_mention"}, ) @classmethod def log_unauthorized_access(cls, user_id: str, resource: str, detail: str = "") -> None: cls._log( "unauthorized_access", {"user_id": user_id, "resource": resource, "detail": detail}, ) @classmethod def log_rate_limit_exceeded(cls, user_id: str, limit_type: str) -> None: cls._log( "rate_limit_exceeded", {"user_id": user_id, "limit_type": limit_type}, ) @classmethod def log_circuit_breaker_open(cls, user_id: str = "", reason: str = "") -> None: cls._log( "circuit_breaker_open", {"user_id": user_id, "reason": reason}, ) @classmethod def log_auth_failure(cls, account_id: str, reason: str) -> None: cls._log( "auth_failure", {"account_id": account_id, "reason": reason}, )