ci(release): opt into npm OIDC Trusted Publishing - #76
Conversation
Token-based publishing silently failed for v1.10.0 through v1.11.1: the org-level NPM_TOKEN became invalid sometime between 2026-05-19 and 05-21, and `bunx clean-publish` swallowed npm's non-zero exit, so four releases went green on Actions while nothing landed on npm. Switch to OIDC Trusted Publishing (no rotating tokens) by enabling `use-oidc: true` and granting the workflow `id-token: write`. Requires a Trusted Publisher entry on npmjs.com pointing at this repo + release.yaml. buildspace's publish-npm block already prefers OIDC when id-token is available and falls back to NPM_TOKEN otherwise, so this is a no-op until the Trusted Publisher is configured on the npm side. Co-authored-by: Cursor <cursoragent@cursor.com>
📝 WalkthroughWalkthroughThe release workflow is updated to enable OpenID Connect (OIDC) authentication by adding ChangesRelease Workflow OIDC Setup
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/release.yaml (1)
10-10: ⚡ Quick winConsider moving
id-token: writeto job-level permissions.The
id-token: writepermission is only needed by thereleasejob. Scoping it at the job level instead of workflow level follows the principle of least privilege and makes the intent clearer.🔐 Proposed job-level permissions
Remove from workflow-level permissions:
permissions: contents: write pull-requests: read - id-token: writeAdd to the
releasejob:jobs: release: + permissions: + contents: write + pull-requests: read + id-token: write uses: photon-hq/buildspace/.github/workflows/typescript-service-release.yaml@mainAs per coding guidelines, the static analysis tool zizmor flagged "id-token: write is overly broad at the workflow level".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/release.yaml at line 10, Move the workflow-level permission "id-token: write" down into the specific job that needs it: the release job; remove the global permissions entry "id-token: write" and add the same permission under the release job's permissions block so only the release job has id-token write access (look for the workflow permissions section and the job named "release" to update).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.github/workflows/release.yaml:
- Line 10: Move the workflow-level permission "id-token: write" down into the
specific job that needs it: the release job; remove the global permissions entry
"id-token: write" and add the same permission under the release job's
permissions block so only the release job has id-token write access (look for
the workflow permissions section and the job named "release" to update).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b51115c6-a8c7-4c10-a301-17295e5e891c
📒 Files selected for processing (1)
.github/workflows/release.yaml
📜 Review details
🧰 Additional context used
🪛 zizmor (1.25.2)
.github/workflows/release.yaml
[error] 10-10: overly broad permissions (excessive-permissions): id-token: write is overly broad at the workflow level
(excessive-permissions)
🔇 Additional comments (1)
.github/workflows/release.yaml (1)
20-20: LGTM!
Move advanced-imessage-ts off long-lived NPM_TOKEN onto npm OIDC Trusted Publishing, mirroring photon-hq/spectrum-ts#76 and #77. - release.yaml: grant `id-token: write` and pass `use-oidc: true` so buildspace's typescript-service-release routes through the OIDC publish job (mints a per-run GitHub OIDC token instead of a rotating secret). - package.json: add `bugs`. `repository.url` and `description` (the field npm provenance verification checks) are already present, so the #77-class E422 "repository.url is empty" failure can't occur here. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Token-based npm publishing has been silently failing for
spectrum-tssincev1.10.0. The org-levelNPM_TOKENwas invalidated on the npm.com side sometime between 2026-05-19 and 2026-05-21, andbunx clean-publishswallowed the resultingnpm error code E404exit, so four GitHub releases (v1.10.0,v1.10.1,v1.11.0,v1.11.1) shipped to GitHub but never landed on npm — npmlatestis still1.9.2.This PR moves
spectrum-tsto npm OIDC Trusted Publishing so future releases authenticate with a per-run GitHub-issued OIDC token instead of a long-lived secret. No more rotating-token-secret class of failure.Changes
permissions:addid-token: write(required for the runner to mint the OIDC token).with:adduse-oidc: trueso buildspace'stypescript-service-releaseworkflow routes through the OIDC publish job.The buildspace
publish-npmblock already prefers OIDC whenid-tokenis available and falls back toNPM_TOKENotherwise, so this is safe — if Trusted Publisher isn't configured yet on the npm side, the publish silently no-ops the way it has been (until photon-hq/buildspace#82 lands, which makes that case hard-fail).Required pre-merge action on npmjs.com
Trusted Publisher must be configured for the
spectrum-tspackage before this PR is merged with areleaselabel, otherwise OIDC will fail and the publish will fall back to the still-broken token. As maintainerphoton_dev:photon-hqspectrum-tsrelease.yamlTest plan
releaselabel) — confirms workflow YAML still parses on push to mainreleaselabelnpm-publish-oidcjob should run instead ofnpm-publish, and the verify-on-registry step (after fix(publish-npm): make silent publish failures structurally impossible buildspace#82) should report<name>@<version> is live on the npm registrycurl https://registry.npmjs.org/spectrum-ts | jq '."dist-tags".latest'shows the new versionBackground
Detailed root-cause analysis: every release run since
v1.10.0showsnpm error 404 - PUT https://registry.npmjs.org/spectrum-ts - Not found(npm returns 404 instead of 401/403 for auth failures), but the step still reports[success]becausebunx clean-publishdoesn't propagate npm's non-zero exit. Counter-evidence: org-levelNPM_TOKENsecret'supdated_atis2026-05-11, well before1.9.2published cleanly on2026-05-19, so the GitHub-side secret value never changed — the token itself was invalidated on npm.Made with Cursor
Need help on this PR? Tag
@codesmithwith what you need. Autofix is disabled.Summary by CodeRabbit