fix(cheap): Service 关 workspace 内建工具(Bash/Edit/Glob/Grep/Read/Write)——内建 Write/Bash 旁路六工具写白名单(护城河击穿)+ M3 12+工具面语义重叠混乱税(80009 死圈/80011 失败目录:Bash CWD 混乱/read_file 被串 Read 参数/Edit 连败,签名富化观测实证) (cutover S2 工具面封口)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
daee094c83
commit
a6d5c29ad3
@ -365,6 +365,13 @@ def build_cheap_app(*, title: str = SERVICE_TITLE) -> "FastAPI":
|
||||
from ctx_compress_patch import apply_ctx_compress_patch # noqa: PLC0415
|
||||
apply_ctx_compress_patch()
|
||||
|
||||
# 工具面封口:2.0.2 Service 路把 workspace 内建(Bash/Edit/Glob/Grep/Read/Write)无条件并入 agent
|
||||
# 工具面 → 便宜档六工具写白名单被内建 Write/Bash 旁路 + M3 拿内建 Bash 相对路径死圈(80009/80011
|
||||
# 生产实证)。本进程只跑便宜档 agent,进程内关内建作用域恰好;tier2 服务独立进程不受影响。
|
||||
# 【钉 agentscope==2.0.2,升级必须复核】纪律同 m3_stream_patch(不改 venv 本体)。
|
||||
from ws_builtin_tools_patch import apply_ws_builtin_tools_patch # noqa: PLC0415
|
||||
apply_ws_builtin_tools_patch()
|
||||
|
||||
storage_params = infra_config.redis_params(for_message_bus=False)
|
||||
bus_params = infra_config.redis_params(for_message_bus=True)
|
||||
# cheap 独立 workspace 根(与 tier2 的 _service-workspaces 分开;本线生成产物另落 game-runtime/games/amgen-<id>)。
|
||||
|
||||
45
cheap-worker/tests/test_ws_builtin_tools_patch.py
Normal file
45
cheap-worker/tests/test_ws_builtin_tools_patch.py
Normal file
@ -0,0 +1,45 @@
|
||||
"""ws_builtin_tools_patch 单测:补丁后 LocalWorkspace 内建工具为空、幂等、六工具白名单路不受影响。
|
||||
跑:cheap-worker/.venv/bin/python -m pytest cheap-worker/tests/test_ws_builtin_tools_patch.py -v
|
||||
"""
|
||||
import asyncio
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1])) # → cheap-worker/
|
||||
import _bootstrap # noqa: E402,F401 仅加 sys.path(import 时不取 key、不触网)
|
||||
from ws_builtin_tools_patch import apply_ws_builtin_tools_patch # noqa: E402
|
||||
|
||||
|
||||
def test_patch_empties_builtin_tools(tmp_path):
|
||||
# 补丁前:2.0.2 硬编码六内建(Bash/Edit/Glob/Grep/Read/Write);补丁后:空表。
|
||||
from agentscope.workspace import LocalWorkspace
|
||||
|
||||
apply_ws_builtin_tools_patch()
|
||||
ws = LocalWorkspace(workspace_id="t", workdir=str(tmp_path))
|
||||
assert asyncio.run(ws.list_tools()) == [], "补丁后内建工具面必须为空(写白名单不被旁路)"
|
||||
|
||||
|
||||
def test_patch_idempotent():
|
||||
# 重复 apply 不再包层(标记位短路),且行为不变。
|
||||
from agentscope.workspace import LocalWorkspace
|
||||
|
||||
apply_ws_builtin_tools_patch()
|
||||
fn1 = LocalWorkspace.list_tools
|
||||
apply_ws_builtin_tools_patch()
|
||||
assert LocalWorkspace.list_tools is fn1, "幂等:第二次 apply 不应替换函数对象"
|
||||
|
||||
|
||||
def test_cheap_six_tools_unaffected(tmp_path):
|
||||
# 六工具经 build_toolkit(extra_agent_tools 工厂路)产出,不走 workspace.list_tools —— 补丁不动它。
|
||||
# 提取方式与生产同源(service.app._extract_function_tools,从 Toolkit.tool_groups 收)。
|
||||
apply_ws_builtin_tools_patch()
|
||||
from cheap_toolkit import CheapSession, build_toolkit
|
||||
from service.app import _extract_function_tools
|
||||
|
||||
session = CheapSession(game_id="99999")
|
||||
tools = _extract_function_tools(build_toolkit(session))
|
||||
names = {getattr(t, "name", getattr(getattr(t, "func", None), "__name__", "")) for t in tools}
|
||||
# 至少核心读写与收尾工具在席(名字集按 cheap_toolkit 现约定,松断言防脆)。
|
||||
assert any("read" in n for n in names), f"六工具应含读工具,实际:{names}"
|
||||
assert any("write" in n for n in names), f"六工具应含写工具,实际:{names}"
|
||||
assert any("finish" in n for n in names), f"六工具应含 finish,实际:{names}"
|
||||
54
cheap-worker/ws_builtin_tools_patch.py
Normal file
54
cheap-worker/ws_builtin_tools_patch.py
Normal file
@ -0,0 +1,54 @@
|
||||
"""ws_builtin_tools_patch.py — 便宜档 Service 关 workspace 内建工具(Bash/Edit/Glob/Grep/Read/Write)。
|
||||
|
||||
【坐实根因(2026-07-04 cutover S2 生产实证)】agentscope 2.0.2 Service 路 build_toolkit
|
||||
(app/_service/_toolkit.py:107)把 workspace.list_tools() 的六内建(workspace/_local_workspace.py
|
||||
:670-679 硬编码,无配置开关)无条件并入 agent 工具面,再拼 extra_agent_tools(便宜档六工具)。后果两条:
|
||||
① 写边界击穿:便宜档护城河 = 六工具白名单(write 越界拒 + basename L1_FIXED 拒,I1 fail-closed),
|
||||
内建 Write/Edit/Bash 不走白名单、可写工作区任意路径(Bash 甚至可越 workdir 触仓外)——白名单被旁路;
|
||||
② 失败噪声/死圈:内建 Bash cwd=Service 工作区(非 repo 根),M3 惯性用相对路径 `ls game-runtime/...`
|
||||
连败(80009 四连败触旧版退化签名 stuck 熔断 ¥2.6 作废;80011 复现同款失败指纹,签名富化打印抓获)。
|
||||
CLI 路(cheap_run)从来只有六工具;Service 归并(配置控制面阶段一②)带进了这个面,per-task review
|
||||
未抓到,live 工具失败观测抓获——「跨路径封口」教训再 +1(tech-decisions §12 同款)。
|
||||
|
||||
【修法】cheap Service 进程内 monkeypatch LocalWorkspace.list_tools → 返回 []。作用域正确性:本进程
|
||||
(cheap_service_app)只跑便宜档 agent,进程内全局补丁 = 恰好全体便宜档 agent;tier2 服务是独立进程,
|
||||
不受影响。skills/MCP 装载(list_skills / MCP 发现)不动;Planning/Team/Schedule 工具面收窄另评
|
||||
(工单 h;其成本风险已有 ¥ 两段式硬地板兜上界)。
|
||||
|
||||
【钉 agentscope==2.0.2,升级必须复核此补丁】运行时 monkeypatch,绝不改 venv/site-packages 文件本体。
|
||||
依赖两个 2.0.2 契约:① _toolkit.py build_toolkit 以 `workspace.list_tools()` 为内建来源;
|
||||
② LocalWorkspace.list_tools 为 async 无参方法。升级 agentscope 后必须复核上述两点并重跑
|
||||
tests/test_ws_builtin_tools_patch.py(版本漂移时 apply 响亮 warning、但仍应用——不应用等于开着白名单旁路)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def apply_ws_builtin_tools_patch() -> None:
|
||||
"""把 LocalWorkspace.list_tools 换成恒返回空表(便宜档 Service 进程专用,幂等)。"""
|
||||
import agentscope # noqa: PLC0415
|
||||
from agentscope.workspace import LocalWorkspace # noqa: PLC0415
|
||||
|
||||
ver = getattr(agentscope, "__version__", "?")
|
||||
if ver != "2.0.2":
|
||||
# 版本漂移:响亮告警但仍应用(不应用 = 内建 Bash/Write 旁路写白名单,比契约漂移更危险)。
|
||||
print(
|
||||
f"[ws-builtin-patch] WARNING: agentscope 版本 {ver} != 钉住的 2.0.2,"
|
||||
"list_tools 契约可能已变,升级复核未做——补丁仍应用,请尽快复核。",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
if getattr(LocalWorkspace.list_tools, "_cheap_ws_patched", False):
|
||||
return # 幂等:重复 apply 不再包一层
|
||||
|
||||
async def _no_builtin_tools(self): # noqa: ANN001 —— 与 2.0.2 原签名一致(async 无参)
|
||||
# 便宜档:内建工具全关(写边界只认六工具白名单;根因与作用域见模块头注释)。
|
||||
return []
|
||||
|
||||
_no_builtin_tools._cheap_ws_patched = True # type: ignore[attr-defined]
|
||||
LocalWorkspace.list_tools = _no_builtin_tools
|
||||
print(
|
||||
"[ws-builtin-patch] 已关 workspace 内建工具(Bash/Edit/Glob/Grep/Read/Write)——"
|
||||
"便宜档写边界只认六工具白名单(钉 2.0.2,升级必须复核)。",
|
||||
flush=True,
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user