fix(ci): publish in topological order so a mid-run failure cannot strand a package ahead of its deps - #47
Conversation
…and a package ahead of its deps
|
Bugbot couldn't run - usage limit reachedBugbot 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_74b087d7-a5b8-4494-b0ea-39a67ad9cdf0) |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
Closes #46. Stacked on #45 (base is
fix/publish-version-guard, notmain) — both change the same publish step, so basing this onmainwould conflict.The defect
The publish loop iterates
packages/*/, which globs alphabetically. That is not dependency order, and the loop runs underset -euo pipefail— so a failure partway through leaves every package before the failure point already live on npm.Measured on this workspace:
npm does not validate that a dependency exists at publish time, and a published version can never be replaced. So an interrupted alphabetical run can leave a permanently-broken package sitting on
latest.The fix
Sort the already-validated
publishableset topologically before executing it. Only edges to packages in this release constrain the order — a dependency already on the registry is satisfied regardless of when we publish, so it imposes nothing.Nothing else changes: auth (OIDC, no token), permissions, the publish command, and all three existing guards from #45 (backwards-version, unresolved-dependency, tarball-size) run unmodified in the earlier validation pass. This only reorders a set that has already been approved.
Three deliberate hardening choices, since this is the last thing standing between a tag push and npm:
^packages/[a-z0-9][a-z0-9._-]*/$. The dirs come from the workflow's own glob, but this script builds a filesystem path from each one, and provenance is not a substitute for validation.__proto__would corrupt the lookup rather than merely being wrong.The node program is a fixed single-quoted argv with input on stdin — no
${{ }}interpolation, and no package-controlled data is ever assembled into code.Verification
CI cannot run — the whole org is under a GitHub billing lock (
"The job was not started because your account is locked due to a billing issue."), which affects public repos too. So this was verified locally against the exact bytes extracted from the workflow file, not a copy:This should not be merged until CI can actually run it. Branch protection is currently unenforced org-wide as a side effect of the same billing lock, so a green tick here would mean the gate vanished, not that the change passed.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Note
Medium Risk
Changes the publish gate ordering logic for all tag releases; mistakes could block publishes (cycles/empty sort) or still mis-order if dependency edges are wrong, but it does not weaken existing validation or auth.
Overview
The npm publish step now topologically sorts the already-validated
publishableset beforepnpm publish, instead of iteratingpackages/*/in alphabetical order.That matters because the loop runs under
set -euo pipefail: a mid-run failure leaves earlier packages live on npm, and npm does not require dependencies to exist at publish time—so publishing a dependent before its workspace dep can strand a brokenlatest. Only @wave-av/ edges to packages in the same release constrain ordering; registry-only deps do not.The sort is a fixed stdin-fed
node -eblock that re-validates paths (^packages/...), uses null-prototype maps, fails closed on dependency cycles, and rejects an empty sort whenpublishableis non-empty. Validation guards from the prior pass are unchanged; only the publish loop input switches frompublishabletotopo_sorted.Reviewed by Cursor Bugbot for commit 1d1a4fe. Configure here.
Summary by cubic
Publish step now sorts packages topologically so dependencies are published first. This prevents a mid-run failure from leaving a package live ahead of its deps. No other behavior changes.
publishableset; only edges to packages in this release constrain the order.__proto__).Written for commit 1d1a4fe. Summary will update on new commits.