Skip to content

Commit 4f408db

Browse files
committed
fix(ci): fail an npm-alias publish leg whose trusted publisher is not registered
The unregistered-trusted-publisher signatures (the OIDC exchange 404 and the bare PUT 404 on the unregistered name) skipped with a notice instead of failing the leg, which made the one-time registration permanently invisible: every alias stayed stranded from the monorepo migration until a manual audit found them. The leg now fails carrying the same registration instructions as an error annotation. Nothing downstream depends on the post-release jobs, so the release and the Pages deploy still cannot be blocked -- the red is a signal, not a gate. The GitHub Packages mirror keeps its graceful skip.
1 parent f4cfbac commit 4f408db

2 files changed

Lines changed: 4 additions & 4 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ jobs:
608608
working-directory: packages/${{ matrix.name }}
609609
run: npm pkg set name="${{ matrix.alias }}"
610610
- name: Publish the alias
611-
# Trusted publishing is registered per package name, so each alias needs its own one-time registration on npmjs.com against this repository and workflow file. Until that registration exists the publish fails two ways depending on where pnpm gives up: the OIDC exchange itself 404s (`oidc/token` or pnpm's `ERR_PNPM_AUTH_TOKEN_EXCHANGE` in the output), or the exchange is skipped and the bare PUT 404s on the unregistered name (`404 Not Found - PUT ... registry.npmjs.org/<alias>`). Both exact signatures are the skip-with-instructions case below; every other failure is real and fails the leg.
611+
# Trusted publishing is registered per package name, so each alias needs its own one-time registration on npmjs.com against this repository and workflow file. Until that registration exists the publish fails two ways depending on where pnpm gives up: the OIDC exchange itself 404s (`oidc/token` or pnpm's `ERR_PNPM_AUTH_TOKEN_EXCHANGE` in the output), or the exchange is skipped and the bare PUT 404s on the unregistered name (`404 Not Found - PUT ... registry.npmjs.org/<alias>`). Both exact signatures are the fail-with-instructions case below (a deliberate signal, not a skip: the registration is a one-time user action, and a silent skip let every alias stay stranded from the monorepo migration until a manual audit found them -- a red leg names the missing registration the day a release runs); every other failure is real and fails the leg too.
612612
if: steps.published.outputs.already != 'true'
613613
working-directory: packages/${{ matrix.name }}
614614
run: |
@@ -619,8 +619,8 @@ jobs:
619619
echo "$OUTPUT"
620620
[ "$STATUS" -eq 0 ] && exit 0
621621
if printf '%s' "$OUTPUT" | grep -qE 'oidc/token|ERR_PNPM_AUTH_TOKEN_EXCHANGE|404 Not Found - PUT .*registry\.npmjs\.org'; then
622-
echo "::notice::Skipped ${{ matrix.alias }}@${{ matrix.version }}: no npm trusted publisher is registered for that package name against this repository and workflow yet. Register it once (a user with access to the package's npm settings): npmjs.com -> Packages -> ${{ matrix.alias }} -> Settings -> Trusted publisher -> GitHub Actions, with Organization \"ExaDev\", Repository \"documents.js\", Workflow filename \"ci.yml\", environment left empty, allowed action \"npm publish\". The first release after that publishes under the alias automatically; see the Releases section of the root README."
623-
exit 0
622+
echo "::error::Failed ${{ matrix.alias }}@${{ matrix.version }}: no npm trusted publisher is registered for that package name against this repository and workflow yet. Register it once (a user with access to the package's npm settings): npmjs.com -> Packages -> ${{ matrix.alias }} -> Settings -> Trusted publisher -> GitHub Actions, with Organization \"ExaDev\", Repository \"documents.js\", Workflow filename \"ci.yml\", environment left empty, allowed action \"npm publish\". The first release after that publishes under the alias automatically; see the Releases section of the root README."
623+
exit 1
624624
fi
625625
exit "$STATUS"
626626
env:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ Release configuration is **only** at the root. The orchestrator sets `tagFormat`
157157

158158
If a release job is itself cancelled by its own timeout after the per-package publish work has already completed but before it collects the released tags into those three matrices, a plain re-run cannot recover it: the collection step diffs tags against a before/after snapshot taken within that same run, so a later run sees every already-existing tag as pre-existing, not new. `ci.yml`'s `workflow_dispatch` trigger takes an optional `backfill_tags` input (comma- or newline-separated `name@version` tags) for exactly this case: a `collect-backfill-matrix` job builds the identical three matrices directly from the given tags, without re-running the release itself, and the three post-release jobs consume whichever of it or the normal release job produced output. Trigger it with `gh workflow run ci.yml --field backfill_tags="pkg-a@1.2.3,pkg-b@4.5.6"`.
159159

160-
One user-only action remains before the npm aliases resume tracking their packages: each alias name's trusted publisher must be registered once against this repository and workflow, because trusted publishing is registered per package name and every alias's existing registration still names its archived standalone repository. Until an alias is registered, its publish leg skips with a notice rather than failing the job (the same graceful skip covers a legacy GitHub Packages mirror whose Actions-access list still names only its archived standalone repository — grant this repository Write on the package's settings page once, and the next release mirrors automatically); the registration is: sign in to [npmjs.com](https://www.npmjs.com) as a user with access to the package's settings → **Packages** → the alias (e.g. `document-bytes`) → **Settings** → **Trusted publisher** → select **GitHub Actions**, then enter Organization `ExaDev`, Repository `documents.js`, Workflow filename `ci.yml` (filename only — it must exist in `.github/workflows/`), leave the environment empty, and allow the `npm publish` action ([npm's trusted-publishers documentation](https://docs.npmjs.com/trusted-publishers) has the canonical form). The first release after that publishes under the alias automatically. The stranded aliases are tracked individually in [ExaDev/documents.js#727](https://github.com/ExaDev/documents.js/issues/727), [#728](https://github.com/ExaDev/documents.js/issues/728), [#729](https://github.com/ExaDev/documents.js/issues/729), [#730](https://github.com/ExaDev/documents.js/issues/730), [#731](https://github.com/ExaDev/documents.js/issues/731), and [#770](https://github.com/ExaDev/documents.js/issues/770).
160+
One user-only action remains before the npm aliases resume tracking their packages: each alias name's trusted publisher must be registered once against this repository and workflow, because trusted publishing is registered per package name and every alias's existing registration still names its archived standalone repository. Until an alias is registered, its publish leg fails with the exact one-time registration instructions in its annotation — a deliberate signal rather than a graceful skip, because a silent skip let every alias stay stranded from the monorepo migration until a manual audit found them; the failure still cannot block the release or the Pages deploy (nothing depends on the post-release jobs), it only makes the outstanding registration visible the moment a release runs. The legacy GitHub Packages mirror keeps its graceful skip (a legacy mirror package's Actions-access list still names only its archived standalone repository — grant this repository Write on the package's settings page once, and the next release mirrors automatically); the registration is: sign in to [npmjs.com](https://www.npmjs.com) as a user with access to the package's settings → **Packages** → the alias (e.g. `document-bytes`) → **Settings** → **Trusted publisher** → select **GitHub Actions**, then enter Organization `ExaDev`, Repository `documents.js`, Workflow filename `ci.yml` (filename only — it must exist in `.github/workflows/`), leave the environment empty, and allow the `npm publish` action ([npm's trusted-publishers documentation](https://docs.npmjs.com/trusted-publishers) has the canonical form). The first release after that publishes under the alias automatically. The stranded aliases are tracked individually in [ExaDev/documents.js#727](https://github.com/ExaDev/documents.js/issues/727), [#728](https://github.com/ExaDev/documents.js/issues/728), [#729](https://github.com/ExaDev/documents.js/issues/729), [#730](https://github.com/ExaDev/documents.js/issues/730), [#731](https://github.com/ExaDev/documents.js/issues/731), and [#770](https://github.com/ExaDev/documents.js/issues/770).
161161

162162
`commitlint.config.ts` derives its allowed commit types from `release-workspace.config.ts`'s own `releaseRules`, preserving the invariant each package's own config was built around: a conventional-commit type cannot trigger a release without also being accepted by commit-message validation, or the reverse.
163163

0 commit comments

Comments
 (0)