From 1eb8946552cd561b572edff4aa806b54f5fbc322 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:11:30 +0800 Subject: [PATCH] =?UTF-8?q?test(base):=20=E7=AB=AF=E5=88=B0=E7=AB=AF?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=B7=A5=E5=85=B7=E6=8B=92=E7=BB=9D=E7=9A=84?= =?UTF-8?q?=E5=88=86=E6=94=AF=202=20=E4=B8=8E=203=EF=BC=8C=E6=8E=A2?= =?UTF-8?q?=E9=92=88=E5=8A=A0=E7=AC=AC=E4=BA=8C=E4=B8=AA=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 接上一轮(分支 1 已验证)。本轮用只读探针触发另外两种拒绝: - 分支 2「工具不在当前意图白名单」:发布白名单 ["probe_alt"] 但 Agent 调 probe_echo。 这一步能做,正是因为给探针加了第二个工具 —— governance.resolve 取的是 「发布白名单 ∩ 代码声明的 allowed_tools」,配置**只能缩小不能放大**,所以单个工具的 Agent 永远构造不出"有白名单但不含该工具"的场景。这是做端到端时才撞到的结构性约束, platform_probe.py 里已注明。 - 分支 3「缺少工具权限」:发布白名单 ["probe_echo"],工具可用了,但 admin 角色并没有 probe:read 这条权限,天然命中权限分支,不需要动 RBAC。 实测:两种拒绝的 stderr 分别为「工具不在当前意图白名单」与「缺少工具权限」, 运行状态均为 failed / AGENT_PERMISSION_DENIED;生效配置已恢复(终点 9 条,与起点一致)。 顺带发现分支 4 的结构性障碍(下一步处理):Agent 层的 validate_access 会先按 AgentDefinition.allowed_roles 拦截,所以要在**工具层**触发"角色不能使用工具", 必须让工具的角色集合比 Agent 的更窄 —— 探针目前两者的角色集合相同,触发不到。 --- app/service/agent/bootstrap.py | 10 ++++++++++ app/service/agent/implementations/platform_probe.py | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/service/agent/bootstrap.py b/app/service/agent/bootstrap.py index b0898f0..a25d1f3 100644 --- a/app/service/agent/bootstrap.py +++ b/app/service/agent/bootstrap.py @@ -18,10 +18,12 @@ from app.service.agent.governance import PlatformGovernance from app.service.agent.implementations.customer_service import CustomerServiceAgent from app.service.agent.implementations.fund_query_demo import FundQueryDemoAgent from app.service.agent.implementations.platform_probe import ( + PROBE_ALT_TOOL, PROBE_PERMISSION, PROBE_TOOL, PlatformProbeAgent, ProbeEchoArgs, + probe_alt_tool, probe_echo_tool, ) from app.service.agent.implementations.risk_agent import RiskAgent @@ -187,6 +189,14 @@ def get_agent_factory() -> AgentFactory: required_permission=PROBE_PERMISSION, allowed_roles=("admin",), )) + # 第二个探针工具:让"有白名单但不含该工具"的分支可被构造(见 platform_probe 的说明) + registry.register(ToolDefinition( + name=PROBE_ALT_TOOL, + input_model=ProbeEchoArgs, + handler=cast(Any, probe_alt_tool), + required_permission=PROBE_PERMISSION, + allowed_roles=("admin",), + )) registry.register(ToolDefinition( name="check_suitability", input_model=SuitabilityToolInput, diff --git a/app/service/agent/implementations/platform_probe.py b/app/service/agent/implementations/platform_probe.py index 5dc2b33..69a4ea5 100644 --- a/app/service/agent/implementations/platform_probe.py +++ b/app/service/agent/implementations/platform_probe.py @@ -26,6 +26,11 @@ from app.service.agent.base import BaseAgent AGENT_TYPE = "platform_probe" INTENT_PROBE = "probe" PROBE_TOOL = "probe_echo" +# 第二个探针工具。**存在的唯一理由**:让"工具不在白名单"这一分支可被触发。 +# `governance.resolve` 取的是「发布白名单 ∩ 代码声明的 allowed_tools」,配置**只能缩小 +# 不能放大**;所以 Agent 只有一个工具时,白名单要么为空、要么正好包含它, +# 永远构造不出"有白名单、但不含被调用的那个工具"的场景——这是我做端到端验证时撞到的。 +PROBE_ALT_TOOL = "probe_alt" PROBE_PERMISSION = "probe:read" @@ -43,6 +48,11 @@ async def probe_echo_tool(arguments: BaseModel, context: RequestContext) -> dict return {"echo": note, "trace_id": context.trace_id} +async def probe_alt_tool(arguments: BaseModel, context: RequestContext) -> dict[str, Any]: + """备用探针工具:只为让"工具不在白名单"的分支可被构造,与 probe_echo 同样只读。""" + return {"alt": True, "trace_id": context.trace_id} + + class PlatformProbeAgent(BaseAgent): """基座探针:只用于验证工具链路的拒绝行为,不承载任何业务。""" @@ -51,7 +61,7 @@ class PlatformProbeAgent(BaseAgent): version="1.0.0", allowed_roles=("admin",), allowed_portals=("api",), - allowed_tools=(PROBE_TOOL,), + allowed_tools=(PROBE_TOOL, PROBE_ALT_TOOL), supported_intents=(INTENT_PROBE,), )