From 4e2e42c89654e4214a3bf134e3e7cf4059288f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=BF=E4=BA=91=E7=A7=8B=E6=9C=88?= <15273589815@163.com> Date: Fri, 11 Sep 2026 13:12:56 +0800 Subject: [PATCH] =?UTF-8?q?test(base):=20=E9=AA=8C=E8=AF=81=E6=9C=80?= =?UTF-8?q?=E5=90=8E=E4=B8=80=E7=A7=8D=E5=B7=A5=E5=85=B7=E6=8B=92=E7=BB=9D?= =?UTF-8?q?=EF=BC=88=E8=A7=92=E8=89=B2=E4=B8=8D=E7=AC=A6=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E5=9B=9B=E7=A7=8D=E5=88=86=E6=94=AF=E5=85=A8=E9=83=A8=E5=AE=9E?= =?UTF-8?q?=E6=B5=8B=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 分支 4 是最难构造的一种,两个前提缺一不可: 1. **工具的角色集合必须比 Agent 的更窄**。Agent 层的 validate_access(base.py:101)会先按 AgentDefinition.allowed_roles 拦截,两者一致时永远进不到工具层的角色校验。所以把 probe_alt 收窄为 ("risk_operator",),而 Agent 仍允许 admin。 2. **调用者必须有工具要求的权限**,否则会先命中权限分支。所以脚本临时给 admin 授 probe:read,验证后撤销。 过程中又修掉一处自己写错的地方:探针的 handle 原先硬编码调用 PROBE_TOOL,导致分支 4 (需要调 probe_alt)与分支 2(需要调白名单之外的那一个)互相干扰——第一次跑出来的结果 是"工具不在当前意图白名单"。改为按消息里的 "alt" 选择要调的工具。 四种分支的实测结果,message 各自独立、指向不同处置动作: - 白名单为空 → 该意图未配置工具白名单 - 工具不在白名单 → 工具不在当前意图白名单 - 缺少工具权限 → 缺少工具权限 - 角色不符 → 角色不能使用工具 目标的另一半也验证了:审计里是完整细节(reason = "角色 ['admin'] 与工具允许的角色 ['risk_operator'] 无交集",并带 tool_name / intent / trace_id),而异常 message 只有 "角色不能使用工具"、不含角色集合。**内部配置只进审计,不进客户可见响应。** 环境复原:生效配置 9 条(与起点一致);sys_permission / sys_role_permission 中 probe:read 的行数为 0。 --- app/service/agent/bootstrap.py | 9 +++++++-- app/service/agent/implementations/platform_probe.py | 7 +++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/service/agent/bootstrap.py b/app/service/agent/bootstrap.py index a25d1f3..269a086 100644 --- a/app/service/agent/bootstrap.py +++ b/app/service/agent/bootstrap.py @@ -189,13 +189,18 @@ def get_agent_factory() -> AgentFactory: required_permission=PROBE_PERMISSION, allowed_roles=("admin",), )) - # 第二个探针工具:让"有白名单但不含该工具"的分支可被构造(见 platform_probe 的说明) + # 第二个探针工具,两个用途: + # ① 让"有白名单但不含该工具"的分支可被构造(见 platform_probe 的说明); + # ② 让**工具层**的"角色不能使用工具"分支可被构造 —— 它的角色集合**比 Agent 的更窄** + # (Agent 允许 admin,本工具只允许 risk_operator)。必须更窄才行:Agent 层的 + # validate_access 会先按 AgentDefinition.allowed_roles 拦截,两者一致时永远进不到 + # 工具层的角色校验。 registry.register(ToolDefinition( name=PROBE_ALT_TOOL, input_model=ProbeEchoArgs, handler=cast(Any, probe_alt_tool), required_permission=PROBE_PERMISSION, - allowed_roles=("admin",), + allowed_roles=("risk_operator",), )) registry.register(ToolDefinition( name="check_suitability", diff --git a/app/service/agent/implementations/platform_probe.py b/app/service/agent/implementations/platform_probe.py index 69a4ea5..646a176 100644 --- a/app/service/agent/implementations/platform_probe.py +++ b/app/service/agent/implementations/platform_probe.py @@ -66,9 +66,12 @@ class PlatformProbeAgent(BaseAgent): ) async def handle(self, request: AgentRequest, context: RequestContext) -> CoreResult: - # 走公共工具链路:探针要验证的正是这条路上的白名单、权限与角色校验。 + # 按消息里的 "alt" 决定调哪个探针工具。两个工具都必须可被指定调用: + # 分支 2(工具不在白名单)要调白名单之外的那个,分支 4(角色不符)要调角色更窄的 + # 那个——硬编码其中一个的话,这两个分支会互相干扰(实测踩到过)。 + tool = PROBE_ALT_TOOL if "alt" in request.message.lower() else PROBE_TOOL output = await self.call_tool( - PROBE_TOOL, + tool, {"note": request.message[:50]}, intent=INTENT_PROBE, context=context,