Skip to content

Commit 8e9abb5

Browse files
committed
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.
1 parent 91a4bad commit 8e9abb5

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

bundler/lib/bundler/definition.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,18 @@ def add_checksums
540540

541541
setup_domain!(add_checksums: true)
542542

543-
specs # force materialization to real specifications, so that checksums are fetched
543+
# force materialization to real specifications, so that checksums are fetched
544+
specs.each do |spec|
545+
next unless spec.source.is_a?(Bundler::Source::Rubygems)
546+
# Checksum was fetched from the compact index API.
547+
next if !spec.source.checksum_store.missing?(spec) && !spec.source.checksum_store.empty?(spec)
548+
# The gem isn't installed, can't compute the checksum.
549+
next unless spec.loaded_from
550+
551+
package = Gem::Package.new(spec.source.cached_built_in_gem(spec))
552+
checksum = Checksum.from_gem_package(package)
553+
spec.source.checksum_store.register(spec, checksum)
554+
end
544555
end
545556

546557
private

bundler/spec/commands/lock_spec.rb

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,6 +2174,97 @@
21742174
L
21752175
end
21762176

2177+
it "add checksums for gems installed on disk" do
2178+
build_repo4 do
2179+
build_gem "warning", "18.0.0"
2180+
end
2181+
2182+
bundle "config lockfile_checksums false"
2183+
2184+
simulate_platform "x86_64-linux" do
2185+
install_gemfile(<<-G, artifice: "endpoint")
2186+
source "https://gem.repo4"
2187+
2188+
gem "warning"
2189+
G
2190+
2191+
bundle "config --delete lockfile_checksums"
2192+
bundle("lock --add-checksums", artifice: "endpoint")
2193+
end
2194+
2195+
checksums = checksums_section do |c|
2196+
c.checksum gem_repo4, "warning", "18.0.0"
2197+
end
2198+
2199+
expect(lockfile).to eq <<~L
2200+
GEM
2201+
remote: https://gem.repo4/
2202+
specs:
2203+
warning (18.0.0)
2204+
2205+
PLATFORMS
2206+
ruby
2207+
x86_64-linux
2208+
2209+
DEPENDENCIES
2210+
warning
2211+
#{checksums}
2212+
BUNDLED WITH
2213+
#{Bundler::VERSION}
2214+
L
2215+
end
2216+
2217+
it "doesn't add checksum for gems not installed on disk" do
2218+
lockfile(<<~L)
2219+
GEM
2220+
remote: https://gem.repo4/
2221+
specs:
2222+
warning (18.0.0)
2223+
2224+
PLATFORMS
2225+
#{local_platform}
2226+
2227+
DEPENDENCIES
2228+
warning
2229+
2230+
BUNDLED WITH
2231+
#{Bundler::VERSION}
2232+
L
2233+
2234+
gemfile(<<~G)
2235+
source "https://gem.repo4"
2236+
2237+
gem "warning"
2238+
G
2239+
2240+
build_repo4 do
2241+
build_gem "warning", "18.0.0"
2242+
end
2243+
2244+
FileUtils.rm_rf("#{gem_repo4}/gems")
2245+
2246+
bundle("lock --add-checksums", artifice: "endpoint")
2247+
2248+
expect(lockfile).to eq <<~L
2249+
GEM
2250+
remote: https://gem.repo4/
2251+
specs:
2252+
warning (18.0.0)
2253+
2254+
PLATFORMS
2255+
#{local_platform}
2256+
2257+
DEPENDENCIES
2258+
warning
2259+
2260+
CHECKSUMS
2261+
warning (18.0.0)
2262+
2263+
BUNDLED WITH
2264+
#{Bundler::VERSION}
2265+
L
2266+
end
2267+
21772268
context "when re-resolving to include prereleases" do
21782269
before do
21792270
build_repo4 do

0 commit comments

Comments
 (0)