Skip to content

Lock the checksum of Bundler itself in the lockfile#9366

Open
Edouard-chin wants to merge 2 commits intoruby:masterfrom
Shopify:ec-bundler-checksum
Open

Lock the checksum of Bundler itself in the lockfile#9366
Edouard-chin wants to merge 2 commits intoruby:masterfrom
Shopify:ec-bundler-checksum

Conversation

@Edouard-chin
Copy link
Collaborator

What was the end-user or developer problem that led to this PR?

I'd like to be able to lock the checksum of the bundler gem itself. I find strange that all gems get their checksum locked, but bundler itself (which is the only gem that every application will need to install due to the auto-switch feature) isn't getting locked.
I think this is a security vulnerability and I'd like to fix this.

With this patch, the lockfile will look like this:

GEM
  remote: https://rubygems.org/
  specs:
    warning (1.5.0)

PLATFORMS
  arm64-darwin-25
  ruby

DEPENDENCIES
  warning

CHECKSUMS
  bundler (4.2.0.dev) sha256=fe2e521b3e2897f24b59cdc682b10ffb2a43677c183fc619911716aa3f203237 <----- This is new
  warning (1.5.0) sha256=0f12c49fea0c06757778eefdcc7771e4fd99308901e3d55c504d87afdd718c53

BUNDLED WITH
  4.2.0.dev

What is your fix for the problem, implemented in this PR?

Details

I'd like to introduce this change into two separate changes for easier reviews. The first (this commit) only produce the checksum in the lockfile, nothings consumes it or verify it yet.

The second patch will make sure that whenever the Bundler auto-install kicks in, Bundler will verify that the locked checksum matches the Bundler version being downloaded and installed.

Though, please let me know if you'd prefer me doing the whole thing in just one PR.

Solution

Overall the solution here is similar to how checksums are already generated for other gems. However, the bundler gem comes from a different source (the Bundler::Source::Metadata) and so it needs to be handled slightly differently.

A big part ot the change is test related. Instead of having to modify all tests that assert the state of the lockfile (which will be broken now, since the lockfile includes the Bundler checksum), I opted to automatically include the checksum whenever the helper metod checksums_section is called.

I'll add a few comments on the code directly for parts that may not be obvious.

Make sure the following tasks are checked

- ### Problem

  With the Bundler autoswitch feature, system Bundler may install
  a `bundler.gem` that matches the Gemfile.lock.
  The `bundler.gem` that gets downloaded is like any other gems,
  but its treated differently (it doesn't appear in the Gemfile specs
  and we also don't lock its checksum).

  If for any reason Bundler itself gets compromised, it's a security
  concern.

  ### Details

  I'd like to introduce this change into two separate changes for
  easier reviews.
  The first (this commit) only produce the checksum in the lockfile,
  nothings consumes it or verify it yet.

  The second patch will make sure that whenever the Bundler
  auto-install kicks in, Bundler will verify that the locked checksum
  matches the Bundler version being downloaded and installed.

  ### Solution

  Overall the solution here is similar to how checksums are already
  generated for other gems. However, the `bundler` gem comes from a
  different source (the `Bundler::Source::Metadata`) and so it needs
  to be handled slightly differently.

  A big part ot the change is test related. Instead of having to
  modify all tests that assert the state of the lockfile (which
  will be broken now, since the lockfile includes the Bundler
  checksum), I opted to automatically include the checksum whenever
  the helper metod `checksums_section` is called.
@Edouard-chin Edouard-chin changed the title Lock the checksum of Bundler itself in the lockfile: Lock the checksum of Bundler itself in the lockfile Mar 5, 2026
require "rubygems/package"

bundler_spec = definition.sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last
return [] unless File.exist?(bundler_spec.cache_file)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I unfortunately need to have this File.exist?(bundler_spec.cache_file) condition here due to the way our rspec is setup. At the very beginning of the a test process, we install test dependencies and we use the local copy of bundler for that. We activate the bundler spec in a weird way, but there is no associated bundler.gem tarball, so we can't compute the checksum.

Note that this condition is only needed to install the dependencies of bundler itself. It doesn't affect tests itself (because we build a bundler.gem each time a test starts).


CHECKSUMS
ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
bundler (4.1.0.dev) sha256=d2562ecdca5da9c15b46fedd7dbc109fca4938895942e34564c974ee6eabd5f8
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I just saw that CI was complaining because the lockfile for development purposes aren't up to date, so I modified them.

This may be annoying though, as it means any changes in Bundler we make will change the checksum and we'd need to update them by running rake version:update_locked_bundler.

I have to think of a solution

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add option to opt-out of this feature somehow? Alternatively skip it for dev/pre versions? I think similar gate is around auto-switch/install trampoline and call for update features. They are disabled if dev Bundler/RubyGems is detected.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh nice! Good idea to skip for dev/pre versions, thanks for the suggestion !

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants