插件的工作原理
本页从运维者的角度解释插件系统:如何发现插件、插件被允许执行什么操作,以及宿主如何将不受信任的插件限制在可控范围内。关于插件作者实现的磁盘协议约定(清单字段、bridge 导出、宿主函数),请参见 Plugin protocol。
系统的形态
插件是一个沙盒化的 WebAssembly 模块加上一个清单。宿主会加载它,读取它声明的能力和权限,并且只有在操作员打开插件系统时,才将其工具暴露给代理。插件中的任何内容都不是隐式的:插件获得的能力仅限于其清单所声明且操作员策略允许的那些,除此之外没有别的。要自己构建一个,请从 plugin guides 开始。
每一层都满足三个属性:
- 默认禁用。 插件系统不会加载任何内容,除非
[plugins] enabled = true。没有插件配置的默认构建不会运行任何插件代码。 - 默认拒绝。 插件只有在其清单中声明了匹配的权限,才能访问宿主能力(HTTP 出站、配置、内存)。未声明的能力不可达,而不仅仅是未使用。
- 已由策略验证。 未签名或不受信任的插件是否允许加载完全由操作员决定,在配置中一次性设置,并在发现时统一强制执行。
插件加载的生命周期
当运行时构建其工具集时,插件加载器会按顺序经历以下阶段。未通过前一阶段的插件不会进入后一阶段。
- 门控。 如果
[plugins] enabled为 false,加载器不会执行任何操作。这是第一道也是最便宜的检查。 - 发现。 加载器会扫描已解析的插件目录(
[plugins] plugins_dir,默认~/.zeroclaw/plugins/)中的包含manifest.toml的子目录。 - 验证形状。 每个 manifest 必须声明至少一个 capability,且非 skill 插件必须指定一个存在的
wasm_path。格式错误的 manifest 会被跳过并发出警告,绝不会被加载。 - 强制执行签名策略。 每个插件都会根据已配置的
[plugins.security] signature_mode和trusted_publisher_keys进行检查。未通过该策略的插件会从已加载集合中移除,不会作为工具展示。 - 注册工具。 保留下来的工具插件会封装为代理工具,并追加到内置工具之后。工具分派按名称进行首次匹配,因此与内置名称冲突的插件工具永远不会被选中;请为插件工具提供唯一名称。工具和技能插件会被_自动发现_,因此仅当
[plugins] auto_discover = true时才会执行此枚举(默认为false,故障关闭):当enabled = true但auto_discover = false时,不会加载任何插件工具或技能,不过你在[channels.plugin.<alias>]下声明的通道仍会激活。技能加载器应用相同的 auto_discover 门控。
签名阶段是最容易配置错误的阶段,因此值得单独理解。
签名策略
每个插件清单都可以携带一个 Ed25519 签名,以及签署它的发布者的十六进制编码公钥。运维人员通过 [plugins.security] signature_mode 决定对该签名的强制执行有多严格:
| 模式 | 什么加载 | 用于 |
|---|---|---|
disabled | 每个格式正确的插件,无论是否已签名 | 针对你自己构建的插件进行本地开发 |
permissive | 每个格式正确的插件;未签名、不受信任,以及无效签名的插件都会在加载时发出警告 | 向签名迁移,同时不破坏现有安装 |
strict | 只有来自受信任发布者且签名有效的插件会加载 | 任何共享或生产主机 |
在 strict 模式下,清单中的 publisher_key 必须出现在 [plugins.security] trusted_publisher_keys 中,并且签名必须针对规范化后的清单字节进行验证。未签名、由不受信任的密钥签名,或签名验证不通过的插件,会在发现阶段被丢弃,且永远不会成为工具。默认值是 disabled,因此新的本地检出无需密钥管理也能正常工作,但任何会从你不控制的来源加载插件的主机都应运行 strict。
此策略统一强制执行:主机在你列出插件时应用的检查,与代理运行时在构建工具集时应用的检查是同一个,因此你在 strict 模式下看不到的插件,代理也无法调用。
功能与权限
清单声明两件独立的事情,而这种区别很重要。
- Capabilities 是插件属于哪种扩展类型:
tool、channel、memory、observer或skill。tool插件会提供 LLM 可以调用的工具。 - 权限是插件代码在运行时可访问的宿主服务:HTTP 外联、配置、内存。清单未声明的权限,就是插件无法访问的宿主功能。
主机以严格范围授予权限:清单未声明的权限对应的主机函数,插件无法调用。配置根据主机签发的实例身份解析,因此插件无法选择其他包或绑定,也绝不会读取原始进程环境。http_client 控制出站 wasi:http 接口;共享的 SSRF 防护出站策略仍属于配套的插件强化工作。本页介绍签名策略边界。
配置参考
所有设置都位于 plugins.* 配置路径下,并可通过任何配置界面(zerocode、网关或 CLI)进行设置:
# 主开关。在这为 false 时不会加载任何内容。
zeroclaw config set plugins.enabled true
# 在运行时加载自动发现的工具和技能插件(默认值:false)。
# Without this, `enabled = true` activates only explicitly-declared channels.
zeroclaw config set plugins.auto_discover true
# 插件的发现位置(默认:~/.zeroclaw/plugins)。
zeroclaw config set plugins.plugins_dir ~/.zeroclaw/plugins
# 已禁用 | 宽松 | 严格
zeroclaw config set plugins.security.signature_mode strict
# 允许在严格模式下发布插件的十六进制编码 Ed25519 公钥。
zeroclaw config set plugins.security.trusted_publisher_keys '["a1b2c3d4e5f6..."]'
旨在加载第三方插件的宿主应设置 enabled = true、signature_mode = "strict",并仅列出你信任的发布者密钥。若还要加载自动发现的工具和技能插件,还应设置 auto_discover = true;它默认为 false,因此仅设置 enabled = true 只会启用你在 [channels.plugin.<alias>] 下声明的通道,不会启用任何插件工具或技能。仅运行你自行构建的插件的宿主,在开发期间可以让 signature_mode 保持其 disabled 默认值,并在共享宿主之前收紧设置。
插件仍然无法做到什么
即使授予了所有权限,沙箱仍会约束插件:
- 它作为一个 WebAssembly 模块运行,无法对宿主进程或其根工作区之外的文件系统进行环境访问。网络外出流量受 HTTP 权限控制;由 SSRF 防护的外出边界本身由配套的插件加固工作提供。
- 可信工具或通道插件可在已授权的服务调用期间,通过其作用域限定的
secrets.get导入读取架构指定机密的明文。工具会在execute期间获得访问权限。通道会在configure和运行调用期间获得config.get和secrets.get;同一次调用中的读取使用同一个规范修订版本,因此同一绑定的公开配置/机密轮换会在下一次操作时可用。实例化和静态元数据发现不能使用任一导入。主机可防止公开配置注入和跨实例选择,但返回明文的导入无法阻止恶意来宾保留其读取的内容。符合要求的通道插件必须在每个使用点解析配置和凭据。 - 它不能取代内置工具:内置工具会先注册,而工具分发会按名称进行首次匹配解析,因此发生冲突的插件工具根本不会被选中。
沙箱和命名空间边界不受插件代码尝试执行的任何操作影响。相反,不保留规则属于受信任的通道插件契约的一部分,这也是发布者审核和签名策略仍然重要的原因。