[rubygems/rubygems] Use the server checksum, then calculate from gem on disk if possible

1. Use the checksum provided by the server if provided: provides security
knowing if the gem you downloaded matches the gem on the server

2. Calculate the checksum from the gem on disk: provides security knowing
if the gem has changed between installs

3. In some cases, neither is possible in which case we don't put anything
in the checksum and we maintain functionality as it is today

Add the checksums to specs in the index if we already have them

Prior to checksums, we didn't lose any information when overwriting specs
in the index with stubs. But now when we overwrite EndpointSpecifications
or RemoteSpecifications with more generic specs, we could lose checksum
info. This manually sets checksum info so we keep it in the index.

https://github.com/rubygems/rubygems/commit/de00a4f153
This commit is contained in:
Mercedes Bernard 2023-02-10 13:34:30 -06:00 committed by Hiroshi SHIBATA
parent ad08674d8d
commit 69d7e9a12e
No known key found for this signature in database
GPG Key ID: F9CF13417264FAC2
22 changed files with 355 additions and 87 deletions

View File

@ -2,22 +2,37 @@
module Bundler module Bundler
class Checksum class Checksum
attr_reader :name, :version, :platform attr_reader :name, :version, :platform, :checksums
attr_accessor :checksum
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 @name = name
@version = version @version = version
@platform = platform || Gem::Platform::RUBY @platform = platform || Gem::Platform::RUBY
@checksum = checksum @checksums = checksums
if @checksum && @checksum !~ SHA256 # can expand this validation when we support more hashing algos later
raise ArgumentError, "invalid checksum (#{@checksum})" if @checksums.any? && @checksums.all? {|c| c !~ SHA256 }
raise ArgumentError, "invalid checksums (#{@checksums})"
end end
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) def match_spec?(spec)
name == spec.name && name == spec.name &&
version == spec.version && version == spec.version &&
@ -26,17 +41,17 @@ module Bundler
def to_lock def to_lock
out = String.new out = String.new
out << " #{GemHelpers.lock_name(name, version, platform)}"
if platform == Gem::Platform::RUBY out << " #{sha256}" if sha256
out << " #{name} (#{version})"
else
out << " #{name} (#{version}-#{platform})"
end
out << " #{checksum}" if checksum
out << "\n" out << "\n"
out out
end end
private
def sha256
@checksums.find {|c| c =~ SHA256 }
end
end end
end end

View File

@ -114,7 +114,7 @@ module Bundler
@originally_locked_specs = @locked_specs @originally_locked_specs = @locked_specs
@locked_sources = [] @locked_sources = []
@locked_platforms = [] @locked_platforms = []
@locked_checksums = [] @locked_checksums = {}
end end
locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }

View File

@ -104,11 +104,6 @@ module Bundler
@remote_specification = spec @remote_specification = spec
end end
def to_checksum
digest = "sha256-#{checksum}" if checksum
Bundler::Checksum.new(name, version, platform, digest)
end
private private
def _remote_specification def _remote_specification

View File

@ -113,5 +113,23 @@ module Bundler
same_runtime_deps && same_metadata_deps same_runtime_deps && same_metadata_deps
end end
module_function :same_deps 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
end end

View File

@ -20,11 +20,7 @@ module Bundler
end end
def full_name def full_name
@full_name ||= if platform == Gem::Platform::RUBY @full_name ||= GemHelpers.spec_full_name(@name, @version, platform)
"#{@name}-#{@version}"
else
"#{@name}-#{@version}-#{platform}"
end
end end
def ==(other) def ==(other)
@ -61,12 +57,7 @@ module Bundler
def to_lock def to_lock
out = String.new out = String.new
out << " #{GemHelpers.lock_name(name, version, platform)}\n"
if platform == Gem::Platform::RUBY
out << " #{name} (#{version})\n"
else
out << " #{name} (#{version}-#{platform})\n"
end
dependencies.sort_by(&:to_s).uniq.each do |dep| dependencies.sort_by(&:to_s).uniq.each do |dep|
next if dep.type == :development next if dep.type == :development
@ -76,17 +67,18 @@ module Bundler
out out
end end
#def materialize_for_checksum def materialize_for_checksum(&blk)
#if @specification #
#yield # See comment about #ruby_platform_materializes_to_ruby_platform?
#else # If the old lockfile format is present where there is no specific
#materialize_for_installation # 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?
#yield s = materialize_for_installation
yield s if block_given?
#@specification = nil end
#end
#end
def materialize_for_installation def materialize_for_installation
source.local! source.local!
@ -134,11 +126,7 @@ module Bundler
end end
def to_s def to_s
@to_s ||= if platform == Gem::Platform::RUBY @__to_s ||= GemHelpers.lock_name(name, version, platform)
"#{name} (#{version})"
else
"#{name} (#{version}-#{platform})"
end
end end
def git_version def git_version
@ -146,20 +134,6 @@ module Bundler
" #{source.revision[0..6]}" " #{source.revision[0..6]}"
end 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 private
def use_exact_resolved_specifications? def use_exact_resolved_specifications?

