-
Notifications
You must be signed in to change notification settings - Fork 0
Trusted Publishing
Last synced from
docs/engineering/plans/release-pipeline-github-ui-setup.mdon 2026-08-05. The repo file is the source of truth. If the two diverge, follow the repo.
This page is the one-time setup procedure for npm Trusted Publishing on
@deessejs/fp. It is meant to be read once, when the project first adopts
Trusted Publishing, and then archived in the maintainer's memory. Day-to-day
release operations are documented in the Release Process page,
not here.
Outline
- What is Trusted Publishing
- Why we use it
- Prerequisites
- npm-side configuration
- GitHub-side configuration
- Validating the setup
- Revoking any existing NPM_TOKEN
- What to do when the publisher needs to change
- Related documents
Trusted Publishing is npm's mechanism for authenticating a publish without a long-lived secret. It is a form of OpenID Connect (OIDC) — npm verifies that a publish request came from a specific GitHub Actions workflow in a specific repository, and only then accepts the publish.
The flow:
- GitHub Actions runs
publish.yml. The workflow has theid-token: writepermission, which lets it mint a short-lived OIDC token. - The workflow calls
pnpm changeset publish. npm sees that noNPM_TOKENis present in the environment and that an OIDC token is, instead. - npm validates the OIDC token against the Trusted Publisher configuration registered on the package (see § 4): it checks the repository, workflow filename, and environment.
- If validation passes, npm publishes. If not, npm refuses with HTTP 403.
The OIDC token is short-lived (about 15 minutes). It is generated fresh for every workflow run and discarded after the publish. There is no secret to leak because the token is never stored.
The previous approach — a long-lived NPM_TOKEN stored as a GitHub secret — has
three concrete problems:
- Secret leakage. A long-lived token in a GitHub secret can leak through workflow logs, fork PRs from external contributors, or compromised maintainer accounts. npm Trusted Publishing eliminates the secret.
- Operational overhead. Tokens need to be rotated periodically. Anyone joining or leaving the maintainer team requires a token rotation. This is pure toil with no security benefit beyond what OIDC provides.
- Reduced auditability. A token-based publish attributes the action to whoever last rotated the token. An OIDC publish attributes it to the specific workflow run, including the commit SHA, the runner, and the environment.
For a project that publishes to a public registry, this is the baseline. Any project with a public npm package should use Trusted Publishing.
To configure Trusted Publishing, you need:
-
Maintainer access to npmjs.com for the
@deessejs/fppackage (the account that owns the package or is added as a maintainer). -
Admin access to the
deessejs/fpGitHub repository (the role required to create or modify GitHub environments). -
A workflow file at
.github/workflows/publish.ymlin the repository. This file must exist before Trusted Publishing is configured, because npm validates the workflow filename as part of the configuration. -
The repository URL in
packages/fp/package.jsonmust match the actual GitHub repository URL. Trusted Publishing validates this field case-sensitively.
If any of these are missing, complete the prerequisite first and come back.
Path: https://www.npmjs.com/package/@deessejs/fp/access → Trusted Publishers → Add Trusted Publisher.
Fill in the form:
| Field | Value |
|---|---|
| Provider | GitHub Actions |
| Organization or user | deessejs |
| Repository |
deessejs/fp (must match package.json#repository.url exactly) |
| Workflow filename | publish.yml |
| Environment name | release |
Save. The new Trusted Publisher appears in the list. Repeat the same configuration
for any future workflow (canary, hotfix, pre-release) that needs its own publish slot,
with a different Workflow filename and Environment name.
After saving:
- Publishing access: require two-factor authentication and disallow tokens. This is the recommended setting.
- Two-factor authentication must already be enabled on the npm account.
Path: https://github.com/deessejs/fp/settings/environments → New environment.
-
Name:
release(must match the npm-side configuration). -
Deployment branches and tags:
- Selected branches:
main. - Selected tags: leave empty. The pipeline does not deploy from tag pushes.
- Selected branches:
- Required reviewers: add 1-2 named engineering maintainers. Do not add a team; keep it named individuals so accountability is explicit.
- Wait timer: leave at 0 minutes. The publish should not be artificially delayed.
- Allow administrators to bypass: leave disabled. Maintainers still go through review.
Path: https://github.com/deessejs/fp/settings/actions → General → Workflow permissions.
-
Allow GitHub Actions to create and approve pull requests: enable.
This is required if you want any future automation (like the
changesets/action@v2Version Packages PR) to open PRs from the bot identity. - Read repository contents and packages permissions: leave as default.
The .github/workflows/publish.yml file must declare the right permissions and
environment:
jobs:
release:
environment: release
permissions:
id-token: write # for npm OIDC
contents: write # to push the version bump and the tag
pull-requests: read # to inspect the mergeIf any of these are missing, GitHub will not mint the OIDC token, and the publish will fail with HTTP 403.
Do not assume the configuration works. Verify it explicitly before trusting it.
Open a test PR with a --empty Changeset (which produces a version bump with no
changelog body). Merge it to main. The first time the workflow runs:
-
publish.ymltriggers onpull_request: closed(merged). - The workflow detects the Changeset.
- The workflow calls
pnpm changeset publish --tag latest. - npm receives the publish request, validates the OIDC token, accepts it.
- The version is published.
To verify the publish succeeded, run:
npm view @deessejs/fp versionThis should print the version that was just published. If the publish failed, npm
will return an error and the workflow's ::error:: annotation will explain why.
After a successful publish, npm provides provenance attestation. Verify it:
- Go to the npmjs.com page for the new version.
- Look for the "Provenance" badge or section.
- It should link to the GitHub Actions workflow run that produced the publish, including the commit SHA and the environment name.
If the provenance is missing, the publish used a different mechanism (probably a fallback to a personal access token). Fix the workflow before the next publish.
If the project previously used NPM_TOKEN:
-
Confirm OIDC works first. Run the test publish (§ 6.1) and verify it
succeeded without
NPM_TOKENin the GitHub environment. If OIDC works,NPM_TOKENis no longer used. -
Rotate the npm token. Go to https://www.npmjs.com/settings/tokens and
delete the token that was used as
NPM_TOKEN. This revokes it from npm's side. -
Delete the GitHub secret. Go to
https://github.com/deessejs/fp/settings/secrets/actions and delete the
NPM_TOKENsecret. This removes it from the GitHub side. -
Update any documentation. Remove references to
NPM_TOKENfrom internal docs and READMEs.
If the OIDC setup fails after revoking NPM_TOKEN, the next publish will fail.
Keep the rollback plan: if you need to revert to NPM_TOKEN, regenerate it
in npm, re-add the GitHub secret, and use the token in the workflow as a
fallback while you debug OIDC.
Three situations:
If publish.yml is renamed (for example, split into publish-release.yml and
publish-hotfix.yml), update the Trusted Publisher entry on npm with the new
filename. Until then, the next publish fails with HTTP 403.
If the release environment is renamed, update both sides atomically: npm
Trusted Publisher first, then GitHub environment. Until both are updated, the
publish fails.
If the repository is transferred to a new owner (for example, from nesalia-inc
to deessejs), update package.json#repository.url first, then update the
Trusted Publisher entry on npm with the new organization name. The npm entry
validates the repository URL case-sensitively.
- Release Process — the release pipeline that uses Trusted Publishing.
-
Branch Strategy — how
main,staging, anddevinteract. - Hotfix Flow — the urgent-fix path.
- Internal:
docs/engineering/plans/release-pipeline-github-ui-setup.md— the operational mirror of this page. - External: npm Trusted Publishers — reference documentation.
- External: GitHub Actions OIDC — reference documentation for OIDC.
This wiki is maintained alongside the @deessejs/fp package. Pages here mirror internal documentation at docs/engineering/ in the repository; the repo file is the source of truth.
- Repository: source code, issues, releases.
- npm package: install, changelog, version history.
- Issue tracker: bug reports and feature requests.
- Discussions: questions and design conversations.