Move content address to a separate CONTENT ADDRESSES lockfile section - #194
Merged
jenshenny merged 1 commit intoSep 2, 2026
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
The permanent lockfile-format and checksum-identity changes warrant final human cross-version review.
Pull request overview
Moves content addresses into a dedicated lockfile section, preserving Bundler 4.0 compatibility while retaining artifact verification.
Changes:
- Adds
CONTENT ADDRESSESgeneration and parsing. - Keeps standard platform pins in
GEMandCHECKSUMS. - Keys checksums by artifact full name to distinguish fat and content-addressed builds.
File summaries
| File | Description |
|---|---|
lib/bundler/checksum.rb |
Separates checksums by artifact full name. |
lib/bundler/lazy_specification.rb |
Supports parsed content-address assignment. |
lib/bundler/lockfile_generator.rb |
Generates the new section. |
lib/bundler/lockfile_parser.rb |
Parses the new section and ordinary pins. |
lib/bundler/rubygems_ext.rb |
Removes content addresses from lock names. |
spec/bundler/lockfile_parser_spec.rb |
Tests parsing and checksum separation. |
spec/install/gemfile/content_addressable_spec.rb |
Tests installation and lockfile behavior. |
spec/other/ext_spec.rb |
Tests ordinary platform lock names. |
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
A content-addressable gem was locked inline as name (version-address)
platform. Bundler 4.0 parses the token after the version as the platform,
gets unknown, materializes name-version-unknown, and fails: it then either
re-resolves and rewrites the lockfile or fails outright under frozen.
Lockfiles are committed and read by many Bundler versions during
co-publication, so the inline form breaks the exact clients the transition
is supposed to protect.
The spec line is now an ordinary platform pin, and the content address moves
to its own section:
GEM
specs:
nokogiri (1.19.4-x86_64-linux)
CONTENT ADDRESSES
nokogiri (1.19.4-x86_64-linux) 86e5e59f sha256=<content-addressable build's sha>
CHECKSUMS
nokogiri (1.19.4-x86_64-linux) sha256=<platform build's sha>
Verified against the released Bundler 4.0.9:
- unknown unindented sections set @parse_method = nil and are skipped
silently (lockfile_parser.rb:137)
- Definition#lockfiles_equal? subtracts unknown sections before comparing
(definition.rb:1196), so a plain 4.0 bundle install does not rewrite the
lockfile and the section survives; it is only dropped on a genuine 4.0
re-lock, and restored on the next 4.1 re-lock
- 4.0 classifies a locked spec with a missing or empty CHECKSUMS entry as a
lockfile change (definition.rb:619-620): a plain install re-resolves and
frozen mode hard-fails. The platform lock name line must therefore carry a
real checksum, and it must be the platform build's, since 4.0 attributes
it to the artifact it installs for that lock name
That last point drives the checksum rules:
- the checksum store is keyed by full name instead of lock name, because a
content-addressable build and the platform build of the same name,
version, and platform share a lock name while being different files.
Store#register accepts anything responding to full_name and lock_name, so
the parser registers CHECKSUMS entries under the name tuple parsed from
the line rather than the (possibly content-addressed) spec object
- the content-addressable build's checksum is serialized next to its
address in CONTENT ADDRESSES, the only place older Bundler never parses,
and verifies the downloaded gem via the existing install-time registration
- CHECKSUMS carries the platform build's checksum, which the compact index
supplies for every row the fetcher sees, so it is captured during
resolution without downloading the platform gem
- when no platform build exists (skinny-only publication), the CHECKSUMS
line is omitted entirely rather than written bare, so every CHECKSUMS
line describes an artifact installable by its lock name
The section registers in SECTIONS_BY_VERSION_INTRODUCED under 4.1.0, and
its line format requires a platform, since content addressing only applies
to platformed gems.
Assisted-By: devx/01a05e2e-d421-7e27-b54e-abee85203da5
jenshenny
force-pushed
the
ca-lockfile-content-addresses-section
branch
from
September 2, 2026 02:10
c7bc124 to
91c4adc
Compare
jenshenny
marked this pull request as ready for review
September 2, 2026 02:49
jenshenny
merged commit Sep 2, 2026
8a1edc2
into
feature-branch-ca-changes-rubygems
106 of 109 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Implements item 4 of hsbt's format review: the content address moves out of the
GEM/specsline into a dedicatedCONTENT ADDRESSESsection, so a lockfile written by Bundler 4.1 degrades gracefully on Bundler 4.0 instead of breaking it.Why the inline format had to go
nokogiri (1.19.4-86e5e59f) x86_64-linuxparses on 4.0 as platformunknown→ materializesnokogiri-1.19.4-unknown→ fails, then re-resolves and rewrites the lockfile (or hard-fails under frozen). Lockfiles are committed and read by many Bundler versions during co-publication, and the format is permanent once shipped.Verified against released Bundler 4.0.9
@parse_method = nil)lockfile_parser.rb:137bundle installdoesn't rewrite:lockfiles_equal?ignores unknown sections, so the section survives plain installs and frozen mode; it's only dropped on a genuine 4.0 re-lockdefinition.rb:1196-1208definition.rb:619-620, 861-862, 933-935return unless spec)parse_checksumCompat matrix
bundle update)