Skip to content

ci: publish with NuGet trusted publishing instead of a stored API key - #28

Merged
ivanvyd merged 1 commit into
mainfrom
chore/trusted-publishing
Aug 1, 2026
Merged

ci: publish with NuGet trusted publishing instead of a stored API key#28
ivanvyd merged 1 commit into
mainfrom
chore/trusted-publishing

Conversation

@ivanvyd

@ivanvyd ivanvyd commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Replaces the long-lived NUGET_API_KEY secret with OIDC-based trusted publishing.

GitHub mints a short-lived token, nuget.org verifies it against a policy naming this exact repository, workflow file and environment, and returns a key valid for one hour. Nothing long-lived is stored in the repo — there is no key to leak, rotate, or scope too widely, and a stolen token cannot be replayed from another workflow.

The exchange runs immediately before the push: the key lasts an hour and each OIDC token buys exactly one key, so requesting it too early is a real failure mode rather than a theoretical one.

NuGet/login is pinned to a commit SHA like every other action here. Worth noting the v1 tag is annotated, so the tag-object SHA (ebc737b) is not the commit SHA — pinned to the commit 8d196754, which v1.2.0 also points at.

Setup this requires (documented in RELEASING.md)

  1. A trusted publishing policy on nuget.org — owner ivanvyd, repo lakespeak, workflow file release.yml (name only, no path), environment nuget.
  2. A NUGET_USER secret holding the nuget.org profile name, not an email.
  3. The nuget environment with a required reviewer — which is both the approval gate and what the policy binds to.

None of these exist yet; the workflow fails early with a clear message rather than half-publishing.

GitHub mints a short-lived OIDC token, nuget.org verifies it against a policy
naming this exact repository, workflow file and environment, and returns a key
valid for one hour. Nothing long-lived is stored in the repository, so there is
no key to leak, rotate, or scope too widely -- and a leaked key cannot be
replayed from anywhere else, because the token only validates from this
workflow.

The exchange happens immediately before the push: the temporary key lasts an
hour and each OIDC token buys exactly one key, so requesting it early enough to
expire is a real failure mode.

NuGet/login is pinned to a commit SHA like every other action here. Note that
the v1 tag is annotated, so the tag object SHA is not the commit SHA -- pinned
to the commit, 8d196754, which v1.2.0 also points at.

RELEASING.md now walks through the three prerequisites step by step: the policy
fields on nuget.org (workflow file name only, no path), the NUGET_USER secret
holding the profile name rather than an email, and the environment whose
required reviewer is both the approval gate and what the policy binds to.
@ivanvyd
ivanvyd force-pushed the chore/trusted-publishing branch from 13c10fc to 7fb76c2 Compare August 1, 2026 10:32
@ivanvyd
ivanvyd merged commit 3f59f15 into main Aug 1, 2026
10 checks passed
@ivanvyd
ivanvyd deleted the chore/trusted-publishing branch August 1, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant