67 lines
1.9 KiB
Python
67 lines
1.9 KiB
Python
"""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
|