Ivan's Blog
主题

Rust crate release

Rust crate release 是 Rust library crate 发布到 crates.io 时的媒介合同:一个明确的源码版本必须先通过 manifest、package 和 dry-run 检查,再以同一 source SHA 形成 crates.io package、不可变 Git tag 和 GitHub Release 三面一致的 release unit。

  • 运维
  • 工具

目录

Definition

Rust crate release 是 Rust library crate 发布到 crates.io 时的媒介合同:一个明确的源码版本必须先通过 manifest、package 和 dry-run 检查,再以同一 source SHA 形成 crates.io package、不可变 Git tag 和 GitHub Release 三面一致的 release unit。它回答“这个 crate 版本怎样安全、可复核地出现在公开 registry 和 GitHub”,不回答 PR 如何表达 intent、哪些 check 是 required、何时触发 workflow,或失败通知发往哪里。

Topic 的输入是一个确定的源码版本和其公开 registry 目标。它适用于公开 crates.io library crate,包括从零到一的 bootstrap、Trusted Publisher/OIDC 迁移、后续版本和发布失败后的幂等恢复;私有 registry、binary application 或完整产品 deployment 需要另外的交付合同。

When to use

当仓库的 Cargo.toml 是可发布 library crate,且目标是 crates.io 时使用。若改动涉及 crate metadata、package 内容、版本策略、cargo publish、GitHub release/tag 绑定、registry 可见性或发布凭据迁移,就应命中本 Topic。仅有 GitHub Release 而没有 crates.io package,或只发布内部 artifact,不足以使用本 Topic。

不要因为仓库存在 label-gate.yml、.github/quality-gates.json 或通知 workflow 就把它们纳入本 Topic 的核心;这些分别属于 PR label release、Quality gates 和 Release failure notification。本 Topic 只接收一个已经确定的源码版本,不规定 label、channel、触发方式、manual-dispatch 输入、签名 intent、required checks、branch protection 或通知策略。

Habits / defaults

  • 先从干净、已验证的提交确定 source SHA,检查 Cargo.toml 的 package version、name、license、repository、readme 和 cargo metadata,再执行 cargo package --locked;检查包内文件清单后,对尚未存在的版本执行 cargo publish --locked --dry-run。dry-run 通过不等于 registry 已发布,仍需做 post-publish 查询。
  • 首发有明确的 bootstrap 例外:Trusted Publisher 只能在 crate 已经存在首个版本后配置。owner 从已验证源码提交用最小权限、短生命周期 crates.io token 发布一次;确认 https://crates.io/api/v1/crates/<crate>/<version> 可见后立即撤销 token,再在 crates.io 配置 GitHub Trusted Publisher,并完成一次 OIDC exchange smoke check。后续版本只走 rust-lang/crates-io-auth-action@v1 等 OIDC 路径,不保留长寿命 token fallback。
  • 每个正式或 prerelease 版本都必须把 crate@version、release/<version> tag 和同 tag GitHub Release 绑定到同一个 source SHA。prerelease 可以使用 Cargo 合法的 -beta.N 或 -dev.N 版本,但 tag、Release class 和 registry version 必须保持同一语义;不要为此引入 type:*、channel:* 或其他 label 编排。
  • 发布前检查 registry 是否已有该版本,发布后确认 registry 可见且未被 yank,并保存能够连接 source SHA、版本和三面公开地址的 release receipt。已有版本不可再次 cargo publish;yank、超时或 workflow 重跑都不能改变这个不重发约束。
  • recovery 先按精确版本查询 crates.io、Git tag 和 GitHub Release,判断缺失面和 source SHA 是否一致,再只补齐缺失的公开面。crate 已存在时不得再次 publish;若已有 tag 指向不同 SHA、Release 不是同一 tag,或状态无法证明一致,应停止并人工处理。fusb302-rs 的 0.2.2 只提供了精确 tag 查询加 bounded retry 的局部 recovery 证据,不规定所有仓库的重试时长。

Reference implementations

  • projects/fusb302-rs.md:完整记录 0.1.0 owner bootstrap、0.2.0/0.2.1 OIDC 发布、0.2.2 recovery,以及 release.yml 的 manifest/package/registry 检查。
  • Cargo 的 publishing contract:cargo package、cargo publish --dry-run、package 文件清单和已发布版本不可覆盖/删除,见 https://doc.rust-lang.org/cargo/reference/publishing.html。
  • crates.io Trusted Publishing 的迁移边界和 GitHub OIDC action,见 https://blog.rust-lang.org/2025/07/11/crates-io-development-update-2025-07/;registry token scope 和撤销原则见 https://blog.rust-lang.org/inside-rust/2023/05/09/api-token-scopes/。

Failure modes

  • 首发前就假设 Trusted Publisher 可用,或把长期 CARGO_REGISTRY_TOKEN 留在 CI,会让从零到一流程无法启动或扩大凭据暴露面;首发必须由 owner 做一次最小 token bootstrap,随后撤销并迁移 OIDC。
  • 没有先查 registry 就重跑 cargo publish,会把 crates.io 的永久版本约束变成重复发布错误。看到版本已存在时,应检查其 tag、GitHub Release 和 source SHA,走 recovery 而不是重发。
  • 只验证 GitHub Release 或移动 tag,未验证 package 内容和 crates.io 版本,会形成无法证明同源的半个 release unit。三面任一绑定不同 SHA 都应阻断公开完成状态。
  • 把 cargo package 的 .cargo_vcs_info.json 当成完整 provenance,或把 dry-run 当成 registry visibility,会高估证据;需要同时保存 manifest/package、source SHA、精确 tag 和 registry 查询结果。
  • 将 PR label release 的 label、Quality gates 的 required checks、具体 trigger/manual input、签名 intent、branch protection 或 Release failure notification 的 transport 写进本 Topic,会破坏职责边界。它们只能作为相邻 Topic 引用或项目编排事实。
  • 把 0.2.2 的 GitHub Release 列表短暂不可见误写成固定发布流程,会导致不必要的全局等待或重复操作;项目可以采用精确 tag 查询和 bounded retry,但默认合同仍是查询后补齐且不重发。

Evidence index

  • projects/fusb302-rs.md
  • skills/style-playbook/references/data/topics/rust-crate-release.json
  • skills/style-rust-crate-release/SKILL.md
  • .github/workflows/release.yml
  • scripts/release_surfaces.py
  • scripts/registry_state.py
  • https://doc.rust-lang.org/cargo/reference/publishing.html
  • https://doc.rust-lang.org/cargo/reference/registry-authentication.html
  • https://blog.rust-lang.org/2025/07/11/crates-io-development-update-2025-07/