Skip to content

ci(publish)!: migrate NPM publication to OIDC trusted publishing (#104)#105

Merged
levalleux-ludo merged 14 commits into
mainfrom
fix/104-npm-oidc-publishing
Jun 4, 2026
Merged

ci(publish)!: migrate NPM publication to OIDC trusted publishing (#104)#105
levalleux-ludo merged 14 commits into
mainfrom
fix/104-npm-oidc-publishing

Conversation

@levalleux-ludo
Copy link
Copy Markdown
Member

Fixes #104.

Problem

NPM now requires trusted publishing (OIDC), which binds a package to one exact workflow filename. The repo currently publishes from two different workflows using a long-lived NPM_TOKEN, so both publish paths are broken:

  • alphaci_reusable.yaml (auto, push to main)
  • latestpublish-latest.yaml (manual workflow_dispatch, semantic-release)

Change

Consolidate both publish paths into a single tokenless workflow.

File Change
.github/workflows/publish.yaml New unified workflow. push → alpha (npm publish --tag alpha); workflow_dispatch → latest via semantic-release + GitHub release. permissions: id-token: write, no NPM_TOKEN.
.github/actions/build-test/action.yml New composite action — setup-node (Node 22) → upgrade npm (≥ 11.5.1) → cache → npm ci → build → test. Shared by the publish workflow and PR CI.
.github/workflows/publish-latest.yaml Deleted (superseded).
.github/workflows/ci_reusable.yaml Build/test only via the composite + PR-only prettier/lint:fix. Drops NPM_TOKEN/NODE_AUTH_TOKEN/PUBLISH_NPM and all publish steps.
.github/workflows/ci.yaml Reduced to a PR-only trigger.

Why these specifics

  • OIDC requires npm CLI ≥ 11.5.1 and Node ≥ 22.14 → composite bumps Node to 22 and runs npm install -g npm@latest.
  • Publishing is tokenless; setup-node + registry-url with no token env is the documented pattern, and provenance is automatic.
  • semantic-release publishes via OIDC only with @semantic-release/npm ≥ 13.1.0, bundled in semantic-release ≥ v25.0.1semantic_version bumped 2425.
  • Build/test is defined once (composite) and the publish job runs it inline in the same runner, so npm publish reuses dist/ with no rebuild (avoids the double-build a reusable-workflow needs: gate would cause).

⚠️ Required manual step (cannot be done in-repo)

Before this can publish, configure the trusted publisher on npmjs.com for @bosonprotocol/chat-sdk → Settings → Trusted Publisher → GitHub Actions:

  • Organization: bosonprotocol
  • Repository: chat-sdk
  • Workflow filename: publish.yaml (exact, case-sensitive)
  • Environment: (blank)
  • Allowed action: npm publish

The first publish fails with ENEEDAUTH until this exists. The NPM_TOKEN repo secret becomes unused and can be removed afterward.

Verification

  • ✅ All workflow files + composite parse as valid YAML; - uses: ./.github/actions/build-test resolves.
  • ✅ No NPM_TOKEN/NODE_AUTH_TOKEN/PUBLISH_NPM usage remains.
  • After merge + npm config: a push to main publishes a new alpha version (with provenance); a manual run of Publish - Chat SDK publishes latest and creates a GitHub release.

🤖 Generated with Claude Code

NPM now requires trusted publishing (OIDC), which binds a package to one
exact workflow filename. Alpha (ci_reusable.yaml) and latest
(publish-latest.yaml) were published from two different workflows with a
long-lived NPM_TOKEN, so both paths are now broken.

Consolidate both publish paths into a single tokenless workflow:

- Add .github/workflows/publish.yaml: push to main -> alpha
  (npm publish --tag alpha), workflow_dispatch -> latest via
  semantic-release (semantic_version 25, which bundles
  @semantic-release/npm >= 13.1 with OIDC support) plus a GitHub release.
  Uses permissions: id-token: write and no NPM_TOKEN.
- Extract the shared setup-node + npm upgrade + ci + build + test steps
  into a local composite action (.github/actions/build-test) reused by
  both the publish workflow and PR CI, so build/test is defined once and
  runs once per runner. Bumps Node to 22 and npm to >= 11.5.1 as required
  by trusted publishing.
- Delete publish-latest.yaml (superseded).
- Reduce ci_reusable.yaml to build/test only (drops NPM_TOKEN,
  NODE_AUTH_TOKEN, PUBLISH_NPM and all publish steps) and ci.yaml to a
  PR-only trigger.

Requires a one-time manual step: configure the GitHub Actions trusted
publisher for @bosonprotocol/chat-sdk on npmjs.com pointing at
publish.yaml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 4, 2026 09:10
@levalleux-ludo levalleux-ludo requested a review from a team as a code owner June 4, 2026 09:10
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates NPM publishing to OIDC trusted publishing by consolidating alpha (on push to main) and latest (manual workflow_dispatch via semantic-release) into a single workflow, and de-tokenizing CI/publish by removing NPM_TOKEN-based auth.

Changes:

  • Added a unified publish.yaml workflow that handles alpha publishes on push and latest releases on manual dispatch (semantic-release).
  • Introduced a shared composite action to standardize Node setup, npm upgrade, install, build, and test across CI and publishing.
  • Simplified CI workflows to PR-only and removed legacy publish workflows/logic and token usage.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
.github/workflows/publish.yaml New unified OIDC-based publishing workflow for both alpha (push) and latest (dispatch via semantic-release).
.github/actions/build-test/action.yml New composite action to centralize Node/npm setup + install/build/test steps.
.github/workflows/publish-latest.yaml Removes the legacy token-based manual release workflow in favor of the unified publish workflow.
.github/workflows/ci_reusable.yaml Strips publishing logic and switches CI to use the shared composite action plus PR-only formatting/linting steps.
.github/workflows/ci.yaml Reduces CI triggering to PR-only and delegates to the reusable build/test workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/publish.yaml Outdated
Comment thread .github/actions/build-test/action.yml Outdated
Comment thread .github/actions/build-test/action.yml Outdated
levalleux-ludo and others added 3 commits June 4, 2026 10:41
… commit

actions/checkout leaves a detached HEAD on push events, so the bare `git push`
in the alpha step would fail ("not currently on a branch"). And `git commit
--amend` rewrote the version-bump commit without moving the tag npm had just
created, so the pushed tag pointed at the pre-amend (orphaned) commit.

Check out `main` explicitly via the checkout `ref`, and bake `[skip ci]` into
the `npm version` commit message (`-m "%s [skip ci]"`) so the commit and tag are
created together in one step. Push both with `git push --follow-tags`.

Addresses PR #105 review comment r3354854034.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Installing npm@latest makes CI and publishing non-deterministic: a new npm
release could break builds or publishing with no change in the repo. Pin to a
known-good version that satisfies the trusted-publishing requirement (>= 11.5.1)
and bump it intentionally when needed.

Addresses PR #105 review comment r3354854090.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
actions/setup-node already caches the npm download cache when cache: "npm" is
set, so the separate actions/cache step for ~/.npm duplicated that work and only
added restore/save overhead and confusion. Rely on setup-node's built-in caching.

Addresses PR #105 review comment r3354854115.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment thread .github/workflows/publish.yaml
Comment thread .github/workflows/publish.yaml
Comment thread .github/actions/build-test/action.yml Outdated
levalleux-ludo and others added 3 commits June 4, 2026 12:19
The publish job mutates and pushes main (version bump + tags) and publishes to
npm, so overlapping runs — two pushes to main close together, or a manual
workflow_dispatch while a push publish is still running — can race and cause
non-fast-forward push failures or inconsistent prerelease sequencing.

Add a workflow-level concurrency group keyed on the ref with
cancel-in-progress: false so publish runs are serialized and a run is never
cancelled mid-publish.

Addresses PR #105 review comment r3355066601.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Checking out `ref: main` meant a run triggered by a specific push could build,
test, bump and publish a *newer* main if other pushes landed before the job
started — making publishes non-reproducible and inviting push conflicts.

Check out `${{ github.sha }}` and recreate a local `main` branch at that commit
(`git checkout -B main`), which keeps the run pinned to the triggering commit
while still avoiding the detached HEAD that would break `git push`. Push
explicitly to `origin main` since the recreated branch has no upstream.

Addresses PR #105 review comment r3355066656.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The major-only selector "22" does not guarantee the >= 22.14 patch level that
OIDC trusted publishing requires — on a fresh runner or a stale toolcache it can
resolve to an earlier 22.x, which would make publishing fail unexpectedly. Pin
the default to 22.14.0 (still overridable via the node-version input).

Addresses PR #105 review comment r3355066675.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Comment thread .github/workflows/publish.yaml Outdated
Comment thread .github/workflows/publish.yaml
Comment thread .github/workflows/ci_reusable.yaml Outdated
levalleux-ludo and others added 4 commits June 4, 2026 13:36
`git checkout -B main` creates the branch without an upstream. The alpha path
compensates with an explicit `origin main` push, but semantic-release performs
its own `git push` on the workflow_dispatch (latest) path and can fail with "no
upstream branch". Configure branch.main.remote/merge so the branch tracks
origin/main, making both publish paths robust.

Addresses PR #105 review comment r3355705468.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The git author identity was only set on push events, but the workflow_dispatch
(latest) path runs semantic-release with @semantic-release/git, which creates
changelog/version commits and fails without a configured author. Move the
author config out of the alpha-only section so it runs unconditionally.

Addresses PR #105 review comment r3355705521.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Previously PR CI ran `prettier --write` and `eslint --fix` *after* the
composite's build+test, so build/test exercised the pre-fix code and the
auto-fixers (which always exit 0) gated nothing — reducing confidence in CI.

Add a `run-checks` input to the build-test composite that runs `npm run lint`
(non-mutating, no --fix) after `npm ci` but before build+test, and enable it
from ci_reusable.yaml (PR CI). Lint is now a real gate and build/test run on the
actual committed code. Publish runs leave run-checks at its default (off).

The mutating `prettier --write` step is dropped from CI: it never gated anything
and whitespace formatting does not affect build/test. A real `prettier --check`
gate is deferred — it currently fails on pre-existing unrelated files (incl. the
semantic-release-managed CHANGELOG.md) and is a separate cleanup.

Addresses PR #105 review comment r3355705568.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to r3355705568: add a real (non-mutating) formatting gate alongside
lint. New `prettier:check` script runs `prettier --check` scoped to first-party
`src/` and `tests/` (both currently clean), wired into the build-test composite
so it runs before build/test when run-checks is enabled (PR CI).

Kept scoped rather than repo-wide because `prettier --check .` fails on
pre-existing unrelated files (CHANGELOG.md — managed by semantic-release — plus
docs/ and scripts/); formatting those is a separate cleanup.

Addresses PR #105 review comment r3355705568.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread .github/workflows/ci_reusable.yaml Outdated
Comment thread .github/workflows/publish.yaml Outdated
levalleux-ludo and others added 2 commits June 4, 2026 14:14
ci_reusable.yaml runs via workflow_call, and `ref: github.event.pull_request.
head.ref` is the wrong revision to check out: it targets the PR head branch tip
rather than the merge commit, and for fork PRs the head ref doesn't exist in
this repo so checkout fails. Drop the explicit ref so actions/checkout uses its
default (github.sha) — the PR merge commit in the caller context, which also
works for fork PRs.

Addresses PR #105 review comment r3356088977.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The inline comment claimed the explicit `origin main` target was needed because
the branch had no upstream after `checkout -B`, but the upstream is now set
(branch.main.remote/merge) a few steps earlier. Update the comment to reflect
that the explicit target is just being explicit; behavior is unchanged.

Addresses PR #105 review comment r3356089027.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread .github/actions/build-test/action.yml
The build-test composite runs Node 22.14.0 / npm 11.5.1 (the latter required by
OIDC trusted publishing), but the Volta pins still selected Node 20.19.0 / npm
8.11.0, so contributors using Volta ran a different runtime than CI and
publishing — a "works locally, fails in CI" gap. Bump the Volta pins to match,
so local dev, PR CI and publish all use the same toolchain.

Addresses PR #105 review comment r3356297523.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@levalleux-ludo levalleux-ludo merged commit 67c2847 into main Jun 4, 2026
4 checks passed
@levalleux-ludo levalleux-ludo deleted the fix/104-npm-oidc-publishing branch June 4, 2026 13:46
levalleux-ludo added a commit that referenced this pull request Jun 4, 2026
PR #105's squash commit message contained a skip directive, so the push
to main skipped all workflows including the new publish workflow. This
empty commit re-triggers it to run the alpha publish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 4, 2026

🎉 This PR is included in version 2.0.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix NPM publication

2 participants