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 &amp; 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'