77 lines
2.8 KiB
Python
77 lines
2.8 KiB
Python
"""鉴权拒绝留痕公共出口(手册 P-05 双写;T-04 评审 P1-2 收口)。
|
||||
|
|
|
|||
|
|
背景:越权留痕原本只在 API 层(api/deps._authz_audit)实现,对话 Tool 层
|
|||
|
|
归属被拒时只落 agent_tool_call,全局鉴权审计维度缺失(输入防护台账查不到
|
|||
|
|
对话链路的越权尝试)。本模块把该逻辑下沉到 utils,供两方共用:
|
|||
|
|
- API 层:deps.deny / _authz_audit(403)
|
|||
|
|
- 对话层:tool_service.run_tool 的 blocked 分支(AUTH_403_* 归属拒绝)
|
|||
|
|
|
|||
|
|
放 utils 而非 api 的原因:service 层不得反向依赖 api 层(分层约束)。
|
|||
|
|
|
|||
|
|
降级口径(与 T-02 审计一致):写库失败仅本地 logger.exception,不改变
|
|||
|
|
拒绝语义——对话不因留痕故障中断,生产可切 fail-closed(待决,已登记)。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
from typing import Any, Sequence
|
|||
|
|
|
|||
|
|
from app.utils.trace import current_trace, new_trace
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
# 四 Agent 入口(input_guard_log.agent_type 的 ENUM 仅此四值;platform 跳过)
|
|||
|
|
AGENT_TYPES = ("customer", "advisor", "analyst", "risk")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def record_authz_denial(
|
|||
|
|
risk_repo: Any,
|
|||
|
|
*,
|
|||
|
|
actor_id: str,
|
|||
|
|
code: str,
|
|||
|
|
roles: Sequence[str] | None = None,
|
|||
|
|
customer_id: str | None = None,
|
|||
|
|
agent_type: str = "risk",
|
|||
|
|
trace_id: str | None = None,
|
|||
|
|
) -> None:
|
|||
|
|
"""越权/拒绝留痕:audit_log(authz) + input_guard_log(四 Agent 内)。
|
|||
|
|
|
|||
|
|
agent_type 非四 Agent(如 platform 网关)时只写 audit_log——
|
|||
|
|
input_guard_log.agent_type 是 ENUM,越界写会报数据截断(T-02 同口径)。
|
|||
|
|
"""
|
|||
|
|
trace_id = trace_id or current_trace() or new_trace()
|
|||
|
|
try:
|
|||
|
|
risk_repo.insert_audit_log(
|
|||
|
|
{
|
|||
|
|
"trace_id": trace_id,
|
|||
|
|
"event_type": "authz",
|
|||
|
|
"agent_type": agent_type,
|
|||
|
|
"actor_id": actor_id or "anonymous",
|
|||
|
|
"customer_id": customer_id,
|
|||
|
|
"rule_id": None,
|
|||
|
|
"input_summary": {"roles": list(roles or []), "code": code},
|
|||
|
|
"decision": "forbidden",
|
|||
|
|
"risk_score": None,
|
|||
|
|
"handler_id": None,
|
|||
|
|
"handler_result": None,
|
|||
|
|
"handler_comment": None,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
if agent_type in AGENT_TYPES:
|
|||
|
|
risk_repo.insert_input_guard_log(
|
|||
|
|
trace_id=trace_id,
|
|||
|
|
agent_type=agent_type,
|
|||
|
|
actor_id=actor_id or "anonymous",
|
|||
|
|
guard_type="illegal_param",
|
|||
|
|
action="blocked",
|
|||
|
|
raw_excerpt=code,
|
|||
|
|
)
|
|||
|
|
except Exception:
|
|||
|
|
logger.exception(
|
|||
|
|
"authz audit failed (degraded): code=%s agent=%s actor=%s",
|
|||
|
|
code,
|
|||
|
|
agent_type,
|
|||
|
|
actor_id,
|
|||
|
|
)
|