From 68a2693a0f6cc40b6bff229f368cd26ca39a94fc Mon Sep 17 00:00:00 2001 From: Tobias Bieniek <tobias@bieniek.cloud> Date: Mon, 23 Jun 2025 16:35:09 +0200 Subject: [PATCH 1/3] Add Trusted Publishing documentation --- app/router.js | 3 + app/templates/docs/trusted-publishing.hbs | 120 ++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 app/templates/docs/trusted-publishing.hbs diff --git a/app/router.js b/app/router.js index e683b17aebc..4a4a34363c6 100644 --- a/app/router.js +++ b/app/router.js @@ -61,6 +61,9 @@ Router.map(function () { // of the URL to be `/security`. this.route('security'); this.route('data-access'); + this.route('docs', function () { + this.route('trusted-publishing'); + }); this.route('confirm', { path: '/confirm/:email_token' }); this.route('accept-invite', { path: '/accept-invite/:token' }); this.route('support'); diff --git a/app/templates/docs/trusted-publishing.hbs b/app/templates/docs/trusted-publishing.hbs new file mode 100644 index 00000000000..46d544c0455 --- /dev/null +++ b/app/templates/docs/trusted-publishing.hbs @@ -0,0 +1,120 @@ +<PageHeader @title="Trusted Publishing" /> + +<TextContent @boxed={{true}}> + <h2>What is Trusted Publishing?</h2> + <p> + Trusted Publishing is a secure way to publish your Rust crates from GitHub Actions without manually managing API tokens. + It uses OpenID Connect (OIDC) to verify that your workflow is running from your repository, then provides a short-lived token for publishing. + </p> + + <p> + Instead of storing long-lived API tokens in your repository secrets, Trusted Publishing allows GitHub Actions to authenticate + directly with crates.io using cryptographically signed tokens that prove the workflow's identity. + </p> + + <p> + <strong>Note:</strong> crates.io currently only supports GitHub Actions, but we are planning to support other + CI/CD platforms like GitLab CI/CD in the future. + </p> + + <h3>Security Benefits</h3> + <ul> + <li><strong>No long-lived API tokens</strong> to manage or rotate</li> + <li><strong>Tokens automatically expire</strong> after 30 minutes</li> + <li><strong>Repository and workflow verification</strong> prevents unauthorized publishing</li> + <li><strong>OIDC-based cryptographic verification</strong> with GitHub's public JWKS</li> + <li><strong>Optional GitHub Actions environments</strong> for additional access controls</li> + </ul> + + <h2>Quick Start</h2> + <p>Follow these steps to set up Trusted Publishing for your crate:</p> + + <ol> + <li><strong>Configure your crate for Trusted Publishing</strong> in the crates.io settings</li> + <li><strong>Set up your GitHub Actions workflow</strong> with the required permissions and authentication action</li> + <li><strong>Publish your crate</strong> using the automated workflow</li> + </ol> + + <h3>Prerequisites</h3> + <ul> + <li>Your crate must already be published to crates.io (initial publish requires an API token)</li> + <li>You must be an owner of the crate on crates.io</li> + <li>Your repository must be on GitHub</li> + </ul> + + <h2>Configuring Trusted Publishing</h2> + <p> + Configure your crate on crates.io: + </p> + + <ol> + <li>Go to your crate's Settings → Trusted Publishing</li> + <li>Click "Add Trusted Publisher" and fill in: + <ul> + <li><strong>Repository owner:</strong> Your GitHub username or organization</li> + <li><strong>Repository name:</strong> The name of your repository</li> + <li><strong>Workflow filename:</strong> The filename of your GitHub Actions workflow (e.g., "release.yml")</li> + <li><strong>Environment:</strong> Optional environment name if you're using GitHub environments</li> + </ul> + </li> + <li>Save the configuration</li> + </ol> + + <h2>GitHub Actions Setup</h2> + <p> + Create a workflow file at <code>.github/workflows/release.yml</code>. This example workflow will automatically publish your crate each time you push a version tag (like <code>v1.0.0</code>): + </p> + + {{!-- template-lint-disable no-whitespace-for-layout --}} + <pre><code>name: Publish to crates.io +on: + push: + tags: ['v*'] # Triggers when pushing tags starting with 'v' +jobs: + publish: + runs-on: ubuntu-latest + environment: release # Optional: for enhanced security + permissions: + id-token: write # Required for OIDC token exchange + contents: read # Required to checkout repository + steps: + - uses: actions/checkout@v4 + - uses: rust-lang/crates-io-auth-action@v1 + id: auth + - run: cargo publish + env: + CARGO_REGISTRY_TOKEN: $\{{ steps.auth.outputs.token }}</code></pre> + + <p> + <strong>Optional:</strong> For enhanced security, create a GitHub Actions environment named "release" + in your repository settings with protection rules like required reviewers or deployment branches. + </p> + + <h2>Security & Best Practices</h2> + <ul> + <li><strong>Use specific workflow filenames</strong> to reduce the attack surface</li> + <li><strong>Use GitHub Actions environments</strong> with protection rules for sensitive publishing</li> + <li><strong>Limit workflow triggers</strong> to specific tags or protected branches</li> + <li><strong>Review all actions used</strong> in your release workflow</li> + <li><strong>Monitor publishing activities</strong> through crates.io email notifications</li> + </ul> + + <p> + <strong>How it works:</strong> GitHub Actions generates an OIDC token that proves your workflow's identity. + The <code>rust-lang/crates-io-auth-action</code> exchanges this for a 30-minute access token that + <code>cargo publish</code> uses automatically. + </p> + + <h2>Migration from API Tokens</h2> + <p> + To migrate from API tokens: set up Trusted Publishing following the steps above, test it, + then remove the API token from your repository secrets. Both methods can be used simultaneously during transition. + </p> + + <h2>Additional Resources</h2> + <ul> + <li><a href="https://rust-lang.github.io/rfcs/3691-trusted-publishing-cratesio.html">RFC 3691: Trusted Publishing for crates.io</a></li> + <li><a href="https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect">GitHub: About security hardening with OpenID Connect</a></li> + <li><a href="https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment">GitHub: Using environments for deployment</a></li> + </ul> +</TextContent> \ No newline at end of file From a9da259db956f36add0812d4e69416ff817e7e68 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek <tobias@bieniek.cloud> Date: Mon, 23 Jun 2025 17:11:06 +0200 Subject: [PATCH 2/3] crate/settings: Add "Learn more" button to Trusted Publishing section --- app/styles/crate/settings/index.module.css | 9 ++++++++- app/templates/crate/settings/index.hbs | 17 +++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/styles/crate/settings/index.module.css b/app/styles/crate/settings/index.module.css index 6c8ec0daeac..67132621c49 100644 --- a/app/styles/crate/settings/index.module.css +++ b/app/styles/crate/settings/index.module.css @@ -1,7 +1,14 @@ -.owners-header, .trusted-publishing-header { +.header { display: flex; justify-content: space-between; align-items: center; + flex-wrap: wrap; + gap: var(--space-s); + margin: var(--space-m) 0; + + > h2 { + margin: 0; + } } .email-form { diff --git a/app/templates/crate/settings/index.hbs b/app/templates/crate/settings/index.hbs index f4dea175696..1e797bfa3fc 100644 --- a/app/templates/crate/settings/index.hbs +++ b/app/templates/crate/settings/index.hbs @@ -2,7 +2,7 @@ <CrateHeader @crate={{this.crate}} /> -<div local-class="owners-header"> +<div local-class="header"> <h2>Owners</h2> {{#unless this.addOwnerVisible}} <button type="button" class="button button--small" data-test-add-owner-button {{on "click" this.showAddOwnerForm}}>Add Owner</button> @@ -56,11 +56,16 @@ {{! The "Trusted Publishing" section is hidden for now until we make this feature publicly available. }} {{#if this.githubConfigs}} - <div local-class="trusted-publishing-header"> + <div local-class="header"> <h2>Trusted Publishing</h2> - <LinkTo @route="crate.settings.new-trusted-publisher" class="button button--small" data-test-add-trusted-publisher-button> - Add - </LinkTo> + <div> + <LinkTo @route="docs.trusted-publishing" class="button button--tan button--small" data-test-trusted-publishing-docs-button> + Learn more + </LinkTo> + <LinkTo @route="crate.settings.new-trusted-publisher" class="button button--small" data-test-add-trusted-publisher-button> + Add + </LinkTo> + </div> </div> <table local-class="trustpub" data-test-trusted-publishing> @@ -95,7 +100,7 @@ </table> {{/if}} -<h2>Danger Zone</h2> +<h2 local-class="header">Danger Zone</h2> <div> <LinkTo @route="crate.delete" class="button button--red" data-test-delete-button> From 012fe63a951d8ef0e9ced97db19141beb94a37e2 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek <tobias@bieniek.cloud> Date: Mon, 23 Jun 2025 19:47:17 +0200 Subject: [PATCH 3/3] docs/trusted-publishing: Enable syntax highlighting for YAML snippet --- app/templates/docs/trusted-publishing.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/docs/trusted-publishing.hbs b/app/templates/docs/trusted-publishing.hbs index 46d544c0455..ab5d19adb0c 100644 --- a/app/templates/docs/trusted-publishing.hbs +++ b/app/templates/docs/trusted-publishing.hbs @@ -66,7 +66,7 @@ </p> {{!-- template-lint-disable no-whitespace-for-layout --}} - <pre><code>name: Publish to crates.io + <pre><code class="language-yaml" {{highlight-syntax}}>name: Publish to crates.io on: push: tags: ['v*'] # Triggers when pushing tags starting with 'v'