From 160f2c29e2a5804d5533c79a97fb2c94887f80cc Mon Sep 17 00:00:00 2001 From: GeiserX <9169332+GeiserX@users.noreply.github.com> Date: Mon, 15 Jun 2026 22:08:44 +0200 Subject: [PATCH] docs: document the new-crate token bootstrap for trusted publishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A brand-new crate cannot be created by OIDC trusted publishing — crates.io returns 403 "Trusted Publishing tokens do not support creating new crates", so the first version needs a one-time manual cargo publish with a token. This bit the v0.40.0 release when ts_netmon was added. Add an explicit new-crate checklist to RELEASING.md so the next new crate does the bootstrap up front. Signed-off-by: GeiserX <9169332+GeiserX@users.noreply.github.com> --- docs/RELEASING.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 04ee49e..584b12e 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -68,6 +68,31 @@ publisher with: Until a crate has its trusted publisher configured, `release.yml`'s publish step fails *for that crate only*; the version-bump + tag + GitHub-Release half (release-please.yml) works regardless. +### Adding a NEW `geiserx_*` crate (token bootstrap REQUIRED) + +A brand-new crate cannot be created by OIDC trusted publishing — crates.io rejects it with +`403 Forbidden: Trusted Publishing tokens do not support creating new crates. Publish the crate +manually, first`. So the **first** version of any new crate needs a one-time token bootstrap, in +addition to the usual checklist. When you add a new `ts_*` crate, do ALL of: + +1. Add it to the workspace `members` + `[workspace.dependencies]` (with `version = "X.Y.Z" + # x-release-please-version`). +2. **Add it to `scripts/publish-crates.sh`'s `CRATES=(…)` array in leaf-first order**, BEFORE any + crate that depends on it (omitting it breaks the whole publish at the first dependent — e.g. + `ts_netmon` missing broke `ts_runtime`'s publish), and bump the `43`→`N` count strings in both + `scripts/publish-crates.sh` and `.github/workflows/release.yml` (incl. the job name). +3. **Token bootstrap (one-time, needs a crates.io token):** + ```sh + export CARGO_REGISTRY_TOKEN= + cargo publish -p geiserx_ # creates the crate + its first version + ./scripts/setup-trusted-publishing.sh # registers GeiserX/tailscale-rs as its trusted publisher (idempotent; derives the list from cargo metadata, so it picks up the new crate) + ``` + After that, CI's OIDC trusted publishing handles the crate on every future release. +4. If a release already published the rest of the workspace but failed at the new crate, finish it: + bootstrap the crate (step 3), then re-dispatch the `Release` workflow for the same tag + (`gh workflow run Release --ref main`; `SKIP_PUBLISHED=1` resumes past the already-published + versions). + > **Bulk option (recommended over 43 web forms):** `scripts/setup-trusted-publishing.sh` registers > the trusted publisher on every publishable crate in one pass via the crates.io API. It is > idempotent (skips crates already configured) and derives the crate list from `cargo metadata`, so