"""NL2SQL 审计日志适配器,复用现有 audit_log 表。""" from __future__ import annotations import json from sqlalchemy import text _SENSITIVE_KEYS = {"password", "token", "secret", "api_key", "connection", "credential"} def _sanitize(value): """递归移除连接凭据等不应进入审计详情的字段。""" if isinstance(value, dict): return { key: "[REDACTED]" if str(key).lower() in _SENSITIVE_KEYS else _sanitize(item) for key, item in value.items() } if isinstance(value, (list, tuple)): return [_sanitize(item) for item in value] return value async def write_nl2sql_audit( db, *, user_id: int | None, username: str | None, action: str, target: str | None, trace_id: str | None, detail: dict | None = None, status: str = "成功", ) -> None: """写入 NL2SQL 审计事件,调用方负责在失败时降级。""" statement = text( """ INSERT INTO audit_log (user_id, username, module, action, target, detail, trace_id, status) VALUES (:user_id, :username, :module, :action, :target, :detail, :trace_id, :status) """ ) await db.execute( statement, { "user_id": user_id, "username": username, "module": "nl2sql", "action": action, "target": target, "detail": json.dumps(_sanitize(detail or {}), ensure_ascii=False), "trace_id": trace_id, "status": status, }, ) await db.commit() async def write_nl2sql_audit_safely(db, **kwargs) -> bool: """审计写入失败时记录 False,不阻断查询主流程。""" try: await write_nl2sql_audit(db, **kwargs) except Exception: # noqa: BLE001 审计故障不能影响查询能力 return False return True