Skip to content

publish-npm.yml cannot succeed on first tag push (aborts on adk version collision), and the obvious fix would ship a 75-line sdk@3.0.0 over the real 2.0.14 #44

Description

@yakimoto

publish-npm.yml is the right design — OIDC trusted publishing, provenance, an environment gate, per-package preview/latest tagging. It is also, as written, unable to succeed on its first real tag push, and if that first failure is fixed the obvious way it ships a 75-line shell over a real package.

Both come from the same three lines:

set -euo pipefail
for dir in packages/*/; do
  ...
  ( cd "$dir" && pnpm publish --access public --provenance --no-git-checks --tag "$tag" )
done

Bug 1 — the loop aborts on the first package, every time

The glob expands alphabetically, so packages/adk/ is always first. adk is at 1.0.14 locally and 1.0.14 on npm (published from elsewhere — see #42). npm rejects a republish of an existing version, pnpm publish exits non-zero, and under set -e a failing subshell in command position kills the whole job.

Three of the four packages that exist on npm are exact version collisions:

Package local npm on pnpm publish
adk 1.0.14 1.0.14 collision → job dies here
mcp-server 0.1.8 0.1.8 collision
workflow-sdk 1.0.6 1.0.6 collision
sdk 3.0.0 2.0.14 no collision

So git tag sdks-v… && git push --tags publishes nothing and reports failure — including the 45 packages that have never been published and genuinely should be.

I have not been able to run this: Actions is billing-locked org-wide (wave-rig#174), so the reasoning above is from the source and the registry, not from a run. The version numbers and the glob order are measured; the set -e abort is read from the script.

Bug 2 — the fix that suggests itself is worse than the bug

The natural repair is "skip a version that already exists." Do only that, and sdk becomes the first package to get through — and sdk here is 2 files, 75 lines, versioned 3.0.0, against a real @wave-av/sdk@2.0.14 with 16 versions behind it.

case "$ver" in 0.0.*) tag=preview sends only 0.0.x to preview. 3.0.0 is not 0.0.x, so it goes to latest. Every consumer of @wave-av/sdk would resolve to the shell on their next install, and semver would present it as the newest stable release.

This is the same failure wave-av/adk#64 was opened to prevent, in a second location and with a wider blast radius — adk#64 guards a fork nobody depends on; this guards the package with the most published history in the scope.

Suggested fix — skip collisions, but refuse regressions

Two independent conditions, because they fail differently. Skipping an already-published version is routine; publishing behind the registry is never intended and should stop the job.

set -euo pipefail
for dir in packages/*/; do
  name=$(node -p "require('./${dir}package.json').name" 2>/dev/null) || continue
  case "$name" in @wave-av/*) ;; *) continue ;; esac
  ver=$(node -p "require('./${dir}package.json').version")
  published=$(npm view "$name" version 2>/dev/null || echo "0.0.0")

  # Already on the registry at this exact version: nothing to do. Not an error —
  # a monorepo-wide tag will always include packages that did not change.
  if [ "$ver" = "$published" ]; then
    echo "skip $name@$ver — already published"
    continue
  fi

  # Behind the registry: the local copy is not the source of truth for this package.
  # Never let semver present it as newer. Hard fail — this needs a human.
  newest=$(printf '%s\n%s\n' "$ver" "$published" | sort -V | tail -1)
  if [ "$newest" != "$ver" ]; then
    echo "::error::$name is $ver locally but npm serves $published — refusing to publish backwards (see #42)"
    exit 1
  fi

  tag=latest; case "$ver" in 0.0.*) tag=preview ;; esac
  echo "publishing $name@$ver --tag $tag"
  ( cd "$dir" && pnpm publish --access public --provenance --no-git-checks --tag "$tag" )
done

Note this deliberately still fails on sdk, because sdk@3.0.0 being a 75-line shell is a real problem that a workflow should not paper over. The guard turns a silent bad release into a loud stop.

One thing I got wrong in #42

I recommended "fix the repository fields first." For this repo that is already done — all 49 packages point at wave-av/sdks, which is exactly what provenance requires, and the workflow's (satisfied) comment is accurate. The wrong repository metadata is in the published artifacts, because they were built from a different source copy. Nothing to fix here.

Also worth confirming before arming this

The header says the workflow is inert until a Trusted Publisher is registered on npmjs.com for this repo + this workflow + the npm-publish environment. Worth confirming that is still unregistered — if it were registered, a tag push would already be live, and Bug 1 is the only thing that has been preventing a bad release.

Related: #42 (which repo publishes what), wave-av/adk#64 (same guard, adk fork).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageOn the board but missing Type/Area/Priority

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions