Skip to content

fix(release): read the crate checksum from the sparse index - #525

Merged
us merged 1 commit into
mainfrom
fix/release-republish-guard
Sep 10, 2026
Merged

us merged 1 commit into
mainfrom
fix/release-republish-guard

Conversation

@us

@us us commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

publish_crate.sh treats "already uploaded" as success only when the local
.crate sha matches the published one. That check has been silently broken:
crates.io's /api/v1/crates/<name>/<version> response no longer carries
version.cksum.

Checked against the live registry on 2026-09-10, the field is absent for every
crate:

$ curl -fsSL https://crates.io/api/v1/crates/crw-mcp-proto/0.34.0 | jq '.version.cksum'
null

So crate_version_cksum returned an empty string with rc 0, and the caller
compared it straight against the local sha. Every idempotent re-publish therefore
failed as a content mismatch. The v0.34.0 release (run 34490023731) died there:

error: crate crw-mcp-proto@0.34.0 already exists on crates.io index
crw-mcp-proto@0.34.0 content mismatch - local=8e9006f12b5e8da3434b167991cc75b6168e1c32f07eb17ee5b54201e00d3b3c remote=
crates.io is immutable; cannot republish. Bump the version.

The sparse index reports that same 8e9006f12b... for the version, so the upload
matched and the run should have taken the idempotent-skip path. The advice to
bump the version was wrong, and would have burned a version number over a lookup
that simply failed.

Change

  • crate_version_cksum reads the checksum from index.crates.io (the registry
    index protocol, where the value is authoritative) instead of the v1 API, and
    returns non-zero when the index or the version cannot be read rather than
    printing nothing and succeeding. crate_index_path implements the documented
    1/2/3/4+ prefix layout.
  • publish_crate.sh separates "unknown" from "different". An unverifiable upload
    still fails the release, because blessing it would defeat the guard, but it no
    longer reports a content mismatch or advises a version bump when the checksum
    could not be read.
  • crate_version_present is unchanged: it reads .version.num, which the v1 API
    still returns.

Tests

Six tests added to the existing guard suite (scripts/release/test_guards.py,
already run by CI). They stub curl and cargo on PATH so the real scripts run
with no network:

test_crate_index_path_follows_the_registry_protocol
test_crate_cksum_reads_the_requested_version_from_the_index
test_crate_cksum_fails_when_the_version_is_absent
test_crate_cksum_fails_when_the_index_is_unreachable
test_unreadable_cksum_is_not_reported_as_a_content_mismatch
test_matching_cksum_is_an_idempotent_skip

All six fail against the code on main and pass with this change; the suite is
14/14 locally.

Deploy notes

Release-pipeline only, no engine or API surface is touched. The next release that
hits the already-uploaded path takes the idempotent-skip branch instead of
failing, which is what publish-crates needed on the last two runs.

@us
us force-pushed the fix/release-republish-guard branch from 5497e9e to db90e58 Compare September 10, 2026 16:02
crates.io's /api/v1/crates/<name>/<version> response no longer carries
`version.cksum` (checked 2026-09-10: absent for every crate queried), so
`crate_version_cksum` returned an empty string with rc 0. `publish_crate.sh`
compared that empty value straight against the local sha, so every idempotent
re-publish failed as a content mismatch and told the maintainer to bump the
version. The v0.34.0 release died exactly there:

  error: crate crw-mcp-proto@0.34.0 already exists on crates.io index
  crw-mcp-proto@0.34.0 content mismatch - local=8e9006f12b... remote=
  crates.io is immutable; cannot republish. Bump the version.

The sparse index reports `8e9006f12b...` for that version, which is the sha the
run had just computed locally: the upload matched and the release should have
skipped it. Read the checksum from the index, which is the registry protocol and
where the value is authoritative, and return non-zero when it cannot be read.

`publish_crate.sh` now separates "unknown" from "different". An unverifiable
upload still fails the release, because blessing it would defeat the guard, but
it no longer claims the content differs or advises bumping a version over a
lookup that simply failed.

Pinned by six tests in the existing guard suite, which stub curl and cargo so the
real scripts run with no network. All six fail against the previous code.
@us
us force-pushed the fix/release-republish-guard branch from db90e58 to ed93f39 Compare September 10, 2026 16:12
@us
us merged commit ab43c40 into main Sep 10, 2026
11 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 10, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant