iii 的 Worker Registry 实战指南:发布、版本化与 Bundle Worker 的安全安装管线

发布时间:2026/9/14 13:03:40
iii 的 Worker Registry 实战指南:发布、版本化与 Bundle Worker 的安全安装管线 iii 的 Worker Registry 实战指南发布、版本化与 Bundle Worker 的安全安装管线【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii本指南围绕 iii 项目的 Worker 注册表Registry展开讲解已发布的 worker 如何被其他 iii 项目以iii worker add name安装使用重点剖析其中第三类产物Bundle Workertar.gz 归档的完整安装管线从注册表响应形状、SHA-256 校验、严格归档安全策略到iii.worker.yaml清单契约与资源钳制Resource Clamping。读完本文你将掌握如何在 iii 中发布与版本化 worker、理解 bundle 与 binary/OCI 三种产物形态的差异并能解释W180/W181/W182/W183等错误码背后的实现原理与安全设计。iii 的 registryworkers.iii.dev是已发布 worker 的存放地供其他 iii 项目通过iii worker add name安装。发布一个 worker 会把它的二进制或 OCI 镜像上传到 registry记录其 semver 版本并让该 worker 能够被任何 iii 项目按名称安装。在三种产物形态binary、image、bundle中bundle 是本文重点——它是一条独立于 OCI 拉取的、带校验与安全限制的 tar.gz 安装路径实现位于 crates/iii-worker/src/cli/bundle_download.rs。注册表定位与安装入口注册表的核心契约非常简洁已发布 worker 通过名称可被任意项目安装。CLI 侧的用户视角是统一的——无论产物是二进制、OCI 镜像还是 bundle 归档都执行同一条命令iii worker add name从源码结构看安装的解析与分发由 crates/iii-worker/src/cli/registry.rs 和 crates/iii-worker/src/cli/managed.rs 承担注册表响应按type字段区分四种形态registry.rs 中WorkerInfoResponsebinary、image、engine、bundlehandle_bundle_addmanaged.rs#L210是 bundle 安装管线的入口随后把工作交给bundle_download模块的下载、校验、解压与原子安装各步骤iii worker update同样汇入 bundle 安装路径因此“更新已发布 worker”对 bundle 而言即“以最新解析结果重新执行 add 管线”。发布与版本化 worker发布Publish发布动作把 worker 的二进制或 OCI 镜像上传到 registry记录 semver 版本并使其可被任意 iii 项目按名称安装。发布行为属于发布端registry 服务端能力当前仓库的 CLI 侧未直接实现iii worker publish命令仓库内的 docs/creating-workers/workers-registry.mdx 原文档也以 TODO 形式标注了“规范发布命令、认证要求、元数据描述、repo URL、支持平台”尚待补充。因此本文聚焦于安装端与bundle 清单契约这些可由源码确认的部分。版本化Semver注册表中的 worker 遵循语义化版本semverpatch 递增修复 bugminor 递增新增向后兼容的能力major 递增函数或触发器签名的破坏性变更。从实现看版本信息贯穿整个解析与安装流程注册表响应如BundleWorkerResponse携带version字段registry.rs#L100-L106安装时的解析图节点ResolvedWorker同样记录version且依赖边ResolvedEdge带有range字段用于版本范围匹配。git tag 模式、预发布版本的发布方式在原文档中标注为 TODO本文不展开虚构。多平台二进制产物二进制类 worker 可以在单个 registry 条目内为多个平台目标发布产物macOS arm64/x64、Linux arm64/x64/armv7、Windows arm64/x64/x86一个已发布版本即可覆盖所有受支持主机无需按平台分别发布。这一点对应 registry 响应中binaries这一可选的按平台映射字段registry.rs 中ResolvedWorker.binaries从数据结构上印证了“单条目多平台”的设计。Bundle Worker第三种产物形态Bundle 是与binary、image并列的第三种产物。注册表为一个 bundle 提供单个 tar.gz 归档内含 worker 的打包源码 位于归档根部的iii.worker.yaml清单。iii worker add name会下载归档校验 SHA-256 校验和将归档解压到~/.iii/workers-bundle/name/走既有的 libkrun 沙箱轨道运行与本地路径local-pathworker 相同的沙箱路径只是去掉宿主机侧的源码监视器。各目录位置与磁盘布局在 config_file.rs#L718-L733 有明确定义~/.iii/workers-bundle/存放全部 bundle 安装~/.iii/workers-bundle/{name}/是单个 worker 的安装目录。什么时候该用 Bundle原文档给出三条明确判据分发预构建产物你发布的是预构建的 JavaScript bundleesbuild、tsdown、bun build或打包好的 Python worker且不想发布 Docker 镜像追求 KB 级体积希望产物以 KB 而非 MB 计量。归档中只传输打包后的源码运行时随引擎白名单基础镜像一起提供docker.io/iiidev/node:latest或docker.io/iiidev/python:latest用户侧体验一致安装对用户而言与 registry 中其他 worker 完全一致iii worker add my-worker与 binary、OCI 相同。Registry 响应形状注册表对 bundle 的响应是如下 JSON{ type: bundle, name: my-worker, version: 1.2.0, archive_url: https://cdn.workers.iii.dev/my-worker/1.2.0/bundle.tar.gz, sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 }该形状与源码中的反序列化结构完全对应BundleWorkerResponse正是name、version、archive_url、sha256四个字段registry.rs#L100-L106。校验流程引擎 GETarchive_url将字节流经 SHA-256 哈希器流式计算并与sha256比对。不匹配则中止安装并立即删除已下载的 blobbundle_download.rs 的download_archive中sha256不匹配分支会remove_file后返回W142错误。此外还要求响应内容类型以application/开头、总大小不超过上限MAX_BUNDLE_TOTAL64 MiB。归档布局归档根部必须包含iii.worker.yaml其余内容位于运行时可按路径发现的位置my-worker-1.2.0.tar.gz ├── iii.worker.yaml ├── bundle.js └── assets/ └── ...清单契约iii.worker.yamlBundle 清单使用本地 worker 清单的严格子集三个字段被显式拒绝scripts.setup会在安装期间执行发布者提供的 shell 脚本属于供应链走私supply-chain smuggling向量scripts.install理由同上应把依赖打包vendor进 bundle 而非安装时安装runtime.base_image允许 bundle 以任意 OCI 镜像作为 rootfs。Bundle 固定使用引擎白名单基础镜像。必填字段name必须等于安装目标即传给iii worker add的值scripts.start非空 shell 字符串引擎会在沙箱 VM 内exec它。示例node bundle.js、python -m worker、bun run bundle.js。可选字段会针对引擎能力上限做钳制超限时输出W182 BundleResourceClamped警告resources.cpus默认2钳制到4resources.memory默认2048MiB钳制到4096MiB。完整示例清单name: my-worker version: 1.2.0 scripts: start: node bundle.js resources: cpus: 2 memory: 2048实现佐证validate_bundle_manifestbundle_download.rs#L1142-L1286逐项落实了上述契约——清单文件缺失、name与安装目标不符、scripts.start缺失或为空都会返回BundleManifestRejectedW180scripts.setup被明确拒绝runtime.base_image必须是一个“貌似合理”的 OCI 引用仅含._-/:与字母数字否则同样触发W180。此外清单文件被限制在64 KiBMAX_BUNDLE_MANIFEST_BYTES这是针对 serde_yaml 0.9.x 的 billion-laughs锚点/别名指数展开攻击的防御超限清单在字节进入 YAML 解析器之前即被拒绝。资源钳制由parse_bundle_resources实现bundle_download.rs#L1339-L1402请求超过ResourceCaps默认 CPU 4、内存 4096 MiB时取上限并记录clamped_cpus/clamped_memory_mb由调用方managed.rs#L339-L358打印W182 BundleResourceClamped警告——警告而非失败安装继续进行。值得注意的一个细节scripts.install在该模块的实现中实际上是允许的与文档表格中“拒绝scripts.install”的早期描述不同——它运行在沙箱 VM 内部与scripts.start处于同一发布者 shell 信任上下文且启动脚本的/var/.iii-prepared守卫保证只执行一次供 Python bundle 做无法按架构打包进归档的 pip/浏览器引导见 bundle_download.rs 中validate_bundle_manifest的注释。从仓库当前实现看这是 bundle 安装端的实际行为。归档安全策略Bundle 归档的解压限制比 OCI 层更严格限制项值解压后总大小64 MiB单个文件最大32 MiB最大条目数1024最大目录深度16允许的 tar 条目类型普通文件Regular、目录Directory含符号链接symlink、硬链接hardlink、字符设备、FIFO 或含..路径分量的归档一律以W181 BundleArchiveUnsafe拒绝。对应常量定义在 bundle_download.rs#L55-L80MAX_BUNDLE_TOTAL 64 MiB、MAX_BUNDLE_FILE 32 MiB、MAX_BUNDLE_ENTRIES 1024、MAX_BUNDLE_DEPTH 16。为什么比 OCI 更严OCI 解压路径worker_manager::oci::extract_layer_with_limits按最大 10 GiB / 100 万条目设计且不显式拒绝 symlink/hardlink而 bundle 是发布时构建的单二进制类产物合法内容中不存在 symlink因此使用专门的、更紧的提取器extract_bundle_safely_blockingbundle_download.rs#L577-L796只接受Regular与Directory拒绝绝对路径与..分量逐条校验大小、总量、深度并将 setuid/setgid 位剥离。集成测试在 tests/bundle_worker_integration.rs 中对..路径、绝对路径、symlink、hardlink、字符设备、FIFO、块设备、超限条目数、超限单文件、超限总量、超深目录等攻击性归档逐一做了回归锁定同时以边界测试确认“恰好等于上限”的合法归档仍被接受extract_accepts_exactly_max_entries、extract_accepts_exactly_max_depth。错误码速查代码失败场景W142归档下载失败HTTP 错误、非预期 content-type、大小超限、sha256 不匹配W180清单被拒含被禁字段如scripts.setup、runtime.base_imageW181归档含不安全条目symlink、hardlink、路径穿越、超限、条目过多W182资源请求超过引擎上限安装以钳制后的值继续警告而非失败W183依赖图过宽或过深最大深度 5最大传递依赖数 32这些代码在 crates/iii-worker/src/core/error.rs 中与WorkerOpErrorKind一一对应并通过to_payload()以{ type, code, message, details }的线缆信封格式暴露含结构化details供自动化调用方按字段分支处理。安装管线的源码级拆解iii worker add bundle的完整管线managed.rs#L210 起分为八个步骤每一步失败都会在清理好现场后返回非零退出码开关检查III_BUNDLE_WORKERS_DISABLED1时直接拒绝一切 bundle 安装在任何网络 I/O 之前——这是面向不信任 registry CDN 的操作员的“总开关”获取锁与暂存目录acquire_staging以spawn_blocking获取按 worker 名隔离的 fslock~/.iii/workers-bundle/.locks/name.lock并在~/.iii/workers-bundle/.staging/rand/创建暂存目录StagingGuard以 RAII 保证未提交即清理流式下载 SHA-256 校验download_archive完成 SSRF 防护、内容类型与大小校验、哈希比对与缓存命中判断安全解压extract_bundle_safely经spawn_blocking调用阻塞式提取器避免拖垮异步运行时严格清单校验validate_bundle_manifest资源钳制parse_bundle_resources超限打印W182警告原子安装atomic_installbundle_download.rs#L811-L863把暂存目录原子rename为~/.iii/workers-bundle/{name}/旧安装先以{name}.old.unique停放、新安装失败时回滚还原跨文件系统时退化为“复制到同父目录的.partial.*兄弟目录再原子 rename”写入配置向项目config.yaml写入仅含名称的条目不带worker_path与image保证解析器在启动时把该 worker 路由到不可变的 bundle 安装目录。安装是机器级全局缓存bundle 按名称而非按项目缓存于~/.iii/workers-bundle/{name}/任何项目add都会用新解析的版本替换磁盘上的负载绝不会复用可能过期的旧安装——这正是iii worker update能刷新 bundle 的原因。测试bundle_add_replaces_existing_install_in_second_project专门锁定了“项目 B 的 add 必须替换项目 A 的陈旧安装”这一行为。安全纵深SSRF 防护、缓存与并发下载侧 SSRF 防护download_archive在任何文件系统操作之前执行 SSRF 守卫拒绝明文 HTTP、file:、ftp:以及落入非路由/链路本地/私网段的字面 IP如云厂商 IMDS 的169.254.169.254、10/8RFC-1918。三个开发逃生口细节值得注意localhost/127.0.0.1/::1仅在显式设置III_BUNDLE_DEV_LOOPBACK1时才放行每次安装都会打印警告用于本地 E2E 测试重定向场景使用专用BUNDLE_HTTP_CLIENT每个Location:头都会重新执行 SSRF 校验且重定向次数上限为 5——公共 CDN 的 URL 永远不允许重定向进内网开发逃生口对重定向不生效网络层测试sha256 不匹配、content-type 拒绝、重定向上限集中在单元测试层集成测试则通过预置缓存实现全离线验证。下载缓存与 LRU 淘汰校验通过的归档会按 SHA-256 存入~/.iii/cache/bundles/sha256.tar.gzBUNDLE_CACHE_MAX_BYTES 1 GiB预算相同字节的归档被所有指向它的nameversion复用重复安装完全跳过网络。缓存命中路径会再次重算哈希关闭缓存文件读取与复制打开之间的 TOCTOU 窗口发现损坏 blob 立即淘汰回退网络下载LRU 淘汰按 mtime 从旧到新清理。cached_archive_path对摘要做了严格格式校验必须 64 位小写十六进制杜绝恶意注册表响应通过构造文件名穿越缓存目录。并发与崩溃安全按 worker 的 fslock并行iii worker add foo会阻塞等待而非报错锁随进程死亡自动释放孤儿暂存目录清扫sweep_orphansbundle_download.rs#L1050-L1131在引擎/CLI 启动时清理残留暂存目录但要求“目录存在超过 60 秒”且“对应 fslock 可无阻塞获取”——后者防止清扫掉正在进行的慢速下载测试sweep_orphans_skips_locked_staging_dir专门锁定此行为旧安装保护替换流程先把旧安装停放到.old.*兄弟目录新安装失败则还原{name}.old.*只在下一次成功安装后才清扫——因为一个没有final_dir的停放兄弟目录可能是该 worker 的唯一剩余副本回归测试atomic_install_failure_preserves_parked_old_sibling。依赖图与 W183bundle以及解析图中的其他节点支持依赖关系注册表响应可携带dependencies映射与边列表ResolvedEdge { from, to, range }安装时由validate_dependency_graph做 DAG 校验tests/bundle_worker_integration.rs 第 D 节拒绝环、容忍重复边去重、对长链与宽共享依赖图采用迭代遍历超过大图阈值LARGE_DEPENDENCY_GRAPH_THRESHOLD 32时标记“需要确认”而不是直接拒绝超深最大深度 5或传递依赖超限最大 32则以W183报错。测试中还固定了eval0.1.0这一真实六节点链的回归形状防止旧的硬编码深度限制误伤合法依赖链。操作员开关与环境变量面向部署侧的两个环境变量开关定义于 bundle_download.rs#L82-L94变量值效果III_BUNDLE_WORKERS_DISABLED1完全禁用 bundle worker 的安装与启动仅字面量1生效true/yes无效III_BUNDLE_DEV_LOOPBACK1仅对直连 localhost/127.0.0.1/::1的归档 URL 放行 SSRF 守卫开发专用生产构建默认拒绝两者都在任何网络/文件系统工作之前被检查测试对取值边界1vstruevs 空串做了防御性回归锁定。总结Worker Registry 让 iii 项目之间以“名称即安装”的方式共享 worker。对 bundle 形态而言一次iii worker add name背后是一整套可审计、可回滚、防供应链攻击的安装管线注册表响应经 SSRF 守卫与 SHA-256 校验归档经严于 OCI 的解压白名单与尺寸上限清单经“拒绝 setup、固定白名单基础镜像”的严格契约资源超限以W182警告降级而非失败安装以原子 rename 旧版停放回滚落地。想深入验证这些行为可以从 crates/iii-worker/src/cli/bundle_download.rs 与 crates/iii-worker/tests/bundle_worker_integration.rs 开始发布侧规范iii worker publish、认证与元数据在 docs/creating-workers/workers-registry.mdx 中仍标注为 TODO属于 registry 服务端能力仓库内暂无实现可引用。【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考