ci(root): add recovery-mode to beta publish for auto-retry on Rekor conflicts#9348
Conversation
|
The "Validate Humans In The Loop" check failure is expected here — the commit is signed with an SSH key (this session's default), not GPG, and isn't in the registered-engineer key allowlist. That check exists specifically to require human sign-off on AI-authored commits, so this isn't something to "fix" by re-signing — it needs 2 approvals from the CODEOWNERS group (@bitgo/btc-team, @bitgo/ecosystem, @bitgo/wallet-core, @bitgo/wallet-core-india) to pass, same as it would for any AI-authored commit. Generated by Claude Code |
|
Pushed 9005101 addressing review feedback: replaced the two-input design ( Generated by Claude Code |
Stuck beta publishes retried on publish.yml can hit TLOG_CREATE_ENTRY_ERROR (409) sigstore/Rekor collisions: Rekor entries are keyed on the tarball's sha256 digest, which embeds the package version, and prepare-release.ts recomputes an identical next version (and therefore an identical digest) on retry since the stuck package's npm dist-tag never advanced after the failed registry write. `recovery-mode` is a single boolean workflow_dispatch input; the bump amount is decided automatically at actual publish time rather than guessed up front. scripts/verify-release.ts, which already loops over packages checking each one's live dist-tag against its local version and publishes any that are missing, now retries a still-missing package's `npm publish` call when recovery-mode is enabled and the failure output matches the Rekor conflict signature (TLOG_CREATE_ENTRY_ERROR or a 409 "transparency log" error), bumping that package's prerelease version between attempts (capped at 5) so its tarball digest is new. This is strictly opt-in via RECOVERY_MODE; behavior is unchanged when it's off. Also mark the "Lerna Publish" workflow step continue-on-error when recovery-mode is enabled, since a stuck package's Rekor conflict fails that step outright and would otherwise prevent the "Verify Publish" step (and its new retry logic) from running at all. No Linear ticket exists for this CI-only infra fix; using the INF-000 junk-drawer reference per the WEB-000/BTC-000/CSHLD-000 convention documented in CLAUDE.md, since INF (Infrastructure) is the closest registered issue prefix for a non-coin, non-web CI change. TICKET: INF-000 Co-Authored-By: Claude Sonnet 5 <[email protected]>
9005101 to
d22e5ad
Compare
Requested by Zahin Mohammad · Slack thread
Description
The beta publish workflow (
.github/workflows/publish.yml) can get stuck in a state where retrying it fails withTLOG_CREATE_ENTRY_ERROR (409)sigstore/Rekor collisions for packages whose npm registry write failed on a previous attempt, even though nothing else about the release changed.What broke:
npm publishwith provenance (NPM_CONFIG_PROVENANCE: true) logs a Sigstore/Rekor transparency-log entry for the published tarball before/alongside writing to the npm registry. If the registry write itself fails (network blip, registry error, etc.) after the Rekor entry was already created, a naive retry of the workflow fails again with a 409 from Rekor'sTLOG_CREATE_ENTRY_ERROR.Why: Rekor entries are keyed on the tarball's sha256 digest, and that digest is derived from the packed tarball contents, which include the version in
package.json. The live npm dist-tag for a stuck package never advances (its registry write failed), so simply re-running the workflow recomputes the exact same version -> the exact same tarball -> the exact same digest -> the same already-logged Rekor entry -> 409 on retry. There was previously no way to get past this short of manually bumping versions by hand.What this PR changes:
.github/workflows/publish.yml: adds arecovery-modebooleanworkflow_dispatchinput (defaultfalse). When set, theLerna Publishstep is markedcontinue-on-error: ${{ inputs.recovery-mode }}so a Rekor conflict there doesn't hard-fail the job, and theVerify Publishstep now receives aRECOVERY_MODE: ${{ inputs.recovery-mode }}env var.scripts/verify-release.ts: adds apublishWithRecovery()helper used byverifyPackage()in place of the old directnpm publishcall. WhenRECOVERY_MODEis set, it detects a Rekor conflict in the publish output (TLOG_CREATE_ENTRY_ERROR, or a(409)mentioning the transparency log), bumps that package'sversioninpackage.jsonwithsemver.inc(..., 'prerelease', ..., preid), and retries — up toMAX_RECOVERY_ATTEMPTS(5) attempts per package — until it lands on a version whose tarball digest hasn't already been logged.verify()also no longer aborts on the first stuck package when recovery mode is on; it keeps going through the rest of the packages and reports overall failure viaprocess.exitCodeat the end.scripts/prepare-release.tsis untouched — no CLI flags were added there, and the fix lives entirely in the publish/verify steps that run after version prep.recovery-modeleft at its default (false), behavior is unchanged:publishWithRecovery()makes exactly one attempt and rethrows on failure, same as the previous directnpm publishcall.How to use it (runbook):
TLOG_CREATE_ENTRY_ERROR (409)on retry, re-triggerPublish @bitgo-betaviaworkflow_dispatchwithrecovery-mode: true.verify-release.tsdetects the Rekor conflict per package and bumps+retries automatically (up to 5 attempts per package) until each stuck package clears.recovery-mode: false(the default) preserves today's behavior exactly.Type of change
How Has This Been Tested?
recovery-mode: false(the default) is a no-op:continue-on-errorevaluates tofalseandpublishWithRecovery()'s loop bound collapses to a single attempt that rethrows immediately, identical to the previous directnpm publishcall.TLOG_CREATE_ENTRY_ERROR/409 in the publish output is caught, the package'spackage.jsonversion is bumped withsemver.inc(..., 'prerelease', ..., preid)and rewritten to disk, and the publish is retried, up to 5 attempts before giving up with an explicit error.publish.ymlworkflow (no credentials, and it is a live release workflow that should never be triggered from this kind of change).Checklist
INF-000junk-drawer reference, following theWEB-000/BTC-000/CSHLD-000convention documented inCLAUDE.md)publish.ymlitself, andverify-release.tshas no existing unit test suite to extend)Generated by Claude Code