diff options
| author | Edouard CHIN <chin.edouard@gmail.com> | 2025-10-09 17:23:43 +0200 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2025-10-15 09:54:50 +0000 |
| commit | dce202d6d653dfc1b2c64822fe53066c3c558a78 (patch) | |
| tree | a782b115ae3d04662aa35fa0a77c96d5573deaac | |
| parent | 51b2c5a4cd8d1a26f25767366e95391b9de203b5 (diff) | |
[rubygems/rubygems] Add checksum of gems hosted on private servers:
- ### Problem
Running `bundle lock --add-checksums` doesn't add the checksum of
gems hosted on server that don't implement the compact index API.
This result in a lockfile which is unusable in production as
some checksums will be missing and Bundler raising an error.
Users can work around this problem by running:
`BUNDLE_LOCKFILE_CHECKSUMS=true bundle install --force`
But this means redownloading and installing all gems which isn't
great and slow on large apps.
### Context
Bundler uses the Compact Index API to get the checksum of gems,
but most private gem servers don't implement the compact index API
(such as cloudsmith or packagecloud). This results in a soft failure
on bundler side, and bundler leaving out blank checksum for those
gems.
### Solution
For gems that are hosted on private servers that don't send back
the checksum of the gem, I'd like to fallback to the
`bundle install` mechanism, which don't rely on an external API but
instead compute the checksum of the package installed on disk.
This patch goes through the spec that didn't return a checksum,
and compute one if the package exists on disk.
This solution makes the `bundle lock --add-checksums` command
actually usable in real world scenarios while keeping the
`bundle lock` command fast enough.
https://github.com/rubygems/rubygems/commit/8e9abb5472
| -rw-r--r-- | lib/bundler/definition.rb | 13 | ||||
| -rw-r--r-- | spec/bundler/commands/lock_spec.rb | 91 |
2 files changed, 103 insertions, 1 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 6cae8964d8..3c8c13b130 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -540,7 +540,18 @@ module Bundler setup_domain!(add_checksums: true) - specs # force materialization to real specifications, so that checksums are fetched + # force materialization to real specifications, so that checksums are fetched + specs.each do |spec| + next unless spec.source.is_a?(Bundler::Source::Rubygems) + # Checksum was fetched from the compact index API. + next if !spec.source.checksum_store.missing?(spec) && !spec.source.checksum_store.empty?(spec) + # The gem isn't installed, can't compute the checksum. + next unless spec.loaded_from + + package = Gem::Package.new(spec.source.cached_built_in_gem(spec)) + checksum = Checksum.from_gem_package(package) + spec.source.checksum_store.register(spec, checksum) + end end private diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index a7460ed695..36493e108a 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -2174,6 +2174,97 @@ RSpec.describe "bundle lock" do L end + it "add checksums for gems installed on disk" do + build_repo4 do + build_gem "warning", "18.0.0" + end + + bundle "config lockfile_checksums false" + + simulate_platform "x86_64-linux" do + install_gemfile(<<-G, artifice: "endpoint") + source "https://gem.repo4" + + gem "warning" + G + + bundle "config --delete lockfile_checksums" + bundle("lock --add-checksums", artifice: "endpoint") + end + + checksums = checksums_section do |c| + c.checksum gem_repo4, "warning", "18.0.0" + end + + expect(lockfile).to eq <<~L + GEM + remote: https://gem.repo4/ + specs: + warning (18.0.0) + + PLATFORMS + ruby + x86_64-linux + + DEPENDENCIES + warning + #{checksums} + BUNDLED WITH + #{Bundler::VERSION} + L + end + + it "doesn't add checksum for gems not installed on disk" do + lockfile(<<~L) + GEM + remote: https://gem.repo4/ + specs: + warning (18.0.0) + + PLATFORMS + #{local_platform} + + DEPENDENCIES + warning + + BUNDLED WITH + #{Bundler::VERSION} + L + + gemfile(<<~G) + source "https://gem.repo4" + + gem "warning" + G + + build_repo4 do + build_gem "warning", "18.0.0" + end + + FileUtils.rm_rf("#{gem_repo4}/gems") + + bundle("lock --add-checksums", artifice: "endpoint") + + expect(lockfile).to eq <<~L + GEM + remote: https://gem.repo4/ + specs: + warning (18.0.0) + + PLATFORMS + #{local_platform} + + DEPENDENCIES + warning + + CHECKSUMS + warning (18.0.0) + + BUNDLED WITH + #{Bundler::VERSION} + L + end + context "when re-resolving to include prereleases" do before do build_repo4 do |
