skip to content

When a CI workflow publishes via trusted publishing, what does the registry actually verify?

level: middleimportance: should knowfreq 48%

answer

  1. policy registered once, evidence per run
  2. signature, audience, claims, expiry
  3. bound to a file, not a person
  4. matched against the registered publisher
  5. returns a package-scoped short token

basics

~20 s

The registry validates the OIDC token's signature against the issuer's keys, checks the audience names this registry, and matches the run's repository and workflow claims against the publisher a project owner registered. Only then is a package-scoped token minted.

solid answer

~40 s

Four things, in order. **Signature and issuer**: the token must be signed by a key the named CI provider publishes, so nobody can forge one. **Audience**: it must be minted for this registry, so an identity token obtained for another service cannot be replayed here. **Claims against the registered publisher**: the registry compares the repository, the workflow file, and optionally the environment and ref against what a project owner configured in advance for this package. **Expiry**: the token is valid for a very short window. If all four hold, the registry issues an upload credential scoped to that single package. The detail worth stating is that the binding is to a *workflow file*, not a person - so a contributor who adds a new workflow to the same repository still cannot publish.

go deeper

for a junior

Know that a project owner configures, at the registry, which repository and workflow may publish, and that the registry checks an identity token against that configuration before letting anything upload.

for a middle

Be ready to walk all four checks - signature and issuer, audience, claims against the registered publisher, expiry - and to explain why the claims are believable: the CI provider signs them, not the pipeline author.

for a senior

Show you would pin the registration as narrowly as the registry allows and would delete the superseded API token, and be able to name what a stale or over-broad registration exposes.

for a principal

Be able to argue how narrowly to pin across an estate - workflow and environment everywhere, or repository-level where teams need flexibility - and who owns the registrations when the publishing team changes.

## The two halves of the trust decision A trusted-publishing exchange is a small identity-federation problem. There are two pieces of state: - **What the project owner registered** at the registry, ahead of time: an issuer (the CI provider), a repository, a workflow file, and often an environment name. This is the policy. - **What arrives at release time**: a signed OIDC ID token whose claims describe the run that is asking. This is the evidence. The registry's job is to decide whether the evidence satisfies the policy. Everything below is that decision. ## What gets checked **1. Signature and issuer.** The token is a signed JWT. The registry fetches the issuer's public keys from the issuer's well-known endpoint and verifies the signature. This is the whole basis of trust: the claims are believable because the CI provider - not the person writing the pipeline - filled them in and signed them. A developer cannot hand-write a token claiming to be someone else's repository, because they cannot produce the signature. **2. Audience.** The token carries an `aud` claim naming who it is for. The registry rejects tokens minted for a different audience. This matters because a job may legitimately request identity tokens for several services in the same run; without an audience check, a token obtained by one service could be turned around and replayed against another that trusts the same issuer. **3. Claims versus the registered publisher.** This is the substance. Typical claims describe: - the **repository** (owner and name), and often a repository ID that survives a rename; - the **workflow** that is running, identified by its path in the repository; - the **ref** - branch or tag - the run is on; - the **environment**, if the job is running in a deployment environment. The registry compares these against the registered publisher for this package and refuses anything that does not match. **4. Freshness.** Standard JWT time checks. These tokens are deliberately short-lived; the exchange is meant to happen seconds after minting. On success the registry mints and returns an upload credential that is **scoped to that project** and valid for a short window - long enough to upload, not long enough to be worth stealing. ## Why binding to a workflow file, not a person, is the good part Consider a Rust command-line tool released to crates.io. The registered publisher names the repository *and* one workflow file - the release workflow on the default branch. Now a contributor with permission to open pull requests, or even to push a branch, adds a second workflow to the same repository that tries to publish. It fails. Their workflow's identity claim names a different workflow path, so the claims do not satisfy the policy and no upload credential is ever minted. The credential is not scoped to a *human maintainer* who might be phished, nor to a *repository* that many people can write to; it is scoped to one code path that is itself protected by branch protection and code review. This is the property to state out loud in an interview, because it is what distinguishes a good mental model from a vague one. People often assume trusted publishing means *this repository may publish*. It means *this workflow, in this repository, on a ref or in an environment you named, may publish* - and every extra claim you pin narrows who inside the organisation can cause a publish. ## The knobs, and what each buys | Claim you constrain | Attack it closes | |---|---| | Repository | A different repository under the same organisation publishing your package | | Workflow file | Someone adding a second, unreviewed workflow to your repository | | Ref (branch or tag) | A release triggered from an unprotected feature branch | | Environment | An unreviewed run publishing, when the environment requires an approval | The environment row is worth dwelling on. Tying the publisher to a deployment environment lets you require a human approval before the job that can obtain the publish credential even starts - so the release path gets a second pair of eyes without the registry needing to know anything about your review process. ## Common mistakes in the configuration - **Registering a publisher too broadly**, so any workflow in the repository qualifies. That gives away the workflow-file property described above and puts publish rights in reach of anyone who can add a file. - **Leaving a stale registration** pointing at a repository that has been renamed, transferred, or archived - especially dangerous if the old name can be re-registered by somebody else. - **Keeping the old long-lived token active** after switching. If the token still exists, nothing has been removed; you have added a second door, not replaced the first. Deleting the superseded credential is the step that makes the migration real. - **Assuming the minted credential is harmless because it is short-lived.** It is live for the duration of the job, and any step in that job can use it. ## The one-sentence version The registry verifies that an identity token, signed by a CI provider it trusts and minted for it specifically, describes exactly the repository and workflow a project owner authorised in advance - and only then hands back a package-scoped credential that expires in minutes.

  • A repository is renamed after the publisher was registered. What can go wrong?
    Claims that carry the textual owner and repository name stop matching, so releases start failing - the visible symptom. The dangerous case is the reverse: the old name becomes available for someone else to claim, and a stale registration that matches on name alone could then be satisfied by a repository you do not control. Registrations that also pin a numeric repository ID resist this.
  • Why tie the trusted publisher to a deployment environment rather than only a branch?
    An environment can carry a gate - required reviewers, a wait timer, restricted refs - that must be satisfied before the job starts. Pinning the publisher to it means a run that skipped the gate never obtains an identity token that matches, so the approval requirement is enforced at the registry rather than only by convention inside the pipeline.
  • What should you do with the old API token once trusted publishing works?
    Delete it. Until you do, the long-lived, portable, account-wide credential still exists and still publishes, so you have added a safer path without closing the unsafe one. Cutting over means proving the new path works on one release and then removing the secret from CI and the token from the registry.

saying these in an interview costs you the question

  • Says the registry trusts any token from the CI provider
  • Ignores the audience check, so replay is possible
  • Thinks the binding is to a maintainer account
  • Believes any workflow in the repository can publish
  • Leaves the superseded API token in place after migrating

context