运行编码 Agent 前,先声明权限边界
提出用可审查的沙箱清单声明 Agent 的文件读写、网络、密钥、预算和产物权限,并通过运行时检查落实约束。文章指出,提示词无法可靠阻止安装脚本、测试或依赖钩子读取环境变量及越界访问。
AI 深度解读
AI 编程 Agent 接到一个改文档的小任务,也可能顺手执行脚本、安装依赖、读取环境变量。作者主张:在代码运行前,用一份机器可读的 sandbox manifest,把文件、网络、凭证、资源和清理规则写清楚,再交给运行时强制执行。
这篇的价值在于给出了能讨论、能审查的配置骨架。但它是一套设计建议,没有实测效果或对照数据。对正在接入 AI 编程的团队,更值得借鉴的是权限拆分方法,以及配置如何真正落到执行环境。
为什么提醒 Agent 小心,还不够
提示词可以约束 Agent 的计划,却管不住它启动的所有进程。安装脚本可能读取继承的环境变量,测试可能向工作目录之外写文件,依赖钩子也可能自行发起网络请求。这些动作未必经过模型再次判断。
所以,执行边界必须由 Agent 进程之外的系统落实。
作者提出的 manifest,就是每次任务的权限合同:允许读写哪些路径、连接哪些服务、取得什么凭证、占用多少资源、留下什么产物,以及何时销毁环境。
这里有一个实用的设计选择:描述能力,少绑定实现。例如 repo_read、artifact_write,表达的是读取仓库、写出产物的权限;底层适配器再将它们转换成挂载、策略和防火墙规则。从本地容器迁移到远程沙箱时,任务意图仍然成立。
Docker 可以承载其中一部分隔离,但容器仍可能继承环境变量、SSH agent、特权 socket 和宽泛的网络权限。「已经放进容器」无法回答这些权限是否必要。
一份配置怎样把权限变成可审查的东西
作者给出一个用于更新 API 文档、运行单元测试的最小配置。它明确了输入目录、可写目录、资源上限和清理规则:
version: 1
run:
purpose: "Update API documentation and run unit tests"
max_duration_seconds: 900
resources:
cpu: 2
memory_mb: 4096
filesystem:
mounts:
- source: repo
target: /workspace
mode: read_only
- source: run-scratch
target: /scratch
mode: read_write
writable_paths:
- /scratch
forbidden_paths:
- /home
- /root
- /var/run/docker.sock
network:
default: deny
allow:
- host: registry.npmjs.org
ports: [443]
identity:
environment: allowlist
capabilities: []
cleanup:
delete_workspace: true
retain_artifacts_hours: 24
重点看 mode: read_only:仓库在这里是输入,Agent 只能向 /scratch 写入。执行时间上限为 900 秒,CPU 配额为 2,内存为 4096 MB,产物保留 24 小时。
但示例还不能直接完成「修改仓库并运行所有测试」。实际编辑需要可写 overlay 或独立 worktree;测试缓存、临时文件、依赖安装目录也需要安排。原文没有补齐这些配置,落地时必须按项目验证。
如果任务需要创建 PR,作者建议声明具体能力,再由 runner 换取短期凭证:
identity:
environment: allowlist
capabilities:
- type: source_control
repository: acme/docs-site
actions: [create_branch, push_branch, create_pull_request]
expires_after_seconds: 1200
require_approval_for: [push_branch, create_pull_request]
artifacts:
collect:
- /scratch/test-results.xml
- /scratch/diff.patch
redact:
- "(?i)(api[_-]?key|token|password)\\s*[:=]\\s*\\S+"
要盯住 require_approval_for:声明了能力,并不代表可以直接推送分支或创建 PR。这里还要求审批,凭证有效期为 1200 秒,作用范围限定在 acme/docs-site。manifest 中不保存密钥值,也不整包复制开发者环境变量。
网络也采用同样的拆分方式。原文要求默认拒绝出站连接,按主机、协议、端口、用途,以及可行时的 API 路径或代理策略放行。示例允许 api.github.com 和 registry.npmjs.org 的 443 端口,并配置 block_private_ranges: true、proxy_required: true。
不过,示例没有写出协议和路径规则,不能把这些建议当成已经实现的控制。下载 npm 包与发布 npm 包也要分开授权;只允许访问 registry 域名,表达不了这种区别。
配置写完以后,谁保证它真的生效
作者把执行拆成三个检查阶段。
启动前,校验 schema 和组织策略,要求用途、负责人、到期时间及资源上限;拒绝越界的可写挂载、无人值守任务的通配网络规则、root 执行和宿主 Docker socket。写入、发布或生产操作还应有审批引用。前面的最小示例并未包含这些全部字段,它只是起点。
启动时,将镜像、源码和挂载别名解析成确定的值,记录 image digest、source commit、挂载路径、网络规则及 capability ID。CPU、内存、磁盘、进程数和实际执行时长,由运行时在 Agent 进程外限制。文末还提出网络、工具调用和 token 预算,但没有给出这些预算的完整配置或执行器实现。
文件系统还要检查链接。即使只挂载一个工作区,其中的符号链接、硬链接、凭证助手配置或本地缓存,也可能改变访问范围。网络侧则要把 DNS 和重定向纳入策略,不能只检查最初填写的域名。
退出时,先收集批准的产物与执行凭据,再撤销能力、销毁工作区、验证销毁结果。清理失败就隔离环境、拒绝重新分配并告警。长期任务通过租约续期证明自己仍在正常工作,失联后由调度器触发取消和清理。
执行回执记录 manifest 摘要、输入 commit、镜像摘要、授权、命令哈希、产物校验和、拒绝动作、最终状态及清理结果。原文示例的 run_id 为 run_8a1,network_denials 为 2,并记录 workspace_destroyed、capabilities_revoked 均为 true。
这份回执用于回答「用了什么输入、获准做什么、实际尝试了什么、最后清理了吗」。它不需要保存模型私有推理,也不该默认保存可能夹带客户数据和 token 的全部命令输出。
我的判断
我赞成作者把输入、工作区、输出和持久状态分开。固定 commit 作为只读输入,修改发生在临时工作区,最后导出 patch、构建产物或测试报告,出错后丢弃工作区即可。需要恢复时,再将快照与原 manifest、输入版本绑定,比保留一台历史不明的机器更容易追查。
但manifest 的约束力取决于执行器,YAML 本身不会隔离任何进程。
原文没有提供完整 schema、运行时适配器、攻击测试或性能数据,因此「更安全、更容易调试和复现」是有合理依据的工程判断,不能当作已验证的收益。配置中写了禁止路径、网络代理或日志脱敏,也需要对应机制逐项兑现。示例里的正则更无法保证识别全部敏感信息。
与每个 prompt 单独配置相比,按任务类别建立模板更适合日常维护;与所有任务共用一套宽权限相比,它能让新增权限进入代码审查。不过,团队仍要承担模板维护、凭证签发、网络代理和清理验证的成本。
原文建议先以 report-only 模式观察,再阻断高风险默认权限,这个顺序务实。但只观察行为不会阻止越权,不能把观察阶段当成隔离已经完成。
能拿来做什么
- 给日常 AI 编程建立「只读解释」「测试与补丁」「创建 PR」三类模板。前者不配网络和凭证,测试任务使用临时可写工作区,PR 任务再增加短期仓库能力。
- 为 Node 项目逐项确认依赖安装、测试缓存和报告输出的路径,并检查锁文件对应的实际下载目标,避免为了跑通测试直接放开整个宿主目录和互联网。
- 先盘点现有 Agent 能接触的路径、socket、环境变量、网络目标和云角色,用
report-only比较声明权限与实际使用,再处理宿主 home、生产凭证、root 和无限期工作区。 - 把 manifest 摘要、输入 commit、产物校验和及清理结果接入任务回执,让 PR 审查能够核对修改内容及其执行条件。