diff options
22 files changed, 355 insertions, 87 deletions
diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb index 2e0a80cac2..0b618d5033 100644 --- a/lib/bundler/checksum.rb +++ b/lib/bundler/checksum.rb @@ -2,22 +2,37 @@ module Bundler class Checksum - attr_reader :name, :version, :platform - attr_accessor :checksum + attr_reader :name, :version, :platform, :checksums - SHA256 = /\Asha256-([a-z0-9]{64}|[A-Za-z0-9+\/=]{44})\z/.freeze + SHA256 = %r{\Asha256-([a-z0-9]{64}|[A-Za-z0-9+\/=]{44})\z}.freeze - def initialize(name, version, platform, checksum = nil) + def initialize(name, version, platform, checksums = []) @name = name @version = version @platform = platform || Gem::Platform::RUBY - @checksum = checksum + @checksums = checksums - if @checksum && @checksum !~ SHA256 - raise ArgumentError, "invalid checksum (#{@checksum})" + # can expand this validation when we support more hashing algos later + if @checksums.any? && @checksums.all? {|c| c !~ SHA256 } + raise ArgumentError, "invalid checksums (#{@checksums})" end end + def self.digest_from_file_source(file_source) + raise ArgumentError, "not a valid file source: #{file_source}" unless file_source.respond_to?(:with_read_io) + + file_source.with_read_io do |io| + digest = Bundler::SharedHelpers.digest(:SHA256).new + digest << io.read(16_384) until io.eof? + io.rewind + digest + end + end + + def full_name + GemHelpers.spec_full_name(@name, @version, @platform) + end + def match_spec?(spec) name == spec.name && version == spec.version && @@ -26,17 +41,17 @@ module Bundler def to_lock out = String.new - - if platform == Gem::Platform::RUBY - out << " #{name} (#{version})" - else - out << " #{name} (#{version}-#{platform})" - end - - out << " #{checksum}" if checksum + out << " #{GemHelpers.lock_name(name, version, platform)}" + out << " #{sha256}" if sha256 out << "\n" out end + + private + + def sha256 + @checksums.find {|c| c =~ SHA256 } + end end end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 6b066051d8..14f6746331 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -114,7 +114,7 @@ module Bundler @originally_locked_specs = @locked_specs @locked_sources = [] @locked_platforms = [] - @locked_checksums = [] + @locked_checksums = {} end locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb index 4c41285043..863544b1f9 100644 --- a/lib/bundler/endpoint_specification.rb +++ b/lib/bundler/endpoint_specification.rb @@ -104,11 +104,6 @@ module Bundler @remote_specification = spec end - def to_checksum - digest = "sha256-#{checksum}" if checksum - Bundler::Checksum.new(name, version, platform, digest) - end - private def _remote_specification diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb index 2e6d788f9c..ed39511a10 100644 --- a/lib/bundler/gem_helpers.rb +++ b/lib/bundler/gem_helpers.rb @@ -113,5 +113,23 @@ module Bundler same_runtime_deps && same_metadata_deps end module_function :same_deps + + def spec_full_name(name, version, platform) + if platform == Gem::Platform::RUBY + "#{name}-#{version}" + else + "#{name}-#{version}-#{platform}" + end + end + module_function :spec_full_name + + def lock_name(name, version, platform) + if platform == Gem::Platform::RUBY + "#{name} (#{version})" + else + "#{name} (#{version}-#{platform})" + end + end + module_function :lock_name end end diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index b4aadb0b5c..a17c8b90e5 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -20,11 +20,7 @@ module Bundler end def full_name - @full_name ||= if platform == Gem::Platform::RUBY - "#{@name}-#{@version}" - else - "#{@name}-#{@version}-#{platform}" - end + @full_name ||= GemHelpers.spec_full_name(@name, @version, platform) end def ==(other) @@ -61,12 +57,7 @@ module Bundler def to_lock out = String.new - - if platform == Gem::Platform::RUBY - out << " #{name} (#{version})\n" - else - out << " #{name} (#{version}-#{platform})\n" - end + out << " #{GemHelpers.lock_name(name, version, platform)}\n" dependencies.sort_by(&:to_s).uniq.each do |dep| next if dep.type == :development @@ -76,17 +67,18 @@ module Bundler out end - #def materialize_for_checksum - #if @specification - #yield - #else - #materialize_for_installation - - #yield + def materialize_for_checksum(&blk) + # + # See comment about #ruby_platform_materializes_to_ruby_platform? + # If the old lockfile format is present where there is no specific + # platform, then we should skip locking checksums as it is not + # deterministic which platform variant is locked. + # + return unless ruby_platform_materializes_to_ruby_platform? - #@specification = nil - #end - #end + s = materialize_for_installation + yield s if block_given? + end def materialize_for_installation source.local! @@ -134,11 +126,7 @@ module Bundler end def to_s - @to_s ||= if platform == Gem::Platform::RUBY - "#{name} (#{version})" - else - "#{name} (#{version}-#{platform})" - end + @__to_s ||= GemHelpers.lock_name(name, version, platform) end def git_version @@ -146,20 +134,6 @@ module Bundler " #{source.revision[0..6]}" end - def to_checksum - return nil unless @specification - - # - # See comment about #ruby_platform_materializes_to_ruby_platform? - # If the old lockfile format is present where there is no specific - # platform, then we should skip locking checksums as it is not - # deterministic which platform variant is locked. - # - return nil unless ruby_platform_materializes_to_ruby_platform? - - @specification.to_checksum - end - private def use_exact_resolved_specifications? diff --git a/lib/bundler/lockfile_generator.rb b/lib/bundler/lockfile_generator.rb index 11e8e3f103..52b3b411aa 100644 --- a/lib/bundler/lockfile_generator.rb +++ b/lib/bundler/lockfile_generator.rb @@ -68,17 +68,14 @@ module Bundler def add_checksums out << "\nCHECKSUMS\n" - definition.resolve.sort_by(&:full_name).each do |spec| checksum = spec.to_checksum if spec.respond_to?(:to_checksum) - - #if spec.is_a?(LazySpecification) - #spec.materialize_for_checksum do - #checksum ||= spec.to_checksum if spec.respond_to?(:to_checksum) - #end - #end - - checksum ||= definition.locked_checksums.find {|c| c.match_spec?(spec) } + if spec.is_a?(LazySpecification) + spec.materialize_for_checksum do |materialized_spec| + checksum ||= materialized_spec.to_checksum if materialized_spec&.respond_to?(:to_checksum) + end + end + checksum ||= definition.locked_checksums[spec.full_name] out << checksum.to_lock if checksum end diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index fc331a928c..001de06d53 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -66,7 +66,7 @@ module Bundler @sources = [] @dependencies = {} @parse_method = nil - @checksums = [] + @checksums = {} @specs = {} if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) @@ -193,7 +193,8 @@ module Bundler version = Gem::Version.new(version) platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY - @checksums << Bundler::Checksum.new(name, version, platform, checksum) + checksum = Bundler::Checksum.new(name, version, platform, [checksum]) + @checksums[checksum.full_name] = checksum end end diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb index f626a3218e..e8054dbbd5 100644 --- a/lib/bundler/remote_specification.rb +++ b/lib/bundler/remote_specification.rb @@ -93,12 +93,56 @@ module Bundler " #{source.revision[0..6]}" end + # we don't get the checksum from a server like we could with EndpointSpecs + # calculating the checksum from the file on disk still provides some measure of security + # if it changes from install to install, that is cause for concern + def to_checksum + @checksum ||= begin + gem_path = fetch_gem + require "rubygems/package" + package = Gem::Package.new(gem_path) + digest = Bundler::Checksum.digest_from_file_source(package.gem) + digest.hexdigest! + end + + digest = "sha256-#{@checksum}" if @checksum + Bundler::Checksum.new(name, version, platform, [digest]) + end + private def to_ary nil end + def fetch_gem + fetch_platform + + cache_path = download_cache_path || default_cache_path_for_rubygems_dir + gem_path = "#{cache_path}/#{file_name}" + return gem_path if File.exist?(gem_path) + + SharedHelpers.filesystem_access(cache_path) do |p| + FileUtils.mkdir_p(p) + end + + Bundler.rubygems.download_gem(self, remote.uri, cache_path) + + gem_path + end + + def download_cache_path + return unless Bundler.feature_flag.global_gem_cache? + return unless remote + return unless remote.cache_slug + + Bundler.user_cache.join("gems", remote.cache_slug) + end + + def default_cache_path_for_rubygems_dir + "#{Bundler.bundle_path}/cache" + end + def _remote_specification @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform]) @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index 38035a00ac..22e3185b7f 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -120,13 +120,10 @@ module Bundler return true unless checksum return true unless source = @package.instance_variable_get(:@gem) return true unless source.respond_to?(:with_read_io) - digest = source.with_read_io do |io| - digest = SharedHelpers.digest(:SHA256).new - digest << io.read(16_384) until io.eof? - io.rewind - send(checksum_type(checksum), digest) - end - unless digest == checksum + digest = Bundler::Checksum.digest_from_file_source(source) + calculated_checksum = send(checksum_type(checksum), digest) + + unless calculated_checksum == checksum raise SecurityError, <<-MESSAGE Bundler cannot continue installing #{spec.name} (#{spec.version}). The checksum for the downloaded `#{spec.full_name}.gem` does not match \ @@ -143,7 +140,7 @@ module Bundler 2. run `bundle install` (More info: The expected SHA256 checksum was #{checksum.inspect}, but the \ - checksum for the downloaded gem was #{digest.inspect}.) + checksum for the downloaded gem was #{calculated_checksum.inspect}.) MESSAGE end true diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb index 6f4264e561..0ce68b964c 100644 --- a/lib/bundler/stub_specification.rb +++ b/lib/bundler/stub_specification.rb @@ -9,6 +9,7 @@ module Bundler spec end + attr_reader :checksum attr_accessor :stub, :ignored def source=(source) @@ -92,6 +93,16 @@ module Bundler stub.raw_require_paths end + def add_checksum(checksum) + @checksum ||= checksum + end + + def to_checksum + return Bundler::Checksum.new(name, version, platform, ["sha256-#{checksum}"]) if checksum + + _remote_specification&.to_checksum + end + private def _remote_specification diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 6f69ee22ce..8af62cced7 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -761,6 +761,8 @@ class Gem::Specification < Gem::BasicSpecification attr_accessor :specification_version + attr_reader :checksum + def self._all # :nodoc: @@all ||= Gem.loaded_specs.values | stubs.map(&:to_spec) end @@ -2738,4 +2740,22 @@ class Gem::Specification < Gem::BasicSpecification def raw_require_paths # :nodoc: @require_paths end + + def add_checksum(checksum) + @checksum ||= checksum + end + + # if we don't get the checksum from the server + # calculating the checksum from the file on disk still provides some measure of security + # if it changes from install to install, that is cause for concern + def to_checksum + return Bundler::Checksum.new(name, version, platform, ["sha256-#{checksum}"]) if checksum + return Bundler::Checksum.new(name, version, platform) unless File.exist?(cache_file) + + require "rubygems/package" + package = Gem::Package.new(cache_file) + digest = Bundler::Checksum.digest_from_file_source(package.gem) + calculated_checksum = digest.hexdigest! + Bundler::Checksum.new(name, version, platform, ["sha256-#{calculated_checksum}"]) if calculated_checksum + end end diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb index a5d244d3aa..3676ed21c8 100644 --- a/spec/bundler/bundler/definition_spec.rb +++ b/spec/bundler/bundler/definition_spec.rb @@ -168,6 +168,7 @@ RSpec.describe Bundler::Definition do only_java CHECKSUMS + #{checksum_for_repo_gem gem_repo1, "only_java", "1.1", "java"} BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index ff387a5990..4426c484fb 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -11,6 +11,18 @@ RSpec.describe "bundle lock" do gem "foo" G + expected_checksums = construct_checksum_section do |c| + c.repo_gem repo, "actionmailer", "2.3.2" + c.repo_gem repo, "actionpack", "2.3.2" + c.repo_gem repo, "activerecord", "2.3.2" + c.repo_gem repo, "activeresource", "2.3.2" + c.repo_gem repo, "activesupport", "2.3.2" + c.repo_gem repo, "foo", "1.0" + c.repo_gem repo, "rails", "2.3.2" + c.repo_gem repo, "rake", "13.0.1" + c.repo_gem repo, "weakling", "0.0.3" + end + @lockfile = <<~L GEM remote: #{file_uri_for(repo)}/ @@ -43,6 +55,7 @@ RSpec.describe "bundle lock" do weakling CHECKSUMS + #{expected_checksums} BUNDLED WITH #{Bundler::VERSION} @@ -107,6 +120,7 @@ RSpec.describe "bundle lock" do foo CHECKSUMS + #{checksum_for_repo_gem repo, "foo", "1.0"} BUNDLED WITH #{Bundler::VERSION} @@ -501,6 +515,10 @@ RSpec.describe "bundle lock" do DEPENDENCIES nokogiri + CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.12.0"} + #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.12.0", "x86_64-darwin"} + BUNDLED WITH #{Bundler::VERSION} L @@ -521,6 +539,9 @@ RSpec.describe "bundle lock" do DEPENDENCIES nokogiri + CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.12.0", "x86_64-darwin"} + BUNDLED WITH #{Bundler::VERSION} L @@ -590,6 +611,10 @@ RSpec.describe "bundle lock" do mixlib-shellout CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "ffi", "1.9.14", "x86-mingw32"} + #{checksum_for_repo_gem gem_repo4, "gssapi", "1.2.0"} + #{checksum_for_repo_gem gem_repo4, "mixlib-shellout", "2.2.6", "universal-mingw32"} + #{checksum_for_repo_gem gem_repo4, "win32-process", "0.8.3"} BUNDLED WITH #{Bundler::VERSION} @@ -621,6 +646,12 @@ RSpec.describe "bundle lock" do mixlib-shellout CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "ffi", "1.9.14"} + #{checksum_for_repo_gem gem_repo4, "ffi", "1.9.14", "x86-mingw32"} + #{checksum_for_repo_gem gem_repo4, "gssapi", "1.2.0"} + #{checksum_for_repo_gem gem_repo4, "mixlib-shellout", "2.2.6"} + #{checksum_for_repo_gem gem_repo4, "mixlib-shellout", "2.2.6", "universal-mingw32"} + #{checksum_for_repo_gem gem_repo4, "win32-process", "0.8.3"} BUNDLED WITH #{Bundler::VERSION} @@ -701,6 +732,8 @@ RSpec.describe "bundle lock" do libv8 CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-19"} + #{checksum_for_repo_gem gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-20"} BUNDLED WITH #{Bundler::VERSION} @@ -907,14 +940,114 @@ RSpec.describe "bundle lock" do it "does not implicitly update" do bundle "lock" - expect(read_lockfile).to eq(@lockfile) + expected_checksums = construct_checksum_section do |c| + c.repo_gem repo, "actionmailer", "2.3.2" + c.repo_gem repo, "actionpack", "2.3.2" + c.repo_gem repo, "activerecord", "2.3.2" + c.repo_gem repo, "activeresource", "2.3.2" + c.repo_gem repo, "activesupport", "2.3.2" + c.repo_gem repo, "foo", "1.0" + c.repo_gem repo, "rails", "2.3.2" + c.repo_gem repo, "rake", "13.0.1" + c.repo_gem repo, "weakling", "0.0.3" + end + + expected_lockfile = strip_lockfile(<<-L) + GEM + remote: #{file_uri_for(repo)}/ + specs: + actionmailer (2.3.2) + activesupport (= 2.3.2) + actionpack (2.3.2) + activesupport (= 2.3.2) + activerecord (2.3.2) + activesupport (= 2.3.2) + activeresource (2.3.2) + activesupport (= 2.3.2) + activesupport (2.3.2) + foo (1.0) + rails (2.3.2) + actionmailer (= 2.3.2) + actionpack (= 2.3.2) + activerecord (= 2.3.2) + activeresource (= 2.3.2) + rake (= 13.0.1) + rake (13.0.1) + weakling (0.0.3) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + foo + rails + weakling + + CHECKSUMS + #{expected_checksums} + + BUNDLED WITH + #{Bundler::VERSION} + L + + expect(read_lockfile).to eq(expected_lockfile) end it "accounts for changes in the gemfile" do gemfile gemfile.gsub('"foo"', '"foo", "2.0"') bundle "lock" - expect(read_lockfile).to eq(@lockfile.sub("foo (1.0)", "foo (2.0)").sub(/foo$/, "foo (= 2.0)")) + expected_checksums = construct_checksum_section do |c| + c.repo_gem repo, "actionmailer", "2.3.2" + c.repo_gem repo, "actionpack", "2.3.2" + c.repo_gem repo, "activerecord", "2.3.2" + c.repo_gem repo, "activeresource", "2.3.2" + c.repo_gem repo, "activesupport", "2.3.2" + c.repo_gem repo, "foo", "2.0" + c.repo_gem repo, "rails", "2.3.2" + c.repo_gem repo, "rake", "13.0.1" + c.repo_gem repo, "weakling", "0.0.3" + end + + expected_lockfile = strip_lockfile(<<-L) + GEM + remote: #{file_uri_for(repo)}/ + specs: + actionmailer (2.3.2) + activesupport (= 2.3.2) + actionpack (2.3.2) + activesupport (= 2.3.2) + activerecord (2.3.2) + activesupport (= 2.3.2) + activeresource (2.3.2) + activesupport (= 2.3.2) + activesupport (2.3.2) + foo (2.0) + rails (2.3.2) + actionmailer (= 2.3.2) + actionpack (= 2.3.2) + activerecord (= 2.3.2) + activeresource (= 2.3.2) + rake (= 13.0.1) + rake (13.0.1) + weakling (0.0.3) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + foo (= 2.0) + rails + weakling + + CHECKSUMS + #{expected_checksums} + + BUNDLED WITH + #{Bundler::VERSION} + L + + expect(read_lockfile).to eq(expected_lockfile) end end @@ -985,6 +1118,8 @@ RSpec.describe "bundle lock" do debug CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "debug", "1.6.3"} + #{checksum_for_repo_gem gem_repo4, "irb", "1.5.0"} BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index eb578d4dff..cf6a8d5be1 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -291,6 +291,8 @@ RSpec.describe "bundle update" do country_select CHECKSUMS + #{checksum_for_repo_gem(gem_repo4, "countries", "3.1.0")} + #{checksum_for_repo_gem(gem_repo4, "country_select", "5.1.0")} BUNDLED WITH #{Bundler::VERSION} @@ -560,6 +562,7 @@ RSpec.describe "bundle update" do activesupport (~> 6.0.0) CHECKSUMS + #{expected_checksums} BUNDLED WITH #{Bundler::VERSION} @@ -1282,7 +1285,7 @@ RSpec.describe "bundle update --bundler" do G lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2') - excepted_checksum = checksum_for_repo_gem(gem_repo4, "rack", "1.0") + expected_checksum = checksum_for_repo_gem(gem_repo4, "rack", "1.0") FileUtils.rm_r gem_repo4 @@ -1302,7 +1305,7 @@ RSpec.describe "bundle update --bundler" do rack CHECKSUMS - #{excepted_checksum} + #{expected_checksum} BUNDLED WITH #{Bundler::VERSION} @@ -1714,6 +1717,14 @@ RSpec.describe "bundle update conservative" do it "should only change direct dependencies when updating the lockfile with --conservative" do bundle "lock --update --conservative" + expected_checksums = construct_checksum_section do |c| + c.repo_gem gem_repo4, "isolated_dep", "2.0.1" + c.repo_gem gem_repo4, "isolated_owner", "1.0.2" + c.repo_gem gem_repo4, "shared_dep", "5.0.1" + c.repo_gem gem_repo4, "shared_owner_a", "3.0.2" + c.repo_gem gem_repo4, "shared_owner_b", "4.0.2" + end + expect(lockfile).to eq <<~L GEM remote: #{file_uri_for(gem_repo4)}/ @@ -1736,6 +1747,7 @@ RSpec.describe "bundle update conservative" do shared_owner_b CHECKSUMS + #{expected_checksums} BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb index 23f1a05c10..f72726fec1 100644 --- a/spec/bundler/install/gemfile/gemspec_spec.rb +++ b/spec/bundler/install/gemfile/gemspec_spec.rb @@ -451,6 +451,7 @@ RSpec.describe "bundle install from an existing gemspec" do expected_checksums = construct_checksum_section do |c| c.repo_gem gem_repo2, "platform_specific", "1.0" + c.repo_gem gem_repo2, "platform_specific", "1.0", "java" c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32 end @@ -494,6 +495,7 @@ RSpec.describe "bundle install from an existing gemspec" do expected_checksums = construct_checksum_section do |c| c.repo_gem gem_repo2, "platform_specific", "1.0" + c.repo_gem gem_repo2, "platform_specific", "1.0", "java" c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32 end @@ -539,6 +541,7 @@ RSpec.describe "bundle install from an existing gemspec" do expected_checksums = construct_checksum_section do |c| c.repo_gem gem_repo2, "indirect_platform_specific", "1.0" c.repo_gem gem_repo2, "platform_specific", "1.0" + c.repo_gem gem_repo2, "platform_specific", "1.0", "java" c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32 end @@ -718,6 +721,7 @@ RSpec.describe "bundle install from an existing gemspec" do CHECKSUMS activeadmin (2.9.0) + #{checksum_for_repo_gem gem_repo4, "jruby-openssl", "0.10.7", "java"} #{checksum_for_repo_gem gem_repo4, "railties", "6.1.4"} BUNDLED WITH diff --git a/spec/bundler/install/gemfile/install_if_spec.rb b/spec/bundler/install/gemfile/install_if_spec.rb index 441b309afe..96b7f07d16 100644 --- a/spec/bundler/install/gemfile/install_if_spec.rb +++ b/spec/bundler/install/gemfile/install_if_spec.rb @@ -39,7 +39,9 @@ RSpec.describe "bundle install with install_if conditionals" do CHECKSUMS #{checksum_for_repo_gem gem_repo1, "activesupport", "2.3.5"} + #{checksum_for_repo_gem gem_repo1, "foo", "1.0"} #{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"} + #{checksum_for_repo_gem gem_repo1, "thin", "1.0"} BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb index 3992d11458..de474d968e 100644 --- a/spec/bundler/install/gemfile/platform_spec.rb +++ b/spec/bundler/install/gemfile/platform_spec.rb @@ -407,6 +407,7 @@ RSpec.describe "bundle install across platforms" do CHECKSUMS #{checksum_for_repo_gem(gem_repo1, "platform_specific", "1.0")} + #{checksum_for_repo_gem(gem_repo1, "platform_specific", "1.0", "java")} BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 40c4bebdd3..318b4907df 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -1567,6 +1567,11 @@ RSpec.describe "bundle install with gems on multiple sources" do it "upgrades the lockfile correctly" do bundle "lock --update", :artifice => "compact_index" + expected_checksums = construct_checksum_section do |c| + c.repo_gem gem_repo2, "capybara", "2.5.0" + c.repo_gem gem_repo4, "mime-types", "3.0.0" + end + expect(lockfile).to eq <<~L GEM remote: https://gem.repo2/ @@ -1587,6 +1592,7 @@ RSpec.describe "bundle install with gems on multiple sources" do mime-types (~> 3.0)! CHECKSUMS + #{expected_checksums} BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index 6938507dd5..4718d0dec1 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -621,6 +621,10 @@ RSpec.describe "bundle install with specific platforms" do nokogiri sorbet-static + CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.13.0", "x86_64-darwin"} + #{checksum_for_repo_gem gem_repo4, "sorbet-static", "0.5.10601", "x86_64-darwin"} + BUNDLED WITH #{Bundler::VERSION} L @@ -822,6 +826,10 @@ RSpec.describe "bundle install with specific platforms" do DEPENDENCIES sorbet-static (= 0.5.10549) + CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-20"} + #{checksum_for_repo_gem gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-21"} + BUNDLED WITH #{Bundler::VERSION} L @@ -868,7 +876,29 @@ RSpec.describe "bundle install with specific platforms" do bundle "lock --update" - expect(lockfile).to eq(original_lockfile) + updated_lockfile = <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + nokogiri (1.13.8) + nokogiri (1.13.8-#{Gem::Platform.local}) + + PLATFORMS + #{lockfile_platforms_for([specific_local_platform, "ruby"])} + + DEPENDENCIES + nokogiri + tzinfo (~> 1.2) + + CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.13.8"} + #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.13.8", "arm64-darwin-22"} + + BUNDLED WITH + #{Bundler::VERSION} + L + + expect(lockfile).to eq(updated_lockfile) end it "does not remove ruby when adding a new gem to the Gemfile" do @@ -1008,6 +1038,9 @@ RSpec.describe "bundle install with specific platforms" do DEPENDENCIES nokogiri (= 1.14.0) + CHECKSUMS + #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.14.0"} + BUNDLED WITH #{Bundler::VERSION} L diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb index 930e3c4791..bc84e25417 100644 --- a/spec/bundler/install/yanked_spec.rb +++ b/spec/bundler/install/yanked_spec.rb @@ -161,6 +161,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking foo CHECKSUMS + #{checksum_for_repo_gem(gem_repo4, "bar", "2.0.0")} BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb index d0af8b1c1c..31d93a559f 100644 --- a/spec/bundler/runtime/platform_spec.rb +++ b/spec/bundler/runtime/platform_spec.rb @@ -92,7 +92,8 @@ RSpec.describe "Bundler.setup with multi platform stuff" do nokogiri (~> 1.11) CHECKSUMS - nokogiri (1.11.1) + #{checksum_for_repo_gem gem_repo4, "mini_portile2", "2.5.0"} + #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.11.1"} #{checksum_for_repo_gem gem_repo4, "nokogiri", "1.11.1", Bundler.local_platform} #{checksum_for_repo_gem gem_repo4, "racca", "1.5.2"} diff --git a/spec/bundler/support/checksums.rb b/spec/bundler/support/checksums.rb index 3594b93518..93e27402c7 100644 --- a/spec/bundler/support/checksums.rb +++ b/spec/bundler/support/checksums.rb @@ -15,7 +15,7 @@ module Spec end checksum = sha256_checksum(gem_file) - @checksums << Bundler::Checksum.new(gem_name, gem_version, platform, checksum) + @checksums << Bundler::Checksum.new(gem_name, gem_version, platform, [checksum]) end def to_lock |