blob: 897d398fc3d099307c1914f803edafa6cee681fc [file] [view]
# Rust release helpers
These scripts define and publish the crates.io package set for Apache Reqsign.
## Publish plan
`plan.py` reads `cargo metadata --no-deps`, selects workspace packages that can
publish to crates.io, and orders them by non-dev local dependencies using
Python's `TopologicalSorter`.
```bash
python3 .github/scripts/release_rust/plan.py
```
The release workflow first runs the complete workspace dry run:
```bash
cargo publish --workspace --dry-run
```
It then runs `publish.py`. The publisher uploads one package at a time, requests
and revokes a fresh GitHub OIDC-derived crates.io token for every attempt,
retries crates.io rate limits, and treats an already-published matching
name/version as a completed step. Individual uploads use `--no-verify` because
the workflow has already verified the complete package set from the same
commit.
Live publishing requires the `release` GitHub environment and a job with
`id-token: write`. It never reads a long-lived crates.io token.
## Bootstrap crate names
Trusted Publishing cannot create the first version of a crate.
`bootstrap.py` reserves new names and audits the complete publish plan:
- `discover` reports missing names and existing `0.0.0` placeholders without
credentials.
- `apply` authenticates every existing crate before any write, publishes a
dependency-free `0.0.0` namespace reservation for each missing name,
configures the exact `apache/reqsign`, `release.yml`, `release`
Trusted Publisher, enables `trustpub_only`, and performs a final authenticated
audit.
- `verify` checks public crate metadata and `trustpub_only`. It cannot verify
ownership or the exact Trusted Publisher because those APIs require
authentication.
The protected `rust-bootstrap` job audits the complete plan before any write,
including when no names are missing. It never changes an established crate. Existing crates must be migrated independently before the
workflow can succeed.
Published crate metadata may still reference the former repository URL or the
former project name in a `0.0.0` placeholder description. The audit accepts that
historical metadata, but every Trusted Publisher must target `apache/reqsign`.
New placeholders and releases use the current project name and repository URL.
Version `0.0.0` is an irreversible namespace reservation. It is not an ASF
software release and contains no implementation.
The local dispatch helper uses GitHub REST API version `2026-03-10` to obtain
the exact workflow run ID, then checks its commit and waits for completion.
These are repository-specific scripts: run them with normal Python (without
`-O` or `PYTHONOPTIMIZE`, which disable assertions). Cargo and crates.io response
fields are used directly; unexpected package or publisher state fails an
assertion. Failed API requests stop the run; rerun after resolving the failure.
Only Cargo publish rate limits and public metadata propagation are retried.
## Tests
```bash
python3 -m unittest discover \
-s .github/scripts/release_rust \
-p "test_*.py"
```