Skip to content

fix(ci): validate the whole release before publishing any of it - #45

Open
yakimoto wants to merge 2 commits into
mainfrom
fix/publish-version-guard
Open

fix(ci): validate the whole release before publishing any of it#45
yakimoto wants to merge 2 commits into
mainfrom
fix/publish-version-guard

Conversation

@yakimoto

@yakimoto yakimoto commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Fixes the two problems in #44.

publish-npm.yml is a good design — OIDC trusted publishing, provenance, an environment gate, per-package preview/latest tagging. It just could not run. packages/adk/ sorts first, sits at 1.0.14 both locally and on npm, and npm rejects a republish; under set -e the job died there, before reaching the 45 packages that have never shipped at all.

The obvious repair — skip versions that already exist — is worse than the bug. packages/sdk is 3 files against a published 2.0.14 of 286 files, and because it carries version 3.0.0 it is numerically ahead, so it would have sailed through to the latest dist-tag and become the newest stable release for every consumer of @wave-av/sdk.

What changed

Collisions are skipped, not fatal. A monorepo-wide tag always sweeps up packages that did not change.

Two things now fail validation: a version that sorts behind the registry, and a tarball less than half the unpackedSize of the one it replaces. The second is the one that matters — a version number tells you nothing about whether the package still has its contents in it.

Validation is a separate pass over every package before anything publishes. Inline validation meant one bad package stranded everything sorting after it — sdk failing would have silently dropped search through zoom, twelve packages that were fine. A release is either coherent or it doesn't go.

Registry lookups use curl against registry.npmjs.org, not npm view. A scoped @wave-av:registry setting outranks --registry, so npm view can answer about GitHub Packages instead. That is not hypothetical — it's the specific trap that caused these packages' publisher to be mis-identified in #42, and I hit it again while testing this change.

Actions are SHA-pinned (same v4 releases, just immutable). This is the one workflow in the repo holding publish rights.

Verification

