资讯动态

OpenSandbox 发布产物验签实战:Sigstore 无密钥签名与 cosign、gh attestation 全链路校验指南

发布时间:2026/9/14 18:33:43 来源:尧图企业网站定制
OpenSandbox 发布产物验签实战Sigstore 无密钥签名与 cosign、gh attestation 全链路校验指南【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandboxOpenSandbox 在发布 SDK、CLI、容器镜像和 Helm chart 时会对产物进行签名并生成来源证明provenance attestation但不改变任何常规安装命令——验签是可选的供应链完整性检查面向需要确认“我装的就是官方从源码构建出来的那个字节序列”的用户。本文以官方文档 Release Verification 为主线完整覆盖签名模型、信任根设定以及源码归档、容器镜像、语言包、Helm chart、Maven 工件五类产物的可复制验证命令并结合发布工作流与发布脚本的源码实现解释每条验证命令背后“验的是什么”。一、签名模型八条产物签名路径OpenSandbox 的发布签名按产物类型分为八条路径。理解这张映射表是验签的前提不同产物要对照不同的发布工作流signer workflow去验证。产物类型签名/证明方式对应发布工作流源码归档opensandbox-tag.tar.gzSHA256SUMS上传到 GitHub Release 后为两个文件分别创建 GitHub/Sigstore 来源证明Generic Release 工作流release-generic.yml容器镜像Docker Hub / GHCR / ACR对三个仓库中的镜像digest做cosign无密钥签名并向三个仓库发布 provenance 证明publish-components.yml、publish-server.ymlPython 与 CLI 包wheel 与 sdist 在uv publish之前完成证明publish-python-sdks.yml、publish-cli.ymlJavaScript 包工作流执行pnpm pack对生成的 npm tarball 做证明并发布同一个tarballpublish-js-sdks.ymlC# 包NuGet.nupkg文件在发布前完成证明publish-csharp-sdks.ymlGo SDK 模块sdks/sandbox/go/vversion的源码归档由 Generic Release 工作流证明release-generic.ymlHelm chart打包出的 chart.tgz被证明并发布带证明的SHA256SUMS消费者可校验精确的发布字节publish-helm-chart.ymlJava/Kotlin 包Maven Central 发布由 Gradle Maven publish signing 配置签名下载.asc后用 OpenPGP 工具验证Gradle publish signing密钥仅存于 GitHub Actions secrets两个重要边界时间边界本文档流程只适用于签名工作流引入之后的发布。更早的发布可能没有证明或签名如果某个发布查不到证明官方建议改用更新的发布作为已签名证据。源码归档边界源码归档仅在 2026-08 之前release-generic.yml工作流被移除之前的发布中产出。更早之前创建的发布没有源码归档验签时应跳过对应章节详见第三节。相关背景见 Release Automationrelease-generic.yml的 dispatch 入口已因无调用方被移除现在的发布流程是通过打 tag 直接触发publish-*工作流。另外发布 tag 本身也可以签名当发布操作者本地配置了 git 签名密钥时可使用scripts/release/create-release.sh --target target --version version --sign-tag从 create-release.sh 的源码可以看到--sign-tag走的是git tag -s使用本地 git 签名配置创建加密签名 tag否则默认创建普通注释 tag。但官方文档明确提醒不要只依赖签名过的 tag 来信任构建产物要验证你实际安装的那个工件——tag 签名只证明 tag 指向的提交不覆盖发布过程中重新打包、构建可能引入的字节差异。二、信任根与密钥GitHub Actions OIDC 无密钥签名OpenSandbox 的绝大多数发布签名是keyless Sigstore 签名由 GitHub Actions OpenID ConnectOIDC身份创建。这意味着没有长期持有的 OpenSandbox 私钥因此也没有项目公钥文件可供下载公开证书与签名 bundle 由gh或cosign运行时从 GitHub 证明服务、OCI 镜像仓库和 Sigstore 透明度基础设施中检索私钥签名材料不会存储在 GitHub Releases、Docker Hub、GHCR、ACR、PyPI、npm、Maven Central、NuGet 或 Helm chart 下载渠道中。唯一的例外是 Java/Kotlin 的 Maven Central 签名密钥仅保存在 GitHub Actions secrets 里。2.1 预期的身份值验签命令的核心是匹配签名者身份。预期的身份值如下项目值仓库opensandbox-group/OpenSandboxOIDC issuerhttps://token.actions.githubusercontent.com源码归档工作流opensandbox-group/OpenSandbox/.github/workflows/release-generic.yml组件镜像工作流opensandbox-group/OpenSandbox/.github/workflows/publish-components.ymlServer 镜像工作流opensandbox-group/OpenSandbox/.github/workflows/publish-server.ymlCLI 包工作流opensandbox-group/OpenSandbox/.github/workflows/publish-cli.ymlPython 包工作流opensandbox-group/OpenSandbox/.github/workflows/publish-python-sdks.ymlJavaScript 包工作流opensandbox-group/OpenSandbox/.github/workflows/publish-js-sdks.ymlC# 包工作流opensandbox-group/OpenSandbox/.github/workflows/publish-csharp-sdks.ymlHelm chart 工作流opensandbox-group/OpenSandbox/.github/workflows/publish-helm-chart.yml先设置好待验证发布所用的仓库身份变量REPOSITORYopensandbox-group/OpenSandbox WORKFLOW_REPOSITORY${REPOSITORY} WORKFLOW_REPOSITORY_URLhttps://github.com/${WORKFLOW_REPOSITORY}三种需要更换身份的场景组织迁移前的历史发布使用历史身份REPOSITORYalibaba/OpenSandbox WORKFLOW_REPOSITORY${REPOSITORY} WORKFLOW_REPOSITORY_URLhttps://github.com/${WORKFLOW_REPOSITORY}下游 fork 自行运行发布工作流把验证命令中的opensandbox-group/OpenSandbox替换为对应 fork 的owner/repository身份。workflow_dispatch手动触发的发布注意其 provenance 的source-ref是 dispatch 时选定的 ref通常是refs/heads/main而不是任务后来创建的发布 tag。2.2 发布前置校验与双人控制源码佐证所有托管发布工作流含publish-components.yml、publish-helm-chart.yml第一步都会调用可复用的 release-preflight.yml 工作流它做两件事源码可达性校验verify-release-ref.sh 从origin强制拉取main分支然后用git merge-base --is-ancestor断言发布提交可达自origin/main——即拒绝从游离分支或私有 fork 状态发布。发布环境审批approve-release任务挂在名为release的 GitHub Environment 上非 dry-run 发布必须经该环境审批且触发者不能审批自己的部署从而形成“一人发起、另一名维护者审批”的双人控制见 release-automation.md。此外发布 tag 命名空间受仓库 rulesets 保护只有授权的发布经理能创建匹配 tag且已存在的发布 tag 不可更新、不可删除。这与后文“Helm 发布必须从精确 tag 触发”的设计互为印证。三、验证源码发布2026-08 之前的发布注意源码归档仅在 2026-08 之前release-generic.yml工作流被移除前的发布中产出更晚的发布没有源码归档直接跳过本节。先设置发布 tag用SAFE_TAG消除 tag 中的/因为归档文件名以-连接TAGserver/v0.1.13 SAFE_TAG${TAG//\//-}下载带签名的源码归档与校验和文件gh release download $TAG \ --repo $REPOSITORY \ --pattern opensandbox-${SAFE_TAG}.tar.gz \ --pattern SHA256SUMS核对归档摘要sha256sum -c SHA256SUMS验证源码归档的来源证明gh attestation verify opensandbox-${SAFE_TAG}.tar.gz \ --repo $REPOSITORY \ --signer-workflow ${WORKFLOW_REPOSITORY}/.github/workflows/release-generic.yml验证校验和文件本身的来源证明这一步保证SHA256SUMS本身也出自官方工作流而不是被调包后“自证清白”gh attestation verify SHA256SUMS \ --repo $REPOSITORY \ --signer-workflow ${WORKFLOW_REPOSITORY}/.github/workflows/release-generic.yml由于 Generic Release 工作流以workflow_dispatch方式启动其 provenance 的source-ref是 dispatch 时选定的 ref通常为refs/heads/main而不是该任务创建的发布 tag。若需要断言--source-ref应以 dispatch 时记录的 ref 为准。四、验证容器镜像按 digest 做 cosign 签名与 provenance 双重校验4.1 前置准备安装cosign和gh然后先解析镜像 digest再验签。官方要求“永远按 digest 验证而不是只按可变 tag”——tag 可以被重新指向digest 才是内容寻址的锚点IMAGEdocker.io/opensandbox/execd TAGv1.0.15 DIGEST$(docker buildx imagetools inspect ${IMAGE}:${TAG} --format {{.Manifest.Digest}}) IMAGE_REF${IMAGE}${DIGEST}发布镜像在三个官方仓库中以相同的组件名和相同的 digest发布仓库镜像名模式Docker Hubdocker.io/opensandbox/componentGitHub Container Registryghcr.io/opensandbox-group/opensandbox/component阿里云容器镜像服务sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/component组件名可以是execd、ingress、egress、controller、task-executor、image-committer、nodeagent之一server 镜像使用组件名server。独立环境镜像提示独立的code-interpreter环境镜像从专有的sandbox-images仓库独立发布和维护。v1.1.0及更早的镜像发布仍沿用 OpenSandbox 本仓库的工作流身份publish-components.yml之后新发布的镜像改用该仓库自身的release.yml工作流身份验签时应遵循该仓库的验证文档。4.2 组件镜像验证命令验证cosign无密钥签名断言证书身份匹配“组件镜像发布工作流 受保护 tag 前缀”cosign verify $IMAGE_REF \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ --certificate-identity-regexp ^${WORKFLOW_REPOSITORY_URL}/.github/workflows/publish-components.ymlrefs/tags/(docker|k8s)/[^/]/v?[0-9].*$验证注册表中的 provenance 证明--bundle-from-oci直接从 OCI 仓库拉取签名 bundlegh attestation verify oci://${IMAGE_REF} \ --repo $REPOSITORY \ --bundle-from-oci \ --signer-workflow ${WORKFLOW_REPOSITORY}/.github/workflows/publish-components.ymlserver 镜像使用镜像名docker.io/opensandbox/server并改用 server 工作流的身份正则IMAGEdocker.io/opensandbox/server TAGv0.1.13 DIGEST$(docker buildx imagetools inspect ${IMAGE}:${TAG} --format {{.Manifest.Digest}}) IMAGE_REF${IMAGE}${DIGEST} cosign verify $IMAGE_REF \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ --certificate-identity-regexp ^${WORKFLOW_REPOSITORY_URL}/.github/workflows/publish-server.ymlrefs/tags/server/v[0-9].*$GHCR 与 ACR 的镜像使用相同的 digest 与身份检查只是换镜像名IMAGEghcr.io/opensandbox-group/opensandbox/execd # 或 IMAGEsandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/execd4.3 签名侧的源码实现对照 publish-components.yml 可以看出上述命令为什么能成立工作流仅在push事件命中docker/component/**、k8s/component/**等 tag 时触发构建组件镜像的 digest 从 buildx 构建元数据文件中的containerimage.digest字段解析L149-L159解析失败则直接失败退出保证签名与证明都锚定在同一 digest 上。签名步骤在 L161-L170仅当github.ref_type tag且 tag 不是latest时执行cosign sign --yes一次性对 Docker Hub、ACR、GHCR 三个imagedigest签名——这就是“三仓同 digest 同签名”的来源。证明步骤是三个独立的actions/attestv4步骤L172-L197每个都设置push-to-registry: true把 provenance bundle 推到各自仓库——这正是验证侧可以用--bundle-from-oci从仓库直接取 bundle 的原因。构建完成后工作流还会调用 bump-component-version.sh 自动提交一个 bump PR把仓库内的镜像版本引用更新到刚发布的版本。五、验证语言包Python、JavaScript 与 C#通用做法从各自正常的包仓库下载包文件再对 OpenSandbox 仓库和预期的发布 tag 验证其证明。Python 与 CLI 包以 server 为例python -m pip download opensandbox-server0.1.13 --no-deps gh attestation verify opensandbox_server-0.1.13*.whl \ --repo $REPOSITORY \ --signer-workflow ${WORKFLOW_REPOSITORY}/.github/workflows/publish-server.yml \ --source-ref refs/tags/server/v0.1.13JavaScript 包npm pack alibaba-group/opensandbox0.1.7 gh attestation verify alibaba-group-opensandbox-0.1.7.tgz \ --repo $REPOSITORY \ --signer-workflow ${WORKFLOW_REPOSITORY}/.github/workflows/publish-js-sdks.yml \ --source-ref refs/tags/js/sandbox/v0.1.7C# 包gh attestation verify Alibaba.OpenSandbox.1.0.0.nupkg \ --repo $REPOSITORY \ --signer-workflow ${WORKFLOW_REPOSITORY}/.github/workflows/publish-csharp-sdks.yml \ --source-ref refs/tags/csharp/sandbox/v1.0.0注意--source-ref的 tag 命名规则与 create-release.sh 中“目标注册表”的 tag 约定一一对应SDK/CLI/server 类目标采用target/vversion如server/v0.1.13、js/sandbox/v0.1.7因此--source-ref必须是refs/tags/前缀加上这套规范 tag。六、验证 Helm chart校验和绑定 来源证明 发布状态分级6.1 验证命令Helm 的验证链条比语言包多一环SHA256SUMS把下载的包字节与发布工作流记录的摘要绑定而证明则确认该摘要对应的包确实由预期的 OpenSandbox 工作流产出HELM_CHARTopensandbox HELM_VERSIONchart-version HELM_TAGhelm/${HELM_CHART}/${HELM_VERSION} HELM_PACKAGE${HELM_CHART}-${HELM_VERSION}.tgz gh release download $HELM_TAG \ --repo $REPOSITORY \ --pattern $HELM_PACKAGE \ --pattern SHA256SUMS sha256sum -c SHA256SUMS gh attestation verify $HELM_PACKAGE \ --repo $REPOSITORY \ --signer-workflow ${WORKFLOW_REPOSITORY}/.github/workflows/publish-helm-chart.yml \ --source-ref refs/tags/${HELM_TAG} gh attestation verify SHA256SUMS \ --repo $REPOSITORY \ --signer-workflow ${WORKFLOW_REPOSITORY}/.github/workflows/publish-helm-chart.yml \ --source-ref refs/tags/${HELM_TAG}验证要换 chart 或版本时只需修改HELM_CHART与HELM_VERSION。关于触发 ref手动workflow_dispatch发起的 Helm 发布必须选择精确的已存在发布 tag作为 dispatch ref因此其 provenance 的source-ref与 tag 触发的 Helm 发布一样指向该受保护的 Helm tag。6.2 为什么“同一个包字节”能贯穿验证与发布工作流源码剖析publish-helm-chart.yml 是官方验证命令最直接的对应实现值得完整走一遍串行化Helm 归档内含时间戳同一源码打包两次字节可能不同。因此工作流用concurrency: group: publish-helm-chartL33-L36串行所有 Helm 发布并把唯一一份候选包通过验证与发布而不是在两个环节各打一次包。package 任务校验 tag 格式helm/component/X.Y.Z版本不带v前缀、确认 tag 在 origin 上且本地提交与远端 tag 解析一致、断言Chart.yaml的version/appVersion与请求一致随后helm package产出dist/component-version.tgz和SHA256SUMS并调用 verify-helm-package.sh 做静态契约校验chart 名/版本/appVersion 匹配、helm lint通过、helm template默认渲染出的主镜像后缀必须等于/image:vappVersion对 all-in-one 的opensandboxchart 还额外检查三个内嵌 chartcontroller/server/node-agent齐全、默认渲染包含 controller Deployment 与 server 资源、且默认不含--containerd-socket-path参数L95-L130。校验通过后候选包以私有 artifact 形式“扣押”hold保留 45 天。kind-gate 任务下载扣押的同一份 artifact先重新执行sha256sum -c SHA256SUMS与包契约校验再对opensandboxumbrella chart 通过 smoke-helm-release.sh run-helm-release-e2e.sh 在临时 Kind 集群Kubernetes v1.30.13linux/amd64中安装这个精确的 .tgz做运行时冒烟。publish 任务挂在release环境上需人工审批下载经过运行时门槛的同一份 artifact再次核对源码提交与包字节然后才执行actions/attestv4分别证明.tgz与SHA256SUMSL401-L409最后由 publish-helm-release.sh 以 draft 方式创建/更新 GitHub Release、上传资产并在发布前后做资产 digest 往返校验。从 publish-helm-release.sh 可以看到发布状态的判定逻辑当组件为opensandbox且RUNTIME_VERIFIEDtrue时状态为production-ready否则为package-verified。6.3 Helm 发布状态分级稳定的opensandboxumbrella chart 只有在发布工作流把发布 digest 指向的那个精确打包 .tgz装入临时 Kind 集群之后才被标记production-ready工作流在运行时门槛与发布之间不会重建 chart。门槛必须验证controller 与 server 工作负载变为 Ready所需的 OpenSandbox CRD 建立并可用带鉴权的 server 访问成功且缺失或非法凭据被拒绝一个 BatchSandbox 完成创建、命令执行、删除的完整生命周期。该状态只覆盖 Release notes 中列名的默认核心 profile不为可选的 ingress、egress 策略、快照/暂停-恢复、node-agent、升级或多架构通道背书除非这些 profile 被单独列出。独立的opensandbox-controller、opensandbox-server、opensandbox-node-agentchart 发布仅标记package-verified其验证覆盖打包后的 chart不声称具备稳定 umbrella 发布那样的集成运行时覆盖。每个 Helm GitHub Release 的 notes 都会记录包 SHA-256 摘要、source ref 与提交、验证工作流运行、验证 profile以及做过运行时验证时请求的核心镜像引用、注册表 RepoDigest 与镜像 IDprofile 字段用于区分稳定 umbrella 的 Kind 运行时门槛与仅包验证。由于 chart 默认值仍是文档化的镜像版本 tagproduction-ready记录的是发布时刻的门槛结果并不声称注册表 tag 永远不会被后续变更。七、验证 Java/Kotlin Maven 工件OpenPGP 签名Java/Kotlin 走的是 Maven Central 传统 OpenPGP 签名密钥仅存于 GitHub Actions secrets而不是 Sigstore 证明。下载 jar 与.asc签名解析签名中的密钥 ID从公共 keyserver 拉取公钥后验证curl -O https://repo1.maven.org/maven2/com/alibaba/opensandbox/sandbox/1.0.10/sandbox-1.0.10.jar curl -O https://repo1.maven.org/maven2/com/alibaba/opensandbox/sandbox/1.0.10/sandbox-1.0.10.jar.asc KEY_ID$(gpg --list-packets sandbox-1.0.10.jar.asc | awk /keyid/ { print $NF; exit }) gpg --keyserver hkps://keys.openpgp.org --recv-keys $KEY_ID gpg --verify sandbox-1.0.10.jar.asc sandbox-1.0.10.jarjava/sandbox发布目标是 Kotlin/JVM SDK 的发布列车包含sandbox、sandbox-api、sandbox-pool-redis、code-interpreter与sandbox-bom其余工件按同样模式替换坐标验证。八、适用前提与排错要点发布时点签名/证明只覆盖签名工作流引入之后的发布。对更早的发布gh attestation verify会查不到证明——此时以更新的发布作为已签名证据而不是假设旧发布同样可信。身份匹配三要素gh attestation verify的--repo仓库、--signer-workflow工作流全路径、--source-ref触发 ref必须与发布时的实际触发方式一致手动 dispatch 的发布注意source-ref是 dispatch ref 而非发布 tag。镜像只按 digest 验cosign verify与gh attestation verify oci://的输入都应是imagesha256:...形式避免可变 tag 造成的指认歧义。源码归档已停发2026-08 之后没有源码归档gh release download找不到opensandbox-tag.tar.gz属于预期行为。信任链的底层保障验签命令之所以可信依赖发布侧的两道闸——release-preflight 的“提交可达origin/main release 环境人工审批”release-preflight.yml以及受保护 tag 命名空间只读不可变。从源码结构看验证者核对的 signer-workflow 与 source-ref正是这套闸保证“只有官方 main 分支上的提交、经双人放行”后才会产生的标识。掌握以上流程后你可以为 OpenSandbox 的任何一类安装渠道镜像仓库、PyPI、npm、NuGet、Maven Central、Helm建立可脚本化的供应链校验先固定 digest/校验和再核对 Sigstore或 OpenPGP签名身份与来源 ref最终把“下载到的字节 官方工作流从受保护 tag 构建出的字节”变成一条可复核的断言。【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价