View File

@ -68,17 +68,14 @@ module Bundler
def add_checksums def add_checksums
out << "\nCHECKSUMS\n" out << "\nCHECKSUMS\n"
definition.resolve.sort_by(&:full_name).each do |spec| definition.resolve.sort_by(&:full_name).each do |spec|
checksum = spec.to_checksum if spec.respond_to?(:to_checksum) checksum = spec.to_checksum if spec.respond_to?(:to_checksum)
if spec.is_a?(LazySpecification)
#if spec.is_a?(LazySpecification) spec.materialize_for_checksum do |materialized_spec|
#spec.materialize_for_checksum do checksum ||= materialized_spec.to_checksum if materialized_spec&.respond_to?(:to_checksum)
#checksum ||= spec.to_checksum if spec.respond_to?(:to_checksum) end
#end end
#end checksum ||= definition.locked_checksums[spec.full_name]
checksum ||= definition.locked_checksums.find {|c| c.match_spec?(spec) }
out << checksum.to_lock if checksum out << checksum.to_lock if checksum
end end

View File

@ -66,7 +66,7 @@ module Bundler
@sources = [] @sources = []
@dependencies = {} @dependencies = {}
@parse_method = nil @parse_method = nil
@checksums = [] @checksums = {}
@specs = {} @specs = {}
if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
@ -193,7 +193,8 @@ module Bundler
version = Gem::Version.new(version) version = Gem::Version.new(version)
platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY 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
end end

View File

@ -93,12 +93,56 @@ module Bundler
" #{source.revision[0..6]}" " #{source.revision[0..6]}"
end 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 private
def to_ary def to_ary
nil nil
end 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 def _remote_specification
@_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform]) @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform])
@_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \

View File

