Skip to content

Commit 5df2f6f

Browse files
authored
Merge pull request #157 from github/bb8gh/trusted-publishing
Publish crates to crates.io via trusted publishing
2 parents c621a54 + 710ca0e commit 5df2f6f

6 files changed

Lines changed: 121 additions & 6 deletions

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Publishes a single crate from this workspace to crates.io using Trusted Publishing.
2+
#
3+
# There is no `CARGO_REGISTRY_TOKEN` secret: `rust-lang/crates-io-auth-action` exchanges this
4+
# workflow's GitHub OIDC identity for a short-lived crates.io token that expires after the run.
5+
#
6+
# One-time setup per crate, on https://crates.io/crates/<crate>/settings/trusted-publishing:
7+
# Repository owner: github
8+
# Repository name: rust-gems
9+
# Workflow name: publish-crates.yaml
10+
# Environment: crates-io
11+
# The environment name must match the `environment:` value below exactly, or crates.io rejects
12+
# the token exchange. A crate must be published manually once before it can be configured.
13+
name: Publish crates
14+
15+
on:
16+
workflow_dispatch:
17+
inputs:
18+
crate:
19+
description: Crate to publish, at the version in its Cargo.toml
20+
required: true
21+
type: choice
22+
options:
23+
- bpe
24+
- bpe-openai
25+
- casefold
26+
- commutative_hasher
27+
- consistent-choose-k
28+
- geo_filters
29+
- hash-sorted-map
30+
- sparse-ngrams
31+
- string-offsets
32+
crate_name_override:
33+
description: Crate name to publish instead, for crates missing from the list above
34+
required: false
35+
type: string
36+
dry_run:
37+
description: Package and verify the crate without uploading it
38+
type: boolean
39+
default: false
40+
41+
permissions:
42+
contents: read
43+
id-token: write # Required to mint the crates.io OIDC token.
44+
45+
jobs:
46+
publish:
47+
name: Publish ${{ inputs.crate_name_override || inputs.crate }}
48+
runs-on: ubuntu-latest
49+
# Gate releases behind an environment so protection rules apply, and so the OIDC claim
50+
# matches the trusted publisher configured on crates.io.
51+
environment: crates-io
52+
steps:
53+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
54+
55+
- uses: rui314/setup-mold@7e4f20ad28a2e8ca6fd0892ccf72e2abb706b9c3
56+
57+
# `crate_name_override` wins when set, because a choice input always has one option
58+
# selected and so can't express "none of these".
59+
- name: Resolve crate
60+
id: resolve
61+
env:
62+
CHOICE: ${{ inputs.crate }}
63+
OVERRIDE: ${{ inputs.crate_name_override }}
64+
run: |
65+
crate=$(printf '%s' "${OVERRIDE:-$CHOICE}" | tr -d '[:space:]')
66+
# Check the name against the workspace so a typo fails here with a clear message,
67+
# and so nothing unvetted reaches the cargo commands below.
68+
publishable=$(cargo metadata --no-deps --format-version 1 |
69+
jq -r '.packages[] | select(.publish != []) | .name')
70+
if ! printf '%s\n' "$publishable" | grep -qxF "$crate"; then
71+
echo "::error::'$crate' is not a publishable crate. Available: $(echo $publishable)"
72+
exit 1
73+
fi
74+
echo "crate=$crate" >> "$GITHUB_OUTPUT"
75+
76+
- name: Package and verify
77+
run: cargo publish --package "$CRATE" --dry-run
78+
env:
79+
CRATE: ${{ steps.resolve.outputs.crate }}
80+
81+
- name: Get crates.io token
82+
if: ${{ !inputs.dry_run }}
83+
id: auth
84+
uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5
85+
86+
# Verification already happened in the dry run above, on this exact tree.
87+
- name: Publish
88+
if: ${{ !inputs.dry_run }}
89+
run: cargo publish --package "$CRATE" --no-verify
90+
env:
91+
CRATE: ${{ steps.resolve.outputs.crate }}
92+
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

CONTRIBUTING.md

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ These are one time installations required to be able to test your changes locall
1515
## Submitting a pull request
1616

1717
1. [Fork][fork] and clone the repository
18-
1. Make sure the tests pass on your machine: `make test`
19-
1. Make sure linter passes on your machine: `make lint`
20-
1. Create a new branch: `git checkout -b my-branch-name`
21-
1. Make your change, add tests, and make sure the tests and linter still pass
22-
1. Push to your fork and [submit a pull request][pr]
23-
1. Pat yourself on the back and wait for your pull request to be reviewed and merged.
18+
2. Make sure the tests pass on your machine: `make test`
19+
3. Make sure linter passes on your machine: `make lint`
20+
4. Create a new branch: `git checkout -b my-branch-name`
21+
5. Make your change, add tests, and make sure the tests and linter still pass
22+
6. Push to your fork and [submit a pull request][pr]
23+
7. Pat yourself on the back and wait for your pull request to be reviewed and merged.
2424

2525
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
2626

@@ -29,6 +29,25 @@ Here are a few things you can do that will increase the likelihood of your pull
2929
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
3030
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
3131

32+
## Releasing a crate
33+
34+
Crates are published to [crates.io](https://crates.io) with
35+
[Trusted Publishing](https://crates.io/docs/trusted-publishing), so there is no long-lived API
36+
token stored in this repository. The `Publish crates` workflow exchanges its GitHub OIDC identity
37+
for a token that is revoked when the run ends.
38+
39+
1. Bump `version` in the crate's `Cargo.toml` and merge that change to `main`.
40+
2. Run the [`Publish crates`](../../actions/workflows/publish-crates.yaml) workflow via
41+
*Run workflow*, pick the crate, and optionally tick *dry-run* first to package and verify it
42+
without uploading. If a newly added crate isn't in the dropdown yet, type its name into
43+
*crate_name_override* instead — and add it to the dropdown in `publish-crates.yaml` while
44+
you're there.
45+
46+
A crate has to be published manually once before crates.io will let you configure a trusted
47+
publisher for it. Configure it at `https://crates.io/crates/<crate>/settings/trusted-publishing`
48+
with repository `github/rust-gems`, workflow `publish-crates.yaml`, and environment `crates-io`.
49+
The environment name must match the workflow's `environment:` exactly or the token exchange fails.
50+
3251
## Resources
3352

3453
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)

crates/bpe/benchmarks/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[package]
22
name = "bpe-benchmarks"
33
edition = "2021"
4+
publish = false
45

56
[lib]
67
path = "lib.rs"

crates/bpe/tests/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[package]
22
name = "bpe-tests"
33
edition = "2021"
4+
publish = false
45

56
[dependencies]
67
bpe = { path = "../../bpe", features = ["rand"] }

crates/casefold/benchmarks/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[package]
22
name = "casefold-benchmarks"
33
edition = "2021"
4+
publish = false
45

56
[lib]
67
path = "lib.rs"

crates/consistent-choose-k/benchmarks/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[package]
22
name = "consistent-choose-k-benchmarks"
33
edition = "2021"
4+
publish = false
45

56
[[bench]]
67
name = "performance"

0 commit comments

Comments
 (0)