diff --git a/.github/workflows/publish-registries.yml b/.github/workflows/publish-registries.yml index 2c716df..3e8c97d 100644 --- a/.github/workflows/publish-registries.yml +++ b/.github/workflows/publish-registries.yml @@ -11,6 +11,7 @@ on: permissions: contents: read + id-token: write concurrency: group: publish-registries-${{ inputs.release_tag }} @@ -21,7 +22,7 @@ jobs: runs-on: ubuntu-latest env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + NUGET_USER: ${{ vars.NUGET_USER }} RELEASE_TAG: ${{ inputs.release_tag }} steps: - uses: actions/checkout@v7.0.0 @@ -42,8 +43,8 @@ jobs: if ([string]::IsNullOrWhiteSpace($env:CARGO_REGISTRY_TOKEN)) { throw "The CARGO_REGISTRY_TOKEN repository secret is not configured" } - if ([string]::IsNullOrWhiteSpace($env:NUGET_API_KEY)) { - throw "The NUGET_API_KEY repository secret is not configured" + if ([string]::IsNullOrWhiteSpace($env:NUGET_USER)) { + throw "The NUGET_USER repository variable is not configured" } - name: Verify GitHub release and checksums @@ -159,8 +160,16 @@ jobs: } } + - name: Request temporary NuGet API key + id: nuget-login + uses: NuGet/login@v1.2.0 + with: + user: ${{ vars.NUGET_USER }} + - name: Publish CatHub.Protocol shell: pwsh + env: + NUGET_API_KEY: ${{ steps.nuget-login.outputs.NUGET_API_KEY }} run: | dotnet nuget push "release/CatHub.Protocol.$($env:VERSION).nupkg" ` --source https://api.nuget.org/v3/index.json ` diff --git a/docs/architecture/release-and-compatibility.md b/docs/architecture/release-and-compatibility.md index e27ac4f..484c61e 100644 --- a/docs/architecture/release-and-compatibility.md +++ b/docs/architecture/release-and-compatibility.md @@ -17,9 +17,12 @@ tag does not publish to crates.io or NuGet. ## Registry publication order -Registry publication requires the release owner's credentials and must occur only after the -tagged release passes CI. Configure the `CARGO_REGISTRY_TOKEN` and `NUGET_API_KEY` Actions -repository secrets, then dispatch the trusted publication workflow: +Registry publication requires the release owner's authorization and must occur only after the +tagged release passes CI. Configure the `CARGO_REGISTRY_TOKEN` Actions repository secret. +On nuget.org, add a Trusted Publishing policy for repository owner `treitforge`, repository +`cathub`, and workflow file `publish-registries.yml`. Leave the policy environment empty and +set the `NUGET_USER` Actions repository variable to the policy owner's NuGet username. Then +dispatch the publication workflow: ```powershell gh workflow run publish-registries.yml -f release_tag=v0.1.0 @@ -28,13 +31,14 @@ gh workflow run publish-registries.yml -f release_tag=v0.1.0 The workflow rejects a draft or prerelease, verifies every release asset checksum, and checks that the tagged Rust and NuGet versions match. It publishes `cathub-protocol`, waits until Cargo can resolve that exact version from the crates.io index, publishes `cathub`, and then -publishes `CatHub.Protocol`. Finally, it verifies both crates through the crates.io API and -waits for the NuGet package to become available. Existing versions are detected so a retry -can safely continue after a partial registry failure. - -Do not print either registry token. Verify package ownership, the expected version, and the -tag before dispatching the workflow. The daemon crate depends on the same version of -`cathub-protocol`. +uses GitHub OIDC to request a short-lived NuGet API key and publish `CatHub.Protocol`. +Finally, it verifies both crates through the crates.io API and waits for the NuGet package to +become available. Existing versions are detected so a retry can safely continue after a +partial registry failure. + +Do not print the crates.io token or the temporary NuGet key. Verify package ownership, the +expected version, and the tag before dispatching the workflow. The daemon crate depends on +the same version of `cathub-protocol`. ## Wire compatibility