Skip to content

Publish to npm: add an organisation-level trusted publisher #1

Description

@JKamsker

Releases currently ship the packaged tarball as a release asset, which installs fine:

npm install -g https://github.com/coderdojo-linz/locker-cli/releases/latest/download/coderdojo-linz-locker-0.1.0.tgz

What it does not give us is npx @coderdojo-linz/locker — the short, install-free way in, which for a tool aimed at kids is most of the point. That needs the package on the npm registry.

Why there is no token to just add

npm permanently revoked every classic token on 9 December 2025. They cannot be recreated or recovered. Granular tokens still exist, but they enforce 2FA and are capped at a 90-day lifetime, so an unattended pipeline built on one is a secret that silently stops working four times a year.

The supported answer is trusted publishing: GitHub mints a short-lived OIDC token for the workflow, npm verifies it against a trust relationship configured on npm's side, and nothing long-lived is stored anywhere. Provenance is generated automatically as a result, so the package page shows which commit and which workflow built it.

What is already done

  • .github/workflows/publish.yml requests id-token: write and runs on a GitHub-hosted runner. Self-hosted runners are not accepted for trusted publishing, which is why publishing lives here rather than on the Forgejo runners with the rest of the pipeline.
  • package.json has the repository field npm requires to match exactly, and a publishConfig asking for public access and provenance — so publishing by hand from a laptop fails rather than quietly producing an unattested package.
  • The npm publish step exists but is switched off, so releases do not fail while this is outstanding.

What is left

1. Own the scope. @coderdojo-linz/locker needs an npm organisation named coderdojo-linz. Create it at npmjs.com if it does not exist. (If the org has to be called something else, the scope in package.json changes with it — it is one word.)

2. Add an organisation-level trusted publisher.

npmjs.com → your organisation → SettingsAutomationTrusted Publishers → Add.

Field Value
Provider GitHub Actions
Organization or user coderdojo-linz
Repository locker-cli
Workflow filename publish.yml
Environment (leave empty)
Allowed actions npm publish

It has to be on the organisation, not on the package. A package-level trusted publisher can only be added to a package that already exists, and this one does not — the usual chicken-and-egg, and the reason the first publish would otherwise still need a token. An organisation-level publisher lets the workflow create new packages in the scope, which sidesteps it entirely.

If the Automation section is not visible, it is an organisation-level setting rather than a personal-account one — a personal account's settings page does not have it. Check you are looking at the org, and that you are an owner of it.

3. Flip the switch. In this repository: Settings → Secrets and variables → Actions → Variables → new repository variable:

NPM_TRUSTED_PUBLISHING = true

The workflow reads it and the next release publishes to npm as well as attaching the tarball. No code change needed, and setting it back to anything else turns it off again.

4. Release.

gh release create v0.1.0 --repo coderdojo-linz/locker-cli --title v0.1.0 --generate-notes

The workflow refuses if the tag and package.json disagree.

Then

Update the install instructions in README.md — both here and in the private server repo, where the CLI is developed — to lead with npx instead of the release tarball.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions