☰
AOS CE Capsule 能力清单实战:Capsule.toml 中 [capabilities] 的完整字段目录与最小权限设计
2026/9/25 2:43:56 网站建设 项目流程

【免费下载链接】aos-ce

AOS Community Edition: the open agent operating system.

项目地址:https://gitcode.com/gh_mirrors/ao/aos-ce
点击查看免费下载

在 AOS Community Edition(开源代理操作系统)中,每个 Capsule(胶囊)声明的权限都写在Capsule.toml的[capabilities]表里,而这份声明遵循“默认拒绝”原则:未声明即无权限。本文以 capsules/capsule-forge/src/guides/capabilities.md 这份能力参考手册为主体,完整覆盖全部 11 个能力字段、VFS 路径规则、网络与进程边界、身份权限分级以及选型工作流,并结合 capsule-forge 的suggest_capabilities工具与 checks.rs 清单校验器,给出可复制、可校验的落地实践。读完后你应能:为任意新 Capsule 写出权限最小的 manifest,理解每个字段在运行时的实际边界,并用工具自动检查常见错误。

这份指南在仓库中的位置与交付方式

capabilities.md是 capsule-forge 内置“作者手册”(Author Manual)中名为capabilities的一章。lib.rs 中的GUIDE_CHAPTERS常量把各章 Markdown 以include_str!编译进 WASM,并通过forge_guide工具按topic渐进式下发——LLM 只在当前工作真正需要时才加载这一章,而不是把整本手册塞进上下文。手册共 12 章(foundations、workspace、capsule、manifest、capabilities、ipc、wit、skills、authority、build、security、meta-harness),其中 capabilities 章的定位是“all capability fields, least authority, VFS paths, and host-call gates”(见 lib.rs#L77-L81)。

手册本身是被代码“看护”的:lib.rs#L800-L821 的测试capability_manual_names_the_complete_current_surface断言 capabilities 章节必须同时包含全部 11 个字段(uplink、net、kv、fs_read、fs_write、host_process、allow_persistent、net_bind、net_connect、identity、allow_prompt_injection),防止字段目录随代码演进而悄悄漂移。这保证了下文所有字段说明与当前运行时 schema 一致。

核心语义:一切字段都 fail-closed

手册开篇定调(capabilities.md 第 1–5 行):

  • 每个字段都“失败即关闭”:列表字段未声明时默认为空列表,布尔字段默认为false;
  • 声明是必要条件,但不充分:principal(调用主体)、operator 策略、运行时 consent(用户同意)都可能在声明之上进一步收窄实际权限。

换句话说,manifest 描述的是“最大权限”,运行期实际权限 = 声明权限 ∩ principal 授权 ∩ 策略/同意约束。这一点对排障很重要:工具“明明声明了却调不通”,往往不是 manifest 错了,而是上游的授权链路在收窄。

checks.rs的清单校验器把同样的类型契约固化了下来:checks.rs#L92-L125 中LIST_FIELDS恰好是net、kv、fs_read、fs_write、host_process、net_bind、net_connect、identity八个列表字段,BOOL_FIELDS恰好是uplink、allow_persistent、allow_prompt_injection三个布尔字段——与手册的目录逐一对应,未知字段(如凭空发明的shell、internet)会被validate_manifest发出 warn。

完整字段目录

手册给出的当前全部能力字段如下(继承自 capabilities.md 第 9–24 行):

字段类型声明的最大权限
uplinkboolean充当长寿命 uplink 并使用带归属(attributed)的 publish 操作;移除普通 WASM 调用超时。
netlist向所列主机名或"*"发起出站 HTTP。
kvlist保留的 manifest 表面;今天 principal + capsule 作用域的 KV 无需声明即可用。
fs_readlist读取所列 VFS 前缀下的内容。
fs_writelist写入所列 VFS 前缀下的内容。
host_processlist启动所列名称的主机可执行文件。
allow_persistentboolean允许宿主拥有的进程存活时间超过 Capsule 实例(在host_process之上的附加授权)。
net_bindlist绑定所列原始 socket 端点。
net_connectlist连接所列原始host:port端点。
identitylist在resolve、link或admin级别执行身份操作。
allow_prompt_injectionboolean允许 hook 输出修改系统提示词。

手册特别强调:“这些就是当前的全部字段。不要发明shell、internet、filesystem或泛化的adminmanifest 能力。” 这一点与校验器的行为互相印证:checks.rs 测试capability_types_follow_the_runtime_schema中,imaginary = true这类未知字段会产生 “Unknown capability field” 告警,而net = true/uplink = ["yes"]这类类型错误会产生 error 级发现。

标准示例与最小权限写法

手册给出的规范示例:

[capabilities] fs_read = ["home://documents/"] fs_write = ["home://data/my-capsule/"] net = ["api.example.com"] host_process = ["git"]

配套的写作原则:优先写具体域名、二进制名、端点和路径前缀;"*"是有语义的宽授权,评审时应当被明确地按宽授权呈现(而不是静默通过)。

仓库里的真实 Capsule 恰好覆盖了各种典型形态,可直接对照:

  • 只读首页目录:capsule-forge/Capsule.toml#L13-L14 仅声明fs_read = ["home://"];
  • 宽 HTTP 授权:capsule-http/Capsule.toml#L13-L14 声明net = ["*"]——按手册,评审时必须把它当作“开放 host 集合”处理;
  • 进程允许列表:capsule-shell/Capsule.toml#L13-L14 声明host_process = ["bash", "sh", "zsh"];
  • 读/写分离的教科书案例:capsule-fs/Capsule.toml#L12-L16 声明fs_read = ["cwd://", "home://"]而fs_write = ["cwd://"],源码注释明确说明“home:// 的写权限被故意省略,因为~/.astrid/内含密钥与审计数据库;只有确实需要时(如插件安装器)才按 Capsule 授予写权限”。这正是“fs_read不蕴含写、fs_write不蕴含读”原则的实例。

文件系统规则(VFS 路径语义)

手册的 Filesystem rules 一节给出五条硬规则:

  1. home://是调用 principal 的主目录,随调用作用域变化——同一个路径在不同 principal 下解析到不同物理位置;
  2. cwd://是运行时提供的 capsule/workspace 根目录;
  3. "*"是workspace 范围内的宽访问,不是宿主完整文件系统;
  4. 父级穿越(parent traversal)一律被拒绝,即使你声明了宽前缀;
  5. 读与写互相独立,不互相蕴含。

由此导出两条实践建议:可变的文件应放在 capsule 专属数据目录(如home://data/my-capsule/);小的结构化状态优先用 KV,发生竞争更新时用 compare-and-swap。

从源码结构看,这些规则由宿主内核的 VFS 与能力系统强制执行,Capsule 侧无法绕过——lib.rs 模块头注释 明确写道“所有操作都经过内核的 VFS 和 capability 系统,Capsule 无法绕过沙箱边界”。

网络规则:三层互不蕴含的授权

net只门控高层 HTTP 客户端(按主机名匹配),它与原始 socket 能力是两回事:

  • net_connect = ["host:443"]授予到具体端点的原始出站 TCP;
  • net_bind授予监听端,对 bus 原生 Capsule 很罕见;
  • HTTP、connect、bind 三层授权互不蕴含。

手册同时给出一条安全红线:对用户提供的 URL 必须在发起 host 调用前做归一化与校验;绝不能让 LLM 参数把窄的静态域名授权变成开放代理(例如net = ["api.example.com"]之下,由模型拼出http://evil.com/redirect?to=api.example.com绕过检查)。这条对代理类 Capsule 尤其关键,因为它的“输入”天然不可信。

进程规则:比 WASM 沙箱更强的边界

host_process是可执行文件名允许列表。它比常规 WASM 调用更强的边界在于:子进程运行在组件沙箱之外。因此:

  • 参数必须以 argv 向量传递,禁止把不可信输入拼接进 shell 命令字符串;
  • 普通子进程是“有界”的——随 Capsule 实例一起被回收(reaped);
  • 需要进程存活时间超过一次调用/实例时,必须额外声明allow_persistent = true,并因此值得显式评审。

suggest_capabilities工具的推荐片段与此一致(lib.rs#L520-L523):识别到 “spawn / subprocess / exec” 类意图时,建议host_process = ["git", "cargo"]并注释“可再附加allow_persistent = true获得宿主拥有的可重附着进程”。

身份权限分级:resolve < link < admin

identity字段取值构成一个递增的权限顺序:

resolve < link < admin

手册要求:只授予最低必需级别;把调用方提供的身份字符串当作“声明(claim)”对待,直到它被 resolve 或被内核盖章(kernel-stamped);绝不能因为某个 payload 字段“看起来像 ID”就把它当作 principal。在suggest_capabilities的实现中,识别到 identity/签名类意图时给出的默认建议就是最低级的identity = ["resolve"](lib.rs#L534-L540),其注释同时说明了“列表按 resolve < link < admin 排序,每一级蕴含更低级别”。

Prompt Injection 与 Uplink:两个布尔字段的边界

  • allow_prompt_injection:授权 Capsule 的 hook 影响系统提示词的构建。返回普通工具文本不需要它。启用前必须审阅源码与确切的 hook 路径。仓库中实际使用者只有两个:capsule-agents/Capsule.toml#L14-L15 与 capsule-memory/Capsule.toml#L14-L15,都与其“注入上下文到提示词”的职责直接对应。
  • uplink:为可信的长寿命协议边缘服务,用外部身份归属进行 publish,并改变超时与归属行为。手册明确反对“仅仅为了让普通任务保持存活就开 uplink”。仓库实例:capsule-registry/Capsule.toml#L47-L48 仅声明uplink = true;而 capsule-cli/Capsule.toml#L10-L12 展示了 uplink +net_bind = ["unix:*"]的组合形态——CLI 前端需要绑定 Unix socket 才能与宿主交换消息,同时以 uplink 语义对外发布。

KV 的保留字段说明

kv列表存在于 manifest schema 中,但它是保留字段,不是普通 SDK KV 的活动门控:Capsule KV 已经按 capsule 与 principal 双重隔离,无需声明即可使用。因此:

  • 除非某个版本特定契约明确要求,否则省略kv;
  • 不要建议虚构的 store 名,好像它能创建新的 KV 命名空间。

校验器同样内置了这条知识:当检测到非空kv列表时,validate_manifest会输出 info 级发现“Thekvcapability field is reserved; ordinary capsule KV does not require it”(checks.rs#L127-L136)。suggest_capabilities对 “persist state / kv store” 意图给出的答案也是“# No capability entry required for ordinary capsule KV”(lib.rs#L510-L519)。

能力选型工作流:七步法与工具辅助

手册给出的选型流程:

  1. 列出设计中将要发起的每一个 host 调用;
  2. 把每个调用映射到确切的 manifest 字段;
  3. 把列表收窄到最小稳定作用域;
  4. 把不相关的权限拆分到另一个 Capsule;
  5. 用suggest_capabilities作为候选生成器,而非审批神谕(not an approval oracle);
  6. 将新 manifest 与已安装版本对比,呈现 delta;
  7. 既测试被拒路径,也测试被允许路径。

最后一段是权限模型的收束:“Instructions 和 Skills 可以指导这一选择;只有已安装 manifest、principal 授权与策略让它真正生效。”

关于第 5 步,suggest_capabilities的实现值得细看:它按意图关键词生成 manifest 片段(lib.rs#L472-L578),覆盖文件、HTTP、TCP、KV、进程、socket、身份、LLM 提供者/消费者。一个容易被忽视的健壮性细节是否定句识别:mentions_positive / occurrence_is_negated 会检查关键词所在从句是否以 “no / not / without / avoid / do not …” 等开头,避免“no identity operations and without http” 这类表述反向制造权限请求——测试capability_suggestions_ignore_plain_negation正是用这个反例锁住该行为。

用校验器收尾:从声明到可运行

手册工作流的产物最终应通过两层机器检查:

  1. validate_manifest:capsule-forge 提供的 lint 工具,接收整段Capsule.toml,返回{ level, message, fix }形式的 JSON 发现列表。对 capabilities 表它检查:必须为 TOML table;八个列表字段必须是数组;三个布尔字段必须是 boolean;未知字段告警;非空kv提示保留语义。完整规则见 checks.rs#L81-L137,测试入口见 checks.rs#L318-L421。
  2. aos capsule check与构建安装循环:manifest 章 的 Author review 清单要求“在构建前运行validate_manifest和aos capsule check”,并核对“Capabilities are the narrowest useful scopes”。

如果你诊断的是已安装 Capsule,capsule_doctor(lib.rs#L342-L362)会在 manifest lint 之外交叉核对[imports]是否被某个已安装 Capsule 导出。

小结

把 capabilities.md 浓缩成三条可执行原则:

  • 目录封闭:只有表中 11 个字段有效,列表默认空、布尔默认 false,不要发明shell/internet/admin;
  • 前缀具体:域名、二进制名、VFS 前缀、host:port 全部写窄;"*"与admin、allow_persistent、uplink这类宽授权必须显式评审;
  • 声明 ≠ 生效:manifest 只定义最大权限,principal 授权、策略与运行时同意共同决定实际边界,所以测试被拒路径与validate_manifest的机器校验缺一不可。

配套阅读路径:字段与规则的完整上下文在 capsules/capsule-forge/src/guides/capabilities.md,manifest 其余表面(package、component、publish/subscribe ACL、env、command)在 capsules/capsule-forge/src/guides/manifest.md,可校验的实现证据在 capsules/capsule-forge/src/checks.rs 与 capsules/capsule-forge/src/lib.rs。

【免费下载链接】aos-ce

AOS Community Edition: the open agent operating system.

项目地址:https://gitcode.com/gh_mirrors/ao/aos-ce
点击查看免费下载
上一篇:yudaocode/yudao-cloud:多环境配置管理策略
下一篇:MessagePack-CSharp最佳配置实践:不同场景下的选项调优

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询