Context
git-fi ships to npm as @gettyimages/git-fi. Publishing a GitHub Release triggers .github/workflows/release.yml, which derives the version from the tag, bumps package.json, prepends the release body to CHANGELOG.md, publishes to npm, and pushes a Release vX.Y.Z commit back to main.
There is no path back. If a release turns out to be broken, npm will never let that version number be reused, and npm unpublish is only unrestricted for 72 hours after publish (after that it needs no dependents, under 300 weekly downloads, and a single owner, or a support request). Deleting the version is also the wrong instinct: it breaks lockfiles that already pin it.
The npm-native fix is to move the latest dist-tag back to the last good version and deprecate the bad one, so npm install @gettyimages/git-fi resolves to something that works while anyone pinned to the broken version gets a warning telling them where to go. Today that means a maintainer running the commands by hand from a laptop that happens to be logged into npm, at exactly the moment they are least likely to get them right.
Proposed approach
Add a rollback path to release.yml behind workflow_dispatch. The dispatch trigger currently runs a packaging dry-run with no inputs, so it becomes a switch on an action input:
on:
workflow_dispatch:
inputs:
action:
type: choice
options: [dry-run, rollback-latest, deprecate]
default: dry-run
version:
description: Version to act on, e.g. 1.2.3
rollback_to:
description: Version to point `latest` at
message:
description: Deprecation message
rollback-latest runs npm dist-tag add @gettyimages/git-fi@<rollback_to> latest; deprecate runs npm deprecate @gettyimages/git-fi@<version> "<message>". Both are reversible, which is why they are the two worth automating.
The obstacle is authentication. The workflow publishes through npm trusted publishing: id-token: write, npm@latest, --provenance, and no NODE_AUTH_TOKEN anywhere. The OIDC exchange appears to happen inside npm publish itself, which would mean dist-tag and deprecate fall back to needing a conventional write credential. That has not been confirmed against npm's behavior, and it decides the shape of the whole change, so it is the first thing to settle.
If a token is required, it should be a granular access token scoped to @gettyimages/git-fi alone with read-and-write permission and an expiry, stored as NPM_TOKEN. A classic automation token would also work; both skip the 2FA one-time-password prompt that makes a classic publish token unusable in a runner.
Acceptance criteria
- Whether npm trusted publishing covers
npm dist-tag and npm deprecate is established by testing it, not inferred, and the answer is recorded in the workflow comments.
- A maintainer can move
latest to a prior published version from the GitHub Actions UI without holding npm credentials themselves.
- A maintainer can deprecate a published version with a custom message from the same place.
- The existing dry-run remains the default dispatch action, so an unattended dispatch cannot publish or mutate anything.
- Any credential the workflow gains is scoped to this one package and cannot publish other
@gettyimages packages.
README.md or CONTRIBUTING.md says what to do when a release is bad, including that the fix ships as a new patch version rather than a republish.
Considerations
Reintroducing a long-lived secret. Trusted publishing exists to remove the standing NPM_TOKEN from the repo. Adding one back for rollback gives it up for a path that runs rarely. Worth weighing whether rollback is better left as a documented manual procedure, with the workflow change limited to whatever OIDC does cover.
unpublish is deliberately absent above. It is irreversible and its blast radius is the whole package. Keeping it off the dispatch menu means it needs a human with credentials, which matches how often it is the right answer.
main drifts from latest. The release workflow commits Release vX.Y.Z with the bumped package.json. Moving latest back does not undo that, so main would claim 1.2.3 while installers get 1.2.2. Fine if the fix ships promptly as 1.2.4; confusing if the rollback sits there. Decide whether the rollback action should also revert the version commit, or whether the documented procedure just says to follow it with a patch release.
Who can dispatch. Anyone with write access to the repo can run a workflow_dispatch, so the rollback actions inherit that audience rather than the narrower set who hold npm publish rights today.
Context
git-fiships to npm as@gettyimages/git-fi. Publishing a GitHub Release triggers.github/workflows/release.yml, which derives the version from the tag, bumpspackage.json, prepends the release body toCHANGELOG.md, publishes to npm, and pushes aRelease vX.Y.Zcommit back tomain.There is no path back. If a release turns out to be broken, npm will never let that version number be reused, and
npm unpublishis only unrestricted for 72 hours after publish (after that it needs no dependents, under 300 weekly downloads, and a single owner, or a support request). Deleting the version is also the wrong instinct: it breaks lockfiles that already pin it.The npm-native fix is to move the
latestdist-tag back to the last good version and deprecate the bad one, sonpm install @gettyimages/git-firesolves to something that works while anyone pinned to the broken version gets a warning telling them where to go. Today that means a maintainer running the commands by hand from a laptop that happens to be logged into npm, at exactly the moment they are least likely to get them right.Proposed approach
Add a rollback path to
release.ymlbehindworkflow_dispatch. The dispatch trigger currently runs a packaging dry-run with no inputs, so it becomes a switch on anactioninput:rollback-latestrunsnpm dist-tag add @gettyimages/git-fi@<rollback_to> latest;deprecaterunsnpm deprecate @gettyimages/git-fi@<version> "<message>". Both are reversible, which is why they are the two worth automating.The obstacle is authentication. The workflow publishes through npm trusted publishing:
id-token: write,npm@latest,--provenance, and noNODE_AUTH_TOKENanywhere. The OIDC exchange appears to happen insidenpm publishitself, which would meandist-taganddeprecatefall back to needing a conventional write credential. That has not been confirmed against npm's behavior, and it decides the shape of the whole change, so it is the first thing to settle.If a token is required, it should be a granular access token scoped to
@gettyimages/git-fialone with read-and-write permission and an expiry, stored asNPM_TOKEN. A classic automation token would also work; both skip the 2FA one-time-password prompt that makes a classic publish token unusable in a runner.Acceptance criteria
npm dist-tagandnpm deprecateis established by testing it, not inferred, and the answer is recorded in the workflow comments.latestto a prior published version from the GitHub Actions UI without holding npm credentials themselves.@gettyimagespackages.README.mdorCONTRIBUTING.mdsays what to do when a release is bad, including that the fix ships as a new patch version rather than a republish.Considerations
Reintroducing a long-lived secret. Trusted publishing exists to remove the standing
NPM_TOKENfrom the repo. Adding one back for rollback gives it up for a path that runs rarely. Worth weighing whether rollback is better left as a documented manual procedure, with the workflow change limited to whatever OIDC does cover.unpublishis deliberately absent above. It is irreversible and its blast radius is the whole package. Keeping it off the dispatch menu means it needs a human with credentials, which matches how often it is the right answer.maindrifts fromlatest. The release workflow commitsRelease vX.Y.Zwith the bumpedpackage.json. Movinglatestback does not undo that, somainwould claim1.2.3while installers get1.2.2. Fine if the fix ships promptly as1.2.4; confusing if the rollback sits there. Decide whether the rollback action should also revert the version commit, or whether the documented procedure just says to follow it with a patch release.Who can dispatch. Anyone with write access to the repo can run a
workflow_dispatch, so the rollback actions inherit that audience rather than the narrower set who hold npm publish rights today.