@ -120,13 +120,10 @@ module Bundler
return true unless checksum return true unless checksum
return true unless source = @package.instance_variable_get(:@gem) return true unless source = @package.instance_variable_get(:@gem)
return true unless source.respond_to?(:with_read_io) return true unless source.respond_to?(:with_read_io)
digest = source.with_read_io do |io| digest = Bundler::Checksum.digest_from_file_source(source)
digest = SharedHelpers.digest(:SHA256).new calculated_checksum = send(checksum_type(checksum), digest)
digest << io.read(16_384) until io.eof?
io.rewind unless calculated_checksum == checksum
send(checksum_type(checksum), digest)
end
unless digest == checksum
raise SecurityError, <<-MESSAGE raise SecurityError, <<-MESSAGE
Bundler cannot continue installing #{spec.name} (#{spec.version}). Bundler cannot continue installing #{spec.name} (#{spec.version}).
The checksum for the downloaded `#{spec.full_name}.gem` does not match \ The checksum for the downloaded `#{spec.full_name}.gem` does not match \
@ -143,7 +140,7 @@ module Bundler
2. run `bundle install` 2. run `bundle install`
(More info: The expected SHA256 checksum was #{checksum.inspect}, but the \ (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 MESSAGE
end end
true true

View File

@ -9,6 +9,7 @@ module Bundler
spec spec
end end
attr_reader :checksum
attr_accessor :stub, :ignored attr_accessor :stub, :ignored
def source=(source) def source=(source)
@ -92,6 +93,16 @@ module Bundler
stub.raw_require_paths stub.raw_require_paths
end 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 private
def _remote_specification def _remote_specification

View File

@ -761,6 +761,8 @@ class Gem::Specification < Gem::BasicSpecification
attr_accessor :specification_version attr_accessor :specification_version
attr_reader :checksum
def self._all # :nodoc: def self._all # :nodoc:
@@all ||= Gem.loaded_specs.values | stubs.map(&:to_spec) @@all ||= Gem.loaded_specs.values | stubs.map(&:to_spec)
end end
@ -2738,4 +2740,22 @@ class Gem::Specification < Gem::BasicSpecification
def raw_require_paths # :nodoc: def raw_require_paths # :nodoc:
@require_paths @require_paths
end 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 end

View File

@ -168,6 +168,7 @@ RSpec.describe Bundler::Definition do
only_java only_java
CHECKSUMS CHECKSUMS
#{checksum_for_repo_gem gem_repo1, "only_java", "1.1", "java"}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}

View File

@ -11,6 +11,18 @@ RSpec.describe "bundle lock" do
gem "foo" gem "foo"
G 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 @lockfile = <<~L
GEM GEM
remote: #{file_uri_for(repo)}/ remote: #{file_uri_for(repo)}/
@ -43,6 +55,7 @@ RSpec.describe "bundle lock" do
weakling weakling
CHECKSUMS CHECKSUMS
#{expected_checksums}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
@ -107,6 +120,7 @@ RSpec.describe "bundle lock" do
foo foo
CHECKSUMS CHECKSUMS
#{checksum_for_repo_gem repo, "foo", "1.0"}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
@ -501,6 +515,10 @@ RSpec.describe "bundle lock" do
DEPENDENCIES DEPENDENCIES
nokogiri 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 BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
L L
@ -521,6 +539,9 @@ RSpec.describe "bundle lock" do
DEPENDENCIES DEPENDENCIES
nokogiri nokogiri
CHECKSUMS
#{checksum_for_repo_gem gem_repo4, "nokogiri", "1.12.0", "x86_64-darwin"}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
L L
@ -590,6 +611,10 @@ RSpec.describe "bundle lock" do
mixlib-shellout mixlib-shellout
CHECKSUMS 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 BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
@ -621,6 +646,12 @@ RSpec.describe "bundle lock" do
mixlib-shellout mixlib-shellout
CHECKSUMS 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 BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
@ -701,6 +732,8 @@ RSpec.describe "bundle lock" do
libv8 libv8
CHECKSUMS 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 BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
@ -907,14 +940,114 @@ RSpec.describe "bundle lock" do
it "does not implicitly update" do it "does not implicitly update" do
bundle "lock" 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 end
it "accounts for changes in the gemfile" do it "accounts for changes in the gemfile" do
gemfile gemfile.gsub('"foo"', '"foo", "2.0"') gemfile gemfile.gsub('"foo"', '"foo", "2.0"')
bundle "lock" 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
end end
@ -985,6 +1118,8 @@ RSpec.describe "bundle lock" do
debug debug
CHECKSUMS CHECKSUMS
#{checksum_for_repo_gem gem_repo4, "debug", "1.6.3"}
#{checksum_for_repo_gem gem_repo4, "irb", "1.5.0"}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}

View File

@ -291,6 +291,8 @@ RSpec.describe "bundle update" do
country_select country_select
CHECKSUMS CHECKSUMS
#{checksum_for_repo_gem(gem_repo4, "countries", "3.1.0")}
#{checksum_for_repo_gem(gem_repo4, "country_select", "5.1.0")}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
@ -560,6 +562,7 @@ RSpec.describe "bundle update" do
activesupport (~> 6.0.0) activesupport (~> 6.0.0)
CHECKSUMS CHECKSUMS
#{expected_checksums}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
@ -1282,7 +1285,7 @@ RSpec.describe "bundle update --bundler" do
G G
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2') 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 FileUtils.rm_r gem_repo4
@ -1302,7 +1305,7 @@ RSpec.describe "bundle update --bundler" do
rack rack
CHECKSUMS CHECKSUMS
#{excepted_checksum} #{expected_checksum}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{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 it "should only change direct dependencies when updating the lockfile with --conservative" do
bundle "lock --update --conservative" 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 expect(lockfile).to eq <<~L
GEM GEM
remote: #{file_uri_for(gem_repo4)}/ remote: #{file_uri_for(gem_repo4)}/
@ -1736,6 +1747,7 @@ RSpec.describe "bundle update conservative" do
shared_owner_b shared_owner_b
CHECKSUMS CHECKSUMS
#{expected_checksums}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}

View File

@ -451,6 +451,7 @@ RSpec.describe "bundle install from an existing gemspec" do
expected_checksums = construct_checksum_section do |c| 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"
c.repo_gem gem_repo2, "platform_specific", "1.0", "java"
c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32 c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32
end end
@ -494,6 +495,7 @@ RSpec.describe "bundle install from an existing gemspec" do
expected_checksums = construct_checksum_section do |c| 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"
c.repo_gem gem_repo2, "platform_specific", "1.0", "java"
c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32 c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32
end end
@ -539,6 +541,7 @@ RSpec.describe "bundle install from an existing gemspec" do
expected_checksums = construct_checksum_section do |c| expected_checksums = construct_checksum_section do |c|
c.repo_gem gem_repo2, "indirect_platform_specific", "1.0" 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"
c.repo_gem gem_repo2, "platform_specific", "1.0", "java"
c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32 c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32
end end
@ -718,6 +721,7 @@ RSpec.describe "bundle install from an existing gemspec" do
CHECKSUMS CHECKSUMS
activeadmin (2.9.0) 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"} #{checksum_for_repo_gem gem_repo4, "railties", "6.1.4"}
BUNDLED WITH BUNDLED WITH

View File

@ -39,7 +39,9 @@ RSpec.describe "bundle install with install_if conditionals" do
CHECKSUMS CHECKSUMS
#{checksum_for_repo_gem gem_repo1, "activesupport", "2.3.5"} #{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, "rack", "1.0.0"}
#{checksum_for_repo_gem gem_repo1, "thin", "1.0"}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}

View File

@ -407,6 +407,7 @@ RSpec.describe "bundle install across platforms" do
CHECKSUMS CHECKSUMS
#{checksum_for_repo_gem(gem_repo1, "platform_specific", "1.0")} #{checksum_for_repo_gem(gem_repo1, "platform_specific", "1.0")}
#{checksum_for_repo_gem(gem_repo1, "platform_specific", "1.0", "java")}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}

View File

@ -1567,6 +1567,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "upgrades the lockfile correctly" do it "upgrades the lockfile correctly" do
bundle "lock --update", :artifice => "compact_index" 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 expect(lockfile).to eq <<~L
GEM GEM
remote: https://gem.repo2/ remote: https://gem.repo2/
@ -1587,6 +1592,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (~> 3.0)! mime-types (~> 3.0)!
CHECKSUMS CHECKSUMS
#{expected_checksums}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}

View File

@ -621,6 +621,10 @@ RSpec.describe "bundle install with specific platforms" do
nokogiri nokogiri
sorbet-static 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 BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
L L
@ -822,6 +826,10 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES DEPENDENCIES
sorbet-static (= 0.5.10549) 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 BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
L L
@ -868,7 +876,29 @@ RSpec.describe "bundle install with specific platforms" do
bundle "lock --update" 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 end
it "does not remove ruby when adding a new gem to the Gemfile" do 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 DEPENDENCIES
nokogiri (= 1.14.0) nokogiri (= 1.14.0)
CHECKSUMS
#{checksum_for_repo_gem gem_repo4, "nokogiri", "1.14.0"}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}
L L

View File

@ -161,6 +161,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
foo foo
CHECKSUMS CHECKSUMS
#{checksum_for_repo_gem(gem_repo4, "bar", "2.0.0")}
BUNDLED WITH BUNDLED WITH
#{Bundler::VERSION} #{Bundler::VERSION}

View File

@ -92,7 +92,8 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri (~> 1.11) nokogiri (~> 1.11)
CHECKSUMS 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, "nokogiri", "1.11.1", Bundler.local_platform}
#{checksum_for_repo_gem gem_repo4, "racca", "1.5.2"} #{checksum_for_repo_gem gem_repo4, "racca", "1.5.2"}

View File

@ -15,7 +15,7 @@ module Spec
end end
checksum = sha256_checksum(gem_file) 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 end
def to_lock def to_lock