diff options
Diffstat (limited to 'lib/bundler')
-rw-r--r-- | lib/bundler/checksum.rb | 218 | ||||
-rw-r--r-- | lib/bundler/definition.rb | 8 | ||||
-rw-r--r-- | lib/bundler/endpoint_specification.rb | 12 | ||||
-rw-r--r-- | lib/bundler/fetcher.rb | 13 | ||||
-rw-r--r-- | lib/bundler/lazy_specification.rb | 15 | ||||
-rw-r--r-- | lib/bundler/lockfile_generator.rb | 13 | ||||
-rw-r--r-- | lib/bundler/lockfile_parser.rb | 80 | ||||
-rw-r--r-- | lib/bundler/plugin/api/source.rb | 3 | ||||
-rw-r--r-- | lib/bundler/remote_specification.rb | 44 | ||||
-rw-r--r-- | lib/bundler/rubygems_gem_installer.rb | 61 | ||||
-rw-r--r-- | lib/bundler/source.rb | 2 | ||||
-rw-r--r-- | lib/bundler/source/path.rb | 1 | ||||
-rw-r--r-- | lib/bundler/source/rubygems.rb | 3 | ||||
-rw-r--r-- | lib/bundler/stub_specification.rb | 10 |
14 files changed, 341 insertions, 142 deletions
diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb index 0b618d5033..3b03935b57 100644 --- a/lib/bundler/checksum.rb +++ b/lib/bundler/checksum.rb @@ -2,31 +2,194 @@ module Bundler class Checksum + class Store + attr_reader :store + protected :store + + def initialize + @store = {} + end + + def initialize_copy(o) + @store = {} + o.store.each do |k, v| + @store[k] = v.dup + end + end + + def [](spec) + sums = @store[spec.full_name] + + Checksum.new(spec.name, spec.version, spec.platform, sums&.transform_values(&:digest)) + end + + def register(spec, checksums) + register_full_name(spec.full_name, checksums) + end + + def register_triple(name, version, platform, checksums) + register_full_name(GemHelpers.spec_full_name(name, version, platform), checksums) + end + + def delete_full_name(full_name) + @store.delete(full_name) + end + + def register_full_name(full_name, checksums) + sums = (@store[full_name] ||= {}) + + checksums.each do |checksum| + algo = checksum.algo + if multi = sums[algo] + multi.merge(checksum) + else + sums[algo] = Multi.new [checksum] + end + end + rescue SecurityError => e + raise e.exception(<<~MESSAGE) + Bundler found multiple different checksums for #{full_name}. + This means that there are multiple different `#{full_name}.gem` files. + This is a potential security issue, since Bundler could be attempting \ + to install a different gem than what you expect. + + #{e.message} + To resolve this issue: + 1. delete any downloaded gems referenced above + 2. run `bundle install` + + If you are sure that the new checksum is correct, you can \ + remove the `#{full_name}` entry under the lockfile `CHECKSUMS` \ + section and rerun `bundle install`. + + If you wish to continue installing the downloaded gem, and are certain it does not pose a \ + security issue despite the mismatching checksum, do the following: + 1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification + 2. run `bundle install` + MESSAGE + end + + def use(other) + other.store.each do |k, v| + register_full_name k, v.values + end + end + end + + class Single + attr_reader :algo, :digest, :source + def initialize(algo, digest, source) + @algo = algo + @digest = digest + @source = source + end + + def ==(other) + other.is_a?(Single) && other.digest == digest && other.algo == algo && source == other.source + end + + def hash + digest.hash + end + + alias_method :eql?, :== + + def to_s + "#{algo}-#{digest} (from #{source})" + end + end + + class Multi + attr_reader :algo, :digest, :checksums + protected :checksums + + def initialize(checksums) + @checksums = checksums + + unless checksums && checksums.size > 0 + raise ArgumentError, "must provide at least one checksum" + end + + first = checksums.first + @algo = first.algo + @digest = first.digest + end + + def initialize_copy(o) + @checksums = o.checksums.dup + @algo = o.algo + @digest = o.digest + end + + def merge(other) + raise ArgumentError, "cannot merge checksums of different algorithms" unless algo == other.algo + unless digest == other.digest + raise SecurityError, <<~MESSAGE + #{other} + #{self} from: + * #{sources.join("\n* ")} + MESSAGE + end + + case other + when Single + @checksums << other + when Multi + @checksums.concat(other.checksums) + else + raise ArgumentError + end + @checksums.uniq! + + self + end + + def sources + @checksums.map(&:source) + end + + def to_s + "#{algo}-#{digest}" + end + end + attr_reader :name, :version, :platform, :checksums SHA256 = %r{\Asha256-([a-z0-9]{64}|[A-Za-z0-9+\/=]{44})\z}.freeze + private_constant :SHA256 - def initialize(name, version, platform, checksums = []) + def initialize(name, version, platform, checksums = {}) @name = name @version = version @platform = platform || Gem::Platform::RUBY - @checksums = checksums + @checksums = checksums || {} # can expand this validation when we support more hashing algos later - if @checksums.any? && @checksums.all? {|c| c !~ SHA256 } + if [email protected]_a?(::Hash) || (@checksums.any? && [email protected]?("sha256")) + raise ArgumentError, "invalid checksums (#{@checksums.inspect})" + end + if @checksums.any? {|_, checksum| !checksum.is_a?(String) } raise ArgumentError, "invalid checksums (#{@checksums})" end end - def self.digest_from_file_source(file_source) + def self.digests_from_file_source(file_source, digest_algorithms: %w[sha256]) raise ArgumentError, "not a valid file source: #{file_source}" unless file_source.respond_to?(:with_read_io) + digests = digest_algorithms.map do |digest_algorithm| + [digest_algorithm.to_s, Bundler::SharedHelpers.digest(digest_algorithm.upcase).new] + end.to_h + file_source.with_read_io do |io| - digest = Bundler::SharedHelpers.digest(:SHA256).new - digest << io.read(16_384) until io.eof? + until io.eof? + block = io.read(16_384) + digests.each_value {|digest| digest << block } + end + io.rewind - digest end + + digests end def full_name @@ -42,12 +205,51 @@ module Bundler def to_lock out = String.new out << " #{GemHelpers.lock_name(name, version, platform)}" - out << " #{sha256}" if sha256 + checksums.sort_by(&:first).each_with_index do |(algo, checksum), idx| + out << (idx.zero? ? " " : ",") + out << algo << "-" << checksum + end out << "\n" out end + def match?(other) + return false unless match_spec?(other) + match_digests?(other.checksums) + end + + def match_digests?(digests) + return true if checksums.empty? && digests.empty? + + common_algos = checksums.keys & digests.keys + return true if common_algos.empty? + + common_algos.all? do |algo| + checksums[algo] == digests[algo] + end + end + + def merge!(other) + raise ArgumentError, "can't merge checksums for different specs" unless match_spec?(other) + + merge_digests!(other.checksums) + end + + def merge_digests!(digests) + if digests.any? {|_, checksum| !checksum.is_a?(String) } + raise ArgumentError, "invalid checksums (#{digests})" + end + @checksums = @checksums.merge(digests) do |algo, ours, theirs| + if ours != theirs + raise ArgumentError, "Digest mismatch for #{algo}:\n\t* #{ours.inspect}\n\t* #{theirs.inspect}" + end + ours + end + + self + end + private def sha256 diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 14f6746331..26e3126d84 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -15,7 +15,6 @@ module Bundler :dependencies, :locked_deps, :locked_gems, - :locked_checksums, :platforms, :ruby_version, :lockfile, @@ -93,7 +92,6 @@ module Bundler @locked_bundler_version = @locked_gems.bundler_version @locked_ruby_version = @locked_gems.ruby_version @originally_locked_specs = SpecSet.new(@locked_gems.specs) - @locked_checksums = @locked_gems.checksums if unlock != true @locked_deps = @locked_gems.dependencies @@ -114,7 +112,6 @@ module Bundler @originally_locked_specs = @locked_specs @locked_sources = [] @locked_platforms = [] - @locked_checksums = {} end locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } @@ -753,6 +750,11 @@ module Bundler changes = sources.replace_sources!(@locked_sources) sources.all_sources.each do |source| + # has to be done separately, because we want to keep the locked checksum + # store for a source, even when doing a full update + if @locked_gems && locked_source = @locked_gems.sources.find {|s| s == source } + source.checksum_store&.use(locked_source.checksum_store) + end # If the source is unlockable and the current command allows an unlock of # the source (for example, you are doing a `bundle update <foo>` of a git-pinned # gem), unlock it. For git sources, this means to unlock the revision, which diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb index 863544b1f9..943e33be94 100644 --- a/lib/bundler/endpoint_specification.rb +++ b/lib/bundler/endpoint_specification.rb @@ -125,7 +125,17 @@ module Bundler next unless v case k.to_s when "checksum" - @checksum = v.last + next if Bundler.settings[:disable_checksum_validation] + digest = v.last + if digest.length == 64 + # nothing to do, it's a hexdigest + elsif digest.length == 44 + # transform the bytes from base64 to hex + digest = digest.unpack("m0").first.unpack("H*").first + else + raise ArgumentError, "The given checksum for #{full_name} (#{digest.inspect}) is not a valid SHA256 hexdigest nor base64digest" + end + @checksum = Checksum::Single.new("sha256", digest, "API response from #{@spec_fetcher.uri}") when "rubygems" @required_rubygems_version = Gem::Requirement.new(v) when "ruby" diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb index 5c1eac415e..08d1ee3437 100644 --- a/lib/bundler/fetcher.rb +++ b/lib/bundler/fetcher.rb @@ -81,7 +81,7 @@ module Bundler :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity, :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze FAIL_ERRORS = begin - fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError] + fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError] fail_errors << Gem::Requirement::BadRequirementError fail_errors.concat(NET_ERRORS.map {|e| Net.const_get(e) }) end.freeze @@ -139,7 +139,16 @@ module Bundler fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata| spec = if dependencies - EndpointSpecification.new(name, version, platform, self, dependencies, metadata) + EndpointSpecification.new(name, version, platform, self, dependencies, metadata).tap do |es| + unless index.local_search(es).empty? + # Duplicate spec.full_names, different spec.original_names + # index#<< ensures that the last one added wins, so if we're overriding + # here, make sure to also override the checksum, otherwise downloading the + # specs (even if that version is completely unused) will cause a SecurityError + source.checksum_store.delete_full_name(es.full_name) + end + source.checksum_store.register(es, [es.checksum]) if source && es.checksum + end else RemoteSpecification.new(name, version, platform, self) end diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index a17c8b90e5..2d084e462f 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -67,19 +67,6 @@ module Bundler out end - 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? - - s = materialize_for_installation - yield s if block_given? - end - def materialize_for_installation source.local! @@ -126,7 +113,7 @@ module Bundler end def to_s - @__to_s ||= GemHelpers.lock_name(name, version, platform) + @to_s ||= GemHelpers.lock_name(name, version, platform) end def git_version diff --git a/lib/bundler/lockfile_generator.rb b/lib/bundler/lockfile_generator.rb index 52b3b411aa..4d2c2c2a86 100644 --- a/lib/bundler/lockfile_generator.rb +++ b/lib/bundler/lockfile_generator.rb @@ -68,16 +68,11 @@ 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 |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 + empty_store = Checksum::Store.new + + definition.resolve.sort_by(&:full_name).each do |spec| + out << (spec.source.checksum_store || empty_store)[spec].to_lock end end diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index 001de06d53..43d544fd32 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -2,6 +2,28 @@ module Bundler class LockfileParser + class Position + attr_reader :line, :column + def initialize(line, column) + @line = line + @column = column + end + + def advance!(string) + lines = string.count("\n") + if lines > 0 + @line += lines + @column = string.length - string.rindex("\n") + else + @column += string.length + end + end + + def to_s + "#{line}:#{column}" + end + end + attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version, :checksums BUNDLED = "BUNDLED WITH" @@ -22,7 +44,7 @@ module Bundler Gem::Version.create("1.10") => [BUNDLED].freeze, Gem::Version.create("1.12") => [RUBY].freeze, Gem::Version.create("1.13") => [PLUGIN].freeze, - Gem::Version.create("2.4.0") => [CHECKSUMS].freeze, + Gem::Version.create("2.5.0") => [CHECKSUMS].freeze, }.freeze KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten!.freeze @@ -66,15 +88,20 @@ module Bundler @sources = [] @dependencies = {} @parse_method = nil - @checksums = {} @specs = {} + @lockfile_path = begin + SharedHelpers.relative_lockfile_path + rescue GemfileNotFound + "Gemfile.lock" + end + @pos = Position.new(1, 1) if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) - raise LockfileError, "Your lockfile contains merge conflicts.\n" \ - "Run `git checkout HEAD -- #{SharedHelpers.relative_lockfile_path}` first to get a clean lock." + raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \ + "Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock." end - lockfile.split(/(?:\r?\n)+/) do |line| + lockfile.split(/((?:\r?\n)+)/).each_slice(2) do |line, whitespace| if SOURCE.include?(line) @parse_method = :parse_source parse_source(line) @@ -93,12 +120,15 @@ module Bundler elsif @parse_method send(@parse_method, line) end + @pos.advance!(line) + @pos.advance!(whitespace) end @specs = @specs.values.sort_by!(&:full_name) rescue ArgumentError => e Bundler.ui.debug(e) - raise LockfileError, "Your lockfile is unreadable. Run `rm #{SharedHelpers.relative_lockfile_path}` " \ - "and then `bundle install` to generate a new lockfile." + raise LockfileError, "Your lockfile is unreadable. Run `rm #{@lockfile_path}` " \ + "and then `bundle install` to generate a new lockfile. The error occurred while " \ + "evaluating #{@lockfile_path}:#{@pos}" end def may_include_redundant_platform_specific_gems? @@ -149,7 +179,7 @@ module Bundler (?:#{space}\(([^-]*) # Space, followed by version (?:-(.*))?\))? # Optional platform (!)? # Optional pinned marker - (?:#{space}(.*))? # Optional checksum + (?:#{space}([^ ]+))? # Optional checksum $ # Line end /xo.freeze @@ -183,19 +213,31 @@ module Bundler end def parse_checksum(line) - if line =~ NAME_VERSION - spaces = $1 - return unless spaces.size == 2 - name = $2 - version = $3 - platform = $4 - checksum = $6 + return unless line =~ NAME_VERSION - version = Gem::Version.new(version) - platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY - checksum = Bundler::Checksum.new(name, version, platform, [checksum]) - @checksums[checksum.full_name] = checksum + spaces = $1 + return unless spaces.size == 2 + name = $2 + version = $3 + platform = $4 + checksums = $6 + return unless checksums + + version = Gem::Version.new(version) + platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY + source = "#{@lockfile_path}:#{@pos} in the CHECKSUMS lockfile section" + checksums = checksums.split(",").map do |c| + algo, digest = c.split("-", 2) + Checksum::Single.new(algo, digest, source) end + + full_name = GemHelpers.spec_full_name(name, version, platform) + + # Don't raise exception if there's a checksum for a gem that's not in the lockfile, + # we prefer to heal invalid lockfiles + return unless spec = @specs[full_name] + + spec.source.checksum_store.register_full_name(full_name, checksums) end def parse_spec(line) diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb index 67c45bd204..57d4eb64ad 100644 --- a/lib/bundler/plugin/api/source.rb +++ b/lib/bundler/plugin/api/source.rb @@ -39,7 +39,7 @@ module Bundler # is present to be compatible with `Definition` and is used by # rubygems source. module Source - attr_reader :uri, :options, :name + attr_reader :uri, :options, :name, :checksum_store attr_accessor :dependency_names def initialize(opts) @@ -48,6 +48,7 @@ module Bundler @uri = opts["uri"] @type = opts["type"] @name = opts["name"] || "#{@type} at #{@uri}" + @checksum_store = Checksum::Store.new end # This is used by the default `spec` method to constructs the diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb index e8054dbbd5..f626a3218e 100644 --- a/lib/bundler/remote_specification.rb +++ b/lib/bundler/remote_specification.rb @@ -93,56 +93,12 @@ 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 22e3185b7f..0a289c416f 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -61,7 +61,7 @@ module Bundler end def pre_install_checks - super && validate_bundler_checksum(options[:bundler_expected_checksum]) + super && validate_bundler_checksum(options[:bundler_checksum_store]) end def build_extensions @@ -115,55 +115,56 @@ module Bundler raise DirectoryRemovalError.new(e, "Could not delete previous installation of `#{dir}`") end - def validate_bundler_checksum(checksum) + def validate_bundler_checksum(checksum_store) return true if Bundler.settings[:disable_checksum_validation] - return true unless checksum + return true unless source = @package.instance_variable_get(:@gem) return true unless source.respond_to?(:with_read_io) - digest = Bundler::Checksum.digest_from_file_source(source) - calculated_checksum = send(checksum_type(checksum), digest) + digests = Bundler::Checksum.digests_from_file_source(source).transform_values(&:hexdigest!) + + checksum = checksum_store[spec] + unless checksum.match_digests?(digests) + expected = checksum_store.send(:store)[spec.full_name] - unless calculated_checksum == checksum - raise SecurityError, <<-MESSAGE + raise SecurityError, <<~MESSAGE Bundler cannot continue installing #{spec.name} (#{spec.version}). The checksum for the downloaded `#{spec.full_name}.gem` does not match \ - the checksum given by the server. This means the contents of the downloaded \ - gem is different from what was uploaded to the server, and could be a potential security issue. + the known checksum for the gem. + This means the contents of the downloaded \ + gem is different from what was uploaded to the server \ + or first used by your teammates, and could be a potential security issue. To resolve this issue: - 1. delete the downloaded gem located at: `#{spec.gem_dir}/#{spec.full_name}.gem` + 1. delete the downloaded gem located at: `#{source.path}` 2. run `bundle install` + If you are sure that the new checksum is correct, you can \ + remove the `#{GemHelpers.lock_name spec.name, spec.version, spec.platform}` entry under the lockfile `CHECKSUMS` \ + section and rerun `bundle install`. + If you wish to continue installing the downloaded gem, and are certain it does not pose a \ security issue despite the mismatching checksum, do the following: 1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification 2. run `bundle install` - (More info: The expected SHA256 checksum was #{checksum.inspect}, but the \ - checksum for the downloaded gem was #{calculated_checksum.inspect}.) + #{expected.map do |algo, multi| + next unless actual = digests[algo] + next if actual == multi + + "(More info: The expected #{algo.upcase} checksum was #{multi.digest.inspect}, but the " \ + "checksum for the downloaded gem was #{actual.inspect}. The expected checksum came from: #{multi.sources.join(", ")})" + end.compact.join("\n")} MESSAGE end + register_digests(digests, checksum_store, source) true end - def checksum_type(checksum) - case checksum.length - when 64 then :hexdigest! - when 44 then :base64digest! - else raise InstallError, "The given checksum for #{spec.full_name} (#{checksum.inspect}) is not a valid SHA256 hexdigest nor base64digest" - end - end - - def hexdigest!(digest) - digest.hexdigest! - end - - def base64digest!(digest) - if digest.respond_to?(:base64digest!) - digest.base64digest! - else - [digest.digest!].pack("m0") - end + def register_digests(digests, checksum_store, source) + checksum_store.register( + spec, + digests.map {|algo, digest| Checksum::Single.new(algo, digest, "downloaded gem @ `#{source.path}`") } + ) end end end diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb index f7f5ea7865..115dbd1378 100644 --- a/lib/bundler/source.rb +++ b/lib/bundler/source.rb @@ -11,6 +11,8 @@ module Bundler attr_accessor :dependency_names + attr_reader :checksum_store + def unmet_deps specs.unmet_dependency_names end diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb index bdfcf8274a..cdf871250a 100644 --- a/lib/bundler/source/path.rb +++ b/lib/bundler/source/path.rb @@ -14,6 +14,7 @@ module Bundler DEFAULT_GLOB = "{,*,*/*}.gemspec" def initialize(options) + @checksum_store = Checksum::Store.new @options = options.dup @glob = options["glob"] || DEFAULT_GLOB diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 3d4d2eeec1..9ea8367006 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -19,6 +19,7 @@ module Bundler @allow_remote = false @allow_cached = false @allow_local = options["allow_local"] || false + @checksum_store = Checksum::Store.new Array(options["remotes"]).reverse_each {|r| add_remote(r) } end @@ -177,7 +178,7 @@ module Bundler :wrappers => true, :env_shebang => true, :build_args => options[:build_args], - :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum, + :bundler_checksum_store => spec.source.checksum_store, :bundler_extension_cache_path => extension_cache_path(spec) ) diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb index 0ce68b964c..da830cf8d4 100644 --- a/lib/bundler/stub_specification.rb +++ b/lib/bundler/stub_specification.rb @@ -93,16 +93,6 @@ 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 |