ci(release): make npm trusted publishing work + post-publish verification
LIVE RECEIPTS
@wave-av/cli 1.0.8 on npm latest prints --version as 1.0.0 (hardcoded,
never matched the real published version) and wave status silently
exited 0 on auth/health failure. The fix for both is already on main
(the 1.0.9 work) with its own unit tests — this PR does not touch that
code. What was still missing: release.yml (from #44) has no working
Trusted Publishing path and no proof that a publish actually reached npm
correctly.
Measured locally against node --version bundled by actions/setup-node's
Node 22:
$ node -v && npm -v
v22.14.0
10.9.2
npm's own docs require npm >= 11.5.1 for OIDC trusted publishing.
10.9.2 is below that floor, so the OIDC branch in the existing workflow
could never actually run — every publish was silently falling through to
the NPM_TOKEN fallback, and would fail outright the moment that secret
is absent (which, per the live smoke that motivated this wave, it is).
Local dry-run of the new apiEndpoint extraction logic this PR adds to
verify-publish (proven against this repo's own build, not the published
package, since publishing is an operator crossing):
$ npm run build && node dist/index.js status --output json
WAVE CLI Status
Auth: Not authenticated
...
Endpoint: https://api.wave.online
{
"project": "default",
"authenticated": false,
"apiEndpoint": "https://api.wave.online",
...
}
$ OUT="$(node dist/index.js status --output json 2>&1 || true)"
$ echo "$OUT" | node -e "...parse from first '{'..."
apiEndpoint=https://api.wave.online
actionlint .github/workflows/release.yml — clean, no findings.
ROOT CAUSE
Two gaps left the OIDC path non-functional and unverified:
actions/setup-node@v7withnode-version: "22"installs whatever npm
Node 22 bundles (10.9.2) — below npm's own 11.5.1 floor for trusted
publishing.mcp-server'srelease.ymlalready had to solve this with
an explicitnpm install -g npm@11.19.0step;cli's did not.- The
releasejob's own smoke test packs and installs a local tarball
before publish — real coverage of the build, but no step proves the
package that actually landed on the registry is reachable and correct.
WHAT CHANGED
.github/workflows/release.yml:
- npm upgrade step before the publish attempt: pins
npm@11.19.0,
then asserts the resulting version is>= 11.5.1(fails loudly instead
of silently degrading to the token fallback). - New
verify-publishjob,needs: release:- Polls
npm view @wave-av/cli@<tag>(8x, 15s apart) until the registry
confirms the exact tagged version is indexed. - Installs that version from the real registry into a throwaway
project and assertsnpx wave --versionprints the tagged version. - Runs
wave status --output json, extracts the JSON block (the
command also prints a human summary first; extraction starts from the
first{), and assertsapiEndpointis exactly
https://api.wave.online— the receipt that the published binary
targets the real API, never thewave.onlinemarketing site.
- Polls
The NPM_TOKEN fallback from #44 is unchanged and still applies whenever
that secret is set, independent of whichever npm version is active.
No source under src/ changed. --version reading package.json at
runtime and wave status exiting non-zero on failure are both already on
main with tests in src/cli.test.ts and
src/commands/status/index.test.ts.
GATES (local, tails)
npm test(vitest):Test Files 4 passed (4),Tests 11 passed (11).npm run build:ESM dist/index.js 158.82 KB— succeeds in 36ms.actionlint .github/workflows/release.yml: clean.npm run lint: fails locally —eslintis referenced in thelint
script but is not a declared dependency in this checkout
(sh: eslint: command not found); pre-existing onmain, unrelated to
this change, and not a steprelease.ymlruns.npm run type-check: fails locally with pre-existingsrc/types
module-resolution errors unrelated to this change (that directory does
not exist in this checkout);tsup's esbuild-based build does not do
full type resolution so it is unaffected, and no workflow in this repo
invokestype-checktoday (grep confirms only a comment mentions it).
Flagging as a known gap, not something this PR silently worked around.
OPERATOR STEPS
One-time npm Trusted Publisher registration (this repo has no
NPM_TOKEN secret today per the live smoke, so the OIDC path is the only
one that will work until one is set):
- Sign in to https://www.npmjs.com, go to the
@wave-av/clipackage ->
Settings -> Trusted Publisher -> "Add GitHub Actions publisher". - Fill in exactly:
- Organization/user:
wave-av - Repository:
cli - Workflow filename:
release.yml - Environment: (leave blank — this workflow does not scope publish to
a GitHub Environment)
- Organization/user:
- Save. No token is generated or stored.
To cut the 1.0.9 release once this PR is merged and the Trusted Publisher
above is registered (operator-run, not this agent — package.json on
main is already 1.0.9, matching the fix already merged):
git -C ~/wave-av/cli fetch origin
git -C ~/wave-av/cli tag v1.0.9 origin/main
git -C ~/wave-av/cli push origin v1.0.9
That tag push triggers release.yml. Watch both the release job and
the new verify-publish job in the Actions tab — a green verify-publish
is the live receipt that npx @wave-av/cli@1.0.9 --version prints 1.0.9
and defaults to https://api.wave.online.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MPeHryYVubEwzmnnf8pykK
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.
[!NOTE]
Low Risk
CI-only workflow changes with no application source or runtime behavior changes; failures only block a release pipeline if the live package is wrong or not yet visible on npm.
Overview
Adds a verify-publish job that runs after publish so a green release is not only “npm publish exited 0” but the tagged build is actually on the public registry.
The job derives the expected version from the release tag, polls npm view (up to eight attempts, 15s apart) until that exact version is indexed, then installs @wave-av/cli from registry.npmjs.org in a throwaway project and fails if npx wave --version does not match the tag. A final step runs wave status --output json, parses the trailing JSON block, and asserts the default apiEndpoint is https://api.wave.online (not the marketing host).
Reviewed by Cursor Bugbot for commit 465054e58dc9ff459788506eacf78db065a95ea8. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by Sourcery
Harden the npm release workflow for trusted publishing and verify that each published CLI package is live and correctly configured.
New Features:
- Add post-publish verification that confirms the tagged CLI version is available from npm, reports the expected version, and targets the production API endpoint.
Bug Fixes:
- Ensure the release workflow can use npm OIDC trusted publishing by enforcing a compatible npm version before publishing.
CI:
- Harden the release workflow with an npm version prerequisite and live registry smoke checks after publishing.
Tests:
- Verify the published package from the real npm registry rather than only testing the pre-publish tarball.