Actions is billing-locked org-wide (wave-rig#174), so this has not run in CI. I tested it by extracting the exact run: block out of the YAML and executing it with pnpm publish stubbed:

Against all 49 real packages, current state — 48 evaluated, sdk trips the shrink guard, zero publishes:

::error::@wave-av/sdk@3.0.0 packs 4749B but 2.0.14 packs 994775B — refusing to publish
         a package less than half the size of the one it replaces (see #44)
::error::1 package(s) failed release validation — publishing nothing.
exit=1     (STUB-publish invocations: 0)

A version behind the registry — fails, and the other packages are still evaluated rather than skipped:

::error::@wave-av/adk is 1.0.13 here but npm serves 1.0.14 — refusing to publish backwards
eligible @wave-av/audience@0.0.2 (npm has 0.0.0)
eligible @wave-av/qr@0.1.0 (npm has 0.0.0)
exit=1     (STUB-publish invocations: 0)

Clean fixture — publishes both, with the right dist-tags (0.0.2preview, 0.1.0latest):

exit=0     (STUB-publish invocations: 2)

What this does not fix

sdk@3.0.0 being a 75-line shell is still a real problem — this change makes it a loud stop instead of a bad release. Somebody has to decide whether that directory is the source of truth for @wave-av/sdk at all, which is the open question in #42.

And this guards one door. Five of the six published @wave-av packages were published from somewhere else entirely, so a guard here does not prevent a release from there.

Refs #44, #42.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Note

Medium Risk
Changes the npm publish gate and release validation logic on a workflow with OIDC publish permissions; mistakes could block legitimate releases or (if guards were wrong) allow bad publishes, though the change is intended to reduce supply-chain risk.

Overview
Hardens publish-npm.yml so monorepo tag pushes can complete without accidentally shipping bad or duplicate @wave-av/* packages.

Publish script now uses a two-pass flow: every package is validated first (skip versions already on npm, refuse publishing behind the registry, refuse tarballs less than half the published unpackedSize), and nothing publishes if any package fails. Registry metadata is fetched via curl to registry.npmjs.org instead of npm view, avoiding scoped-registry misreads.

GitHub Actions steps (checkout, pnpm, setup-node) are SHA-pinned on the workflow that holds publish rights.

Reviewed by Cursor Bugbot for commit 4c190bd. Configure here.


Summary by cubic

Validate the whole npm release before publishing anything to avoid partial or wrong releases. Skip already-published versions and block backward versions, suspiciously small tarballs, and packages with unresolved @wave-av/* dependencies.

  • Bug Fixes

    • Run a validation pass over all @wave-av/* packages; publish only if all pass.
    • Skip packages already published at the same version.
    • Fail if the local version sorts behind the registry or if the packed size is <50% of the current release.
    • Reject packages with @wave-av/* deps that exist neither on npm nor in this workspace; allow deps satisfied by the same release.
    • Query registry.npmjs.org with curl instead of npm view to avoid scoped-registry misreads, and tighten slug validation.
  • Dependencies

    • SHA-pin actions/checkout, pnpm/action-setup, and actions/setup-node.

Written for commit 58bdb14. Summary will update on new commits.

Review in cubic

publish-npm.yml could not succeed on a first tag push. `packages/adk/` sorts
first, is already on npm at its local version, and npm rejects a republish —
so the loop died there under `set -e` before reaching the 45 packages that
have never shipped.

Skipping collisions alone would have been worse than the bug: `packages/sdk`
is 3 files against a published 2.0.14 of 286, and being numerically ahead at
3.0.0 it would have gone straight to the `latest` dist-tag.

Three changes:

- already-published versions are skipped, not fatal — a monorepo-wide tag
  always includes packages that did not change
- a version behind the registry, or a tarball less than half the size of the
  one it replaces, fails validation
- validation runs as a separate pass over every package before anything is
  published, so one bad package cannot strand the ones that sort after it

Registry lookups go to registry.npmjs.org over curl rather than `npm view`,
because a scoped @wave-av:registry setting outranks --registry and can answer
about the wrong registry entirely — the same trap that mis-identified these
packages' publisher in #42.

Actions are SHA-pinned; this is the one workflow here holding publish rights.

Verified locally with the publish call stubbed: shrink guard trips on sdk and
publishes nothing (exit 1); a behind-registry version trips and publishes
nothing (exit 1); a clean fixture publishes both packages with the expected
preview/latest tags (exit 0).

Refs #44, #42
@changeset-bot

changeset-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 58bdb14

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cursor

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_60acbb40-0806-49dd-a66d-2bcdfb823330)

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 23 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b650cf6c-0442-48ec-a58e-2c84914604cc

📥 Commits

Reviewing files that changed from the base of the PR and between 9eb128a and 58bdb14.

📒 Files selected for processing (1)
  • .github/workflows/publish-npm.yml
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/publish-version-guard
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/publish-version-guard

Comment @coderabbitai help to get the list of available commands.

…claim

The size guard mis-diagnoses packages/sdk. It is not a shell — it is a re-export barrel over 44 product packages, and small is what correct looks like for one. The comment asserting otherwise is now fixed, and the guard is documented as a known false positive to narrow rather than delete when the umbrella is ready.

Adds a dependency check that catches what size cannot: a dependency that exists neither on the registry nor in this workspace. That is a broken reference no amount of publishing can satisfy.

Deliberately NOT a registry-only check. 45 of the 49 packages depend on @wave-av/core, which is itself unpublished, so requiring every dependency to be on npm already would reject nearly the whole workspace on the first coordinated release. A gate that always fires teaches people to route around it.

Verified both directions locally, since CI cannot run: all 45 packages with @wave-av dependencies pass, and a synthetic dependency on a package that exists nowhere is rejected by name while its workspace sibling is not.

Also tightens the registry_meta slug check. The case pattern only anchored the first character, so a name like a/../x would have reached the URL.
@cursor

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_30b17538-d2d9-40c7-ad21-82b3576c0ff3)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant