fix: 审计覆盖 + 备份过滤 + unknown action 保留
- unknown action 在 detail 保留原始值 - backup 支持过滤 + limit 上限(防大响应) - 提取 _build_filter 公共过滤函数
This commit is contained in:
parent
55e4ce30b8
commit
d38e26ffff
@ -41,6 +41,8 @@ async def audit_log(sor, user_id: str, username: str, action: str,
|
||||
审计写入失败不应阻断主流程,返回 False 由调用方决定是否处理。
|
||||
"""
|
||||
if action not in VALID_ACTIONS:
|
||||
# 保留原始 action,避免排查时丢失是哪个模块拼错了
|
||||
detail = (detail or "") + " [原始action:" + str(action) + "]"
|
||||
action = "unknown"
|
||||
try:
|
||||
from appPublic.uniqueID import getID
|
||||
@ -87,8 +89,8 @@ def _row_to_dict(row) -> dict:
|
||||
return d
|
||||
|
||||
|
||||
async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int = 60):
|
||||
"""查询审计日志(分页,DataGrid 兼容),返回 {rows, total}。"""
|
||||
def _build_filter(filters: dict):
|
||||
"""构造 WHERE 子句 + 参数(list/backup/delete 共用)。返回 (wsql, ns)。"""
|
||||
filters = filters or {}
|
||||
where = []
|
||||
ns = {}
|
||||
@ -108,6 +110,12 @@ async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int =
|
||||
where.append("created_at<=${t}$")
|
||||
ns["t"] = filters["to"]
|
||||
wsql = (" WHERE " + " AND ".join(where)) if where else ""
|
||||
return wsql, ns
|
||||
|
||||
|
||||
async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int = 60):
|
||||
"""查询审计日志(分页,DataGrid 兼容),返回 {rows, total}。"""
|
||||
wsql, ns = _build_filter(filters)
|
||||
try:
|
||||
page = max(1, int(page or 1))
|
||||
except (ValueError, TypeError):
|
||||
@ -127,11 +135,16 @@ async def list_audit_logs(sor, filters: dict = None, page: int = 1, rows: int =
|
||||
|
||||
|
||||
async def backup_audit_logs(sor, user_id: str, username: str, filters: dict = None,
|
||||
client_ip: str = "") -> dict:
|
||||
"""导出审计日志(仅 owner.audit),返回 JSON 内容供下载。"""
|
||||
# 查最近 10000 条(备份上限,避免一次拉全表拖垮内存)
|
||||
limit: int = 10000, client_ip: str = "") -> dict:
|
||||
"""导出审计日志(仅 owner.audit),支持过滤 + 上限,返回 JSON 内容供下载。"""
|
||||
wsql, ns = _build_filter(filters)
|
||||
try:
|
||||
limit = max(1, min(int(limit or 10000), 50000))
|
||||
except (ValueError, TypeError):
|
||||
limit = 10000
|
||||
recs = await sor.sqlExe(
|
||||
"SELECT * FROM sd_audit_logs ORDER BY created_at DESC LIMIT 10000", {})
|
||||
"SELECT * FROM sd_audit_logs" + wsql + " ORDER BY created_at DESC LIMIT "
|
||||
+ str(limit), ns)
|
||||
rows = [_row_to_dict(r) for r in recs]
|
||||
# 备份操作本身也审计
|
||||
await audit_log(sor, user_id, username, "audit_backup",
|
||||
|
||||
@ -51,9 +51,17 @@ if action == 'list':
|
||||
return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False)
|
||||
|
||||
elif action == 'backup':
|
||||
bfilters = {
|
||||
'user_id': (params_kw or {}).get('user_id', ''),
|
||||
'username': (params_kw or {}).get('username', ''),
|
||||
'action': (params_kw or {}).get('act', ''),
|
||||
'from': (params_kw or {}).get('from', ''),
|
||||
'to': (params_kw or {}).get('to', ''),
|
||||
}
|
||||
blimit = (params_kw or {}).get('limit', 10000)
|
||||
try:
|
||||
async with get_sor_context(request._run_ns, 'pipeline') as sor:
|
||||
r = await backup_audit_logs(sor, user_id, username, None, client_ip)
|
||||
r = await backup_audit_logs(sor, user_id, username, bfilters, blimit, client_ip)
|
||||
return json.dumps(r, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
return json.dumps({'ok': False, 'error': str(e)}, ensure_ascii=False)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user