第二十二章:实验二,给工具加上可验证边界
22.1 三个工具足够暴露核心问题
实验只提供 read_file、write_file 和 check_file。读取返回文本和 SHA-256;写入要求 expected_sha256;检查把文件与预期内容直接比较。没有通用 Shell,因此实验不会让模型任意启动本机命令。
工具注册以严格 schema 字段集合检查输入。错误类型、多余字段和未知名称都会产生 invalid 结果。这个校验发生在路径操作之前,也在任何写入之前。
22.2 先检查资源范围
checked_path() 规范化目标路径,确认它位于工作区之内,并禁止访问第一段为 .harness 的保留位置。测试分别覆盖 .. 逃逸、符号链接指向外部,以及覆盖自身日志。
不要只删除这些测试里的危险字符串,然后宣称工具安全。测试反映的是路径语义;生产实现还需要考虑不可信并发、特殊文件、挂载与权限。普通 Path 检查无法提供强制隔离,本书不会把它称为沙箱。
22.3 将写入与旧状态关联
读取工具返回的哈希用于下一步写入前置条件。若文件已变,write_file 返回 conflict 并保留现有内容。读者可以在读取后人为修改目标,再执行同一写入请求,验证不会无声覆盖。
仍须记住检查和写入不是一个原子操作。实验假设合作的单执行者,并用这一限制说明向生产升级的方向。若多个进程同时写入,需要引入真实的资源锁或更强存储协议,不能仅增加更多哈希字段解决竞态。
22.4 将大结果外置
当工具结果超过 preview_chars,宿主把完整内容写到 .harness/artifacts/,文件名依据内容哈希生成;日志和模型消息只保留预览、定位符与哈希。测试会重新读取附件并核对内容,防止“截断后原文消失”。
这里按字符截取 Python 字符串,不会把 UTF-8 字节从中间切开。但真实模型 token、终端列宽和字节长度不是同一单位。你可以继续增加多字节字符与组合字符样本,分别测试存储、展示和预算。
22.5 运行相关测试
python3 -m unittest discover -s lab/tests -v关注三个观测对象:工具结果状态、目标文件内容和日志类型。只断言返回字符串含有“denied”还不够,还应确认外部文件没有改变。反过来,目标内容正确也不能说明错误路径没有绕过策略,需要同时检查执行证据。
扩展练习:增加 append_file 工具前,先写一份重试与恢复说明。追加操作不是天然幂等,未知结果时重试可能重复写入。能否查到操作 ID,或者能否改写为带版本的替换,将决定你能承诺什么。