能力与安全边界
理解插件运行时默认拒绝的文件、网络、命令执行和文件修改边界。
Semifold 把生态插件视为“仓库中负责解析不可信项目数据的代码”。因此,运行时使用明确且限定在单次操作内的能力,不允许插件继承整台机器的环境权限。
边界速览
| 能力 | 默认状态 | 怎样授权 | 重要限制 |
|---|---|---|---|
| 列出文件 | 拒绝 | metadata.readPatterns | 请求和返回路径都必须匹配已授权的仓库相对 glob。 |
| 读取文本 | 拒绝 | 同一项读取模式 | 读取不能离开项目根目录,并受单文件和单次操作预算限制。 |
| HTTPS 请求 | 拒绝 | .changes/config.toml 中的 allowed-origins | 只接受精确 HTTPS 来源,不接受通配符、凭据或按路径授权。 |
URL | 提供受限子集 | Boa 宿主内置 | 只支持 SDK 已声明的接口。 |
| 写文件 | 不提供 | 无法授权 | 插件返回候选修改,由宿主验证并应用。 |
| 启动命令 | 不提供 | 无法授权 | 发布与钩子命令保留在解析器配置中。 |
| 宿主凭据 | 不提供 | 无法授权 | 软件包仓库与代码托管平台凭据不会进入插件输入。 |
文件访问
插件在元数据中声明尽可能小的 glob 集合:
export const metadata = definePluginMetadata({
ecosystem: 'com.example.game',
pluginVersion: '1.0.0',
readPatterns: [
'packages/*/manifest.json',
'workspace.lock',
],
});host.listFiles(pattern) 不能扩大权限:请求的 glob 必须与 readPatterns 中的某一项完全相同,每条返回路径也会再次检查。不能用一个看似更窄的不同 glob 代替已声明值。host.readText(path) 会执行相同的项目根目录、glob、路径编码、文件大小和单次操作累计预算检查。
协议数据应统一使用正斜杠和仓库相对路径,不要依赖调用者的当前工作目录。
网络访问
在配置中授权精确来源:
[plugins."com.example.game"]
path = "plugins/game.js"
allowed-origins = [
"https://api.example.com",
"https://metadata.example.net:8443",
]运行时会拒绝非 HTTPS URL、内嵌凭据、未授权端口和只是看起来相似的来源。请求与响应正文、请求次数、重定向、并发和累计耗时都有限制。网络传输不会继承系统代理。
fetch 和 URL 有意小于浏览器 API。请把 @semifold/plugin-sdk 类型当作受支持的契约;熟悉的 Web API 名称并不意味着存在 DOM、Cookie、浏览器缓存或 Node.js 行为。
返回候选修改,而不是直接写文件
plan-edits 返回声明式文件修改。修改已有文件时,必须携带插件读取到的原始字节对应的 SHA-256。宿主随后会验证:
- 目标路径合法且没有离开仓库;
- 修改提到的软件包和依赖确实存在;
- 修改来源与发布计划一致;
- 当前文件内容仍与预期哈希匹配;
- 不存在重复目标或跨适配器冲突;
- 候选修改能被普通文件修改执行器接受。
插件永远不会得到可写文件句柄。
运行时与协议失败
可以预期的领域失败应由插件返回结构化诊断。Semifold 还会把运行时异常、错误协议版本、缺少操作、响应操作不匹配、非法路径、资源超限和无效修改转换成带插件范围的错误。
某个插件失败会停止需要它的当前操作;Semifold 不会因此开放备用权限,也不会悄悄接受一张不完整的工作区图。
仍由宿主负责的工作
以下能力不会进入插件:
- 解析变更集并合并版本提升级别;
- 验证跨生态依赖图;
- 计算发布通道版本;
- 渲染变更日志;
- 执行软件包仓库检查与发布命令;
- 创建 GitHub Release 并上传附件;
- 最终应用文件修改并报告恢复状态。
这条边界让自定义软件包格式可以扩展,又不会把插件变成一段拥有整台机器权限的发布脚本。