mirror of
https://github.com/ruby/ruby.git
synced 2025-08-24 21:44:30 +02:00
[rubygems/rubygems] Refactor Checksum classes and methods to reduce
code.
(https://github.com/rubygems/rubygems/pull/6917)
2238bdaadc
This commit is contained in:
parent
c5fd94073f
commit
92f23a48e3
24 changed files with 343 additions and 405 deletions
|
@ -2,6 +2,80 @@
|
||||||
|
|
||||||
module Bundler
|
module Bundler
|
||||||
class Checksum
|
class Checksum
|
||||||
|
DEFAULT_BLOCK_SIZE = 16_384
|
||||||
|
private_constant :DEFAULT_BLOCK_SIZE
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def from_gem_source(source, digest_algorithms: %w[sha256])
|
||||||
|
raise ArgumentError, "not a valid gem source: #{source}" unless source.respond_to?(:with_read_io)
|
||||||
|
|
||||||
|
source.with_read_io do |io|
|
||||||
|
checksums = from_io(io, "#{source.path || source.inspect} gem source hexdigest", :digest_algorithms => digest_algorithms)
|
||||||
|
io.rewind
|
||||||
|
return checksums
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def from_io(io, source, digest_algorithms: %w[sha256])
|
||||||
|
digests = digest_algorithms.to_h do |algo|
|
||||||
|
[algo.to_s, Bundler::SharedHelpers.digest(algo.upcase).new]
|
||||||
|
end
|
||||||
|
|
||||||
|
until io.eof?
|
||||||
|
ret = io.read DEFAULT_BLOCK_SIZE
|
||||||
|
digests.each_value {|digest| digest << ret }
|
||||||
|
end
|
||||||
|
|
||||||
|
digests.map do |algo, digest|
|
||||||
|
Checksum.new(algo, digest.hexdigest!, source)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_reader :algo, :digest, :sources
|
||||||
|
def initialize(algo, digest, source)
|
||||||
|
@algo = algo
|
||||||
|
@digest = digest
|
||||||
|
@sources = [source]
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
match?(other) && other.sources == sources
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method :eql?, :==
|
||||||
|
|
||||||
|
def match?(other)
|
||||||
|
other.is_a?(self.class) && other.digest == digest && other.algo == algo
|
||||||
|
end
|
||||||
|
|
||||||
|
def hash
|
||||||
|
digest.hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{to_lock} (from #{sources.first}#{", ..." if sources.size > 1})"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_lock
|
||||||
|
"#{algo}-#{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}
|
||||||
|
#{to_lock} from:
|
||||||
|
* #{sources.join("\n* ")}
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
|
||||||
|
@sources.concat(other.sources).uniq!
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
class Store
|
class Store
|
||||||
attr_reader :store
|
attr_reader :store
|
||||||
protected :store
|
protected :store
|
||||||
|
@ -10,42 +84,61 @@ module Bundler
|
||||||
@store = {}
|
@store = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize_copy(o)
|
def initialize_copy(other)
|
||||||
@store = {}
|
@store = {}
|
||||||
o.store.each do |k, v|
|
other.store.each do |full_name, checksums|
|
||||||
@store[k] = v.dup
|
store[full_name] = checksums.dup
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def [](spec)
|
def checksums(full_name)
|
||||||
sums = @store[spec.full_name]
|
store[full_name]
|
||||||
|
|
||||||
Checksum.new(spec.name, spec.version, spec.platform, sums&.transform_values(&:digest))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def register(spec, checksums)
|
def register_gem_package(spec, source)
|
||||||
register_full_name(spec.full_name, checksums)
|
new_checksums = Checksum.from_gem_source(source)
|
||||||
end
|
new_checksums.each do |checksum|
|
||||||
|
register spec.full_name, checksum
|
||||||
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
|
end
|
||||||
|
rescue SecurityError
|
||||||
|
expected = checksums(spec.full_name)
|
||||||
|
gem_lock_name = GemHelpers.lock_name(spec.name, spec.version, spec.platform)
|
||||||
|
raise SecurityError, <<~MESSAGE
|
||||||
|
Bundler cannot continue installing #{gem_lock_name}.
|
||||||
|
The checksum for the downloaded `#{spec.full_name}.gem` does not match \
|
||||||
|
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: `#{source.path}`
|
||||||
|
2. run `bundle install`
|
||||||
|
|
||||||
|
If you are sure that the new checksum is correct, you can \
|
||||||
|
remove the `#{gem_lock_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`
|
||||||
|
|
||||||
|
#{expected.map do |checksum|
|
||||||
|
next unless actual = new_checksums.find {|c| c.algo == checksum.algo }
|
||||||
|
next if actual.digest == checksum.digest
|
||||||
|
|
||||||
|
"(More info: The expected #{checksum.algo.upcase} checksum was #{checksum.digest.inspect}, but the " \
|
||||||
|
"checksum for the downloaded gem was #{actual.digest.inspect}. The expected checksum came from: #{checksum.sources.join(", ")})"
|
||||||
|
end.compact.join("\n")}
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
|
|
||||||
|
def register(full_name, checksum)
|
||||||
|
return unless checksum
|
||||||
|
|
||||||
|
sums = (store[full_name] ||= [])
|
||||||
|
sums.find {|c| c.algo == checksum.algo }&.merge!(checksum) || sums << checksum
|
||||||
rescue SecurityError => e
|
rescue SecurityError => e
|
||||||
raise e.exception(<<~MESSAGE)
|
raise e.exception(<<~MESSAGE)
|
||||||
Bundler found multiple different checksums for #{full_name}.
|
Bundler found multiple different checksums for #{full_name}.
|
||||||
|
@ -69,191 +162,15 @@ module Bundler
|
||||||
MESSAGE
|
MESSAGE
|
||||||
end
|
end
|
||||||
|
|
||||||
def use(other)
|
def replace(full_name, checksum)
|
||||||
other.store.each do |k, v|
|
store[full_name] = checksum ? [checksum] : nil
|
||||||
register_full_name k, v.values
|
end
|
||||||
|
|
||||||
|
def register_store(other)
|
||||||
|
other.store.each do |full_name, checksums|
|
||||||
|
checksums.each {|checksum| register(full_name, checksum) }
|
||||||
end
|
end
|
||||||
end
|
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 = {})
|
|
||||||
@name = name
|
|
||||||
@version = version
|
|
||||||
@platform = platform || Gem::Platform::RUBY
|
|
||||||
@checksums = checksums || {}
|
|
||||||
|
|
||||||
# can expand this validation when we support more hashing algos later
|
|
||||||
if !@checksums.is_a?(::Hash) || (@checksums.any? && !@checksums.key?("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.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|
|
|
||||||
until io.eof?
|
|
||||||
block = io.read(16_384)
|
|
||||||
digests.each_value {|digest| digest << block }
|
|
||||||
end
|
|
||||||
|
|
||||||
io.rewind
|
|
||||||
end
|
|
||||||
|
|
||||||
digests
|
|
||||||
end
|
|
||||||
|
|
||||||
def full_name
|
|
||||||
GemHelpers.spec_full_name(@name, @version, @platform)
|
|
||||||
end
|
|
||||||
|
|
||||||
def match_spec?(spec)
|
|
||||||
name == spec.name &&
|
|
||||||
version == spec.version &&
|
|
||||||
platform.to_s == spec.platform.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_lock
|
|
||||||
out = String.new
|
|
||||||
out << " #{GemHelpers.lock_name(name, version, platform)}"
|
|
||||||
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
|
|
||||||
@checksums.find {|c| c =~ SHA256 }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -753,7 +753,7 @@ module Bundler
|
||||||
# has to be done separately, because we want to keep the locked checksum
|
# has to be done separately, because we want to keep the locked checksum
|
||||||
# store for a source, even when doing a full update
|
# store for a source, even when doing a full update
|
||||||
if @locked_gems && locked_source = @locked_gems.sources.find {|s| s == source }
|
if @locked_gems && locked_source = @locked_gems.sources.find {|s| s == source }
|
||||||
source.checksum_store&.use(locked_source.checksum_store)
|
source.checksum_store.register_store(locked_source.checksum_store)
|
||||||
end
|
end
|
||||||
# If the source is unlockable and the current command allows an unlock of
|
# 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
|
# the source (for example, you are doing a `bundle update <foo>` of a git-pinned
|
||||||
|
|
|
@ -135,7 +135,7 @@ module Bundler
|
||||||
else
|
else
|
||||||
raise ArgumentError, "The given checksum for #{full_name} (#{digest.inspect}) is not a valid SHA256 hexdigest nor base64digest"
|
raise ArgumentError, "The given checksum for #{full_name} (#{digest.inspect}) is not a valid SHA256 hexdigest nor base64digest"
|
||||||
end
|
end
|
||||||
@checksum = Checksum::Single.new("sha256", digest, "API response from #{@spec_fetcher.uri}")
|
@checksum = Checksum.new("sha256", digest, "API response from #{@spec_fetcher.uri}")
|
||||||
when "rubygems"
|
when "rubygems"
|
||||||
@required_rubygems_version = Gem::Requirement.new(v)
|
@required_rubygems_version = Gem::Requirement.new(v)
|
||||||
when "ruby"
|
when "ruby"
|
||||||
|
|
|
@ -140,14 +140,11 @@ module Bundler
|
||||||
fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata|
|
fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata|
|
||||||
spec = if dependencies
|
spec = if dependencies
|
||||||
EndpointSpecification.new(name, version, platform, self, dependencies, metadata).tap do |es|
|
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
|
||||||
# Duplicate spec.full_names, different spec.original_names
|
# index#<< ensures that the last one added wins, so if we're overriding
|
||||||
# index#<< ensures that the last one added wins, so if we're overriding
|
# here, make sure to also override the checksum, otherwise downloading the
|
||||||
# here, make sure to also override the checksum, otherwise downloading the
|
# specs (even if that version is completely unused) will cause a SecurityError
|
||||||
# specs (even if that version is completely unused) will cause a SecurityError
|
source.checksum_store.replace(es.full_name, es.checksum)
|
||||||
source.checksum_store.delete_full_name(es.full_name)
|
|
||||||
end
|
|
||||||
source.checksum_store.register(es, [es.checksum]) if source && es.checksum
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
RemoteSpecification.new(name, version, platform, self)
|
RemoteSpecification.new(name, version, platform, self)
|
||||||
|
|
|
@ -69,10 +69,12 @@ module Bundler
|
||||||
def add_checksums
|
def add_checksums
|
||||||
out << "\nCHECKSUMS\n"
|
out << "\nCHECKSUMS\n"
|
||||||
|
|
||||||
empty_store = Checksum::Store.new
|
|
||||||
|
|
||||||
definition.resolve.sort_by(&:full_name).each do |spec|
|
definition.resolve.sort_by(&:full_name).each do |spec|
|
||||||
out << (spec.source.checksum_store || empty_store)[spec].to_lock
|
lock_name = GemHelpers.lock_name(spec.name, spec.version, spec.platform)
|
||||||
|
out << " #{lock_name}"
|
||||||
|
checksums = spec.source.checksum_store.checksums(spec.full_name)
|
||||||
|
out << " #{checksums.map(&:to_lock).sort.join(",")}" if checksums
|
||||||
|
out << "\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -225,19 +225,16 @@ 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
|
||||||
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)
|
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,
|
# Don't raise exception if there's a checksum for a gem that's not in the lockfile,
|
||||||
# we prefer to heal invalid lockfiles
|
# we prefer to heal invalid lockfiles
|
||||||
return unless spec = @specs[full_name]
|
return unless spec = @specs[full_name]
|
||||||
|
|
||||||
spec.source.checksum_store.register_full_name(full_name, checksums)
|
checksums.split(",").each do |c|
|
||||||
|
algo, digest = c.split("-", 2)
|
||||||
|
lock_name = GemHelpers.lock_name(spec.name, spec.version, spec.platform)
|
||||||
|
spec.source.checksum_store.register(full_name, Checksum.new(algo, digest, "#{@lockfile_path}:#{@pos} CHECKSUMS #{lock_name}"))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_spec(line)
|
def parse_spec(line)
|
||||||
|
|
|
@ -117,54 +117,11 @@ module Bundler
|
||||||
|
|
||||||
def validate_bundler_checksum(checksum_store)
|
def validate_bundler_checksum(checksum_store)
|
||||||
return true if Bundler.settings[:disable_checksum_validation]
|
return true if Bundler.settings[:disable_checksum_validation]
|
||||||
|
|
||||||
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)
|
||||||
digests = Bundler::Checksum.digests_from_file_source(source).transform_values(&:hexdigest!)
|
|
||||||
|
|
||||||
checksum = checksum_store[spec]
|
checksum_store.register_gem_package spec, source
|
||||||
unless checksum.match_digests?(digests)
|
|
||||||
expected = checksum_store.send(:store)[spec.full_name]
|
|
||||||
|
|
||||||
raise SecurityError, <<~MESSAGE
|
|
||||||
Bundler cannot continue installing #{spec.name} (#{spec.version}).
|
|
||||||
The checksum for the downloaded `#{spec.full_name}.gem` does not match \
|
|
||||||
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: `#{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`
|
|
||||||
|
|
||||||
#{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
|
true
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,6 +11,7 @@ module Bundler
|
||||||
|
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
@options = options
|
@options = options
|
||||||
|
@checksum_store = Checksum::Store.new
|
||||||
@glob = options["glob"] || DEFAULT_GLOB
|
@glob = options["glob"] || DEFAULT_GLOB
|
||||||
|
|
||||||
@allow_cached = false
|
@allow_cached = false
|
||||||
|
|
|
@ -78,7 +78,7 @@ RSpec.describe Bundler::Definition do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
foo (1.0)
|
#{gem_no_checksum "foo", "1.0"}
|
||||||
#{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
|
#{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
|
@ -137,7 +137,7 @@ RSpec.describe Bundler::Definition do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
foo (1.0)
|
#{gem_no_checksum "foo", "1.0"}
|
||||||
#{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
|
#{checksum_for_repo_gem gem_repo1, "rack", "1.0.0"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
|
|
|
@ -22,6 +22,9 @@ RSpec.describe Bundler::LockfileParser do
|
||||||
peiji-san!
|
peiji-san!
|
||||||
rake
|
rake
|
||||||
|
|
||||||
|
CHECKSUMS
|
||||||
|
rake (10.3.2) sha256-814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 2.1.3p242
|
ruby 2.1.3p242
|
||||||
|
|
||||||
|
@ -33,7 +36,7 @@ RSpec.describe Bundler::LockfileParser do
|
||||||
it "returns the attributes" do
|
it "returns the attributes" do
|
||||||
attributes = described_class.sections_in_lockfile(lockfile_contents)
|
attributes = described_class.sections_in_lockfile(lockfile_contents)
|
||||||
expect(attributes).to contain_exactly(
|
expect(attributes).to contain_exactly(
|
||||||
"BUNDLED WITH", "DEPENDENCIES", "GEM", "GIT", "PLATFORMS", "RUBY VERSION"
|
"BUNDLED WITH", "CHECKSUMS", "DEPENDENCIES", "GEM", "GIT", "PLATFORMS", "RUBY VERSION"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -115,6 +118,7 @@ RSpec.describe Bundler::LockfileParser do
|
||||||
let(:platforms) { [rb] }
|
let(:platforms) { [rb] }
|
||||||
let(:bundler_version) { Gem::Version.new("1.12.0.rc.2") }
|
let(:bundler_version) { Gem::Version.new("1.12.0.rc.2") }
|
||||||
let(:ruby_version) { "ruby 2.1.3p242" }
|
let(:ruby_version) { "ruby 2.1.3p242" }
|
||||||
|
let(:lockfile_path) { Bundler.default_lockfile.relative_path_from(Dir.pwd) }
|
||||||
|
|
||||||
shared_examples_for "parsing" do
|
shared_examples_for "parsing" do
|
||||||
it "parses correctly" do
|
it "parses correctly" do
|
||||||
|
@ -125,6 +129,11 @@ RSpec.describe Bundler::LockfileParser do
|
||||||
expect(subject.platforms).to eq platforms
|
expect(subject.platforms).to eq platforms
|
||||||
expect(subject.bundler_version).to eq bundler_version
|
expect(subject.bundler_version).to eq bundler_version
|
||||||
expect(subject.ruby_version).to eq ruby_version
|
expect(subject.ruby_version).to eq ruby_version
|
||||||
|
checksums = subject.sources.last.checksum_store.checksums("rake-10.3.2")
|
||||||
|
expect(checksums.size).to eq(1)
|
||||||
|
expected_checksum = Bundler::Checksum.new("sha256", "814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8", "#{lockfile_path}:??:1")
|
||||||
|
expect(checksums.first).to be_match(expected_checksum)
|
||||||
|
expect(checksums.first.sources.first).to match(/#{Regexp.escape(lockfile_path.to_s)}:\d+:\d+/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,5 +158,33 @@ RSpec.describe Bundler::LockfileParser do
|
||||||
let(:lockfile_contents) { super().sub("peiji-san!", "peiji-san!\n foo: bar") }
|
let(:lockfile_contents) { super().sub("peiji-san!", "peiji-san!\n foo: bar") }
|
||||||
include_examples "parsing"
|
include_examples "parsing"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when CHECKSUMS has duplicate checksums that don't match" do
|
||||||
|
let(:lockfile_contents) { super().split(/(?<=CHECKSUMS\n)/m).insert(1, " rake (10.3.2) sha256-69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b6\n").join }
|
||||||
|
|
||||||
|
it "raises a security error" do
|
||||||
|
expect { subject }.to raise_error(Bundler::SecurityError) do |e|
|
||||||
|
expect(e.message).to match <<~MESSAGE
|
||||||
|
Bundler found multiple different checksums for rake-10.3.2.
|
||||||
|
This means that there are multiple different `rake-10.3.2.gem` files.
|
||||||
|
This is a potential security issue, since Bundler could be attempting to install a different gem than what you expect.
|
||||||
|
|
||||||
|
sha256-814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8 (from #{lockfile_path}:21:1 CHECKSUMS rake (10.3.2))
|
||||||
|
sha256-69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b69b6 from:
|
||||||
|
* #{lockfile_path}:20:1 CHECKSUMS rake (10.3.2)
|
||||||
|
|
||||||
|
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 `rake-10.3.2` 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
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -920,7 +920,7 @@ RSpec.describe "bundle install with gem sources" do
|
||||||
gem "loofah", "~> 2.12.0"
|
gem "loofah", "~> 2.12.0"
|
||||||
G
|
G
|
||||||
|
|
||||||
checksums = construct_checksum_section do |c|
|
checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo4, "crass", "1.0.6"
|
c.repo_gem gem_repo4, "crass", "1.0.6"
|
||||||
c.repo_gem gem_repo4, "loofah", "2.12.0"
|
c.repo_gem gem_repo4, "loofah", "2.12.0"
|
||||||
c.repo_gem gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
|
c.repo_gem gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
|
||||||
|
@ -964,7 +964,7 @@ RSpec.describe "bundle install with gem sources" do
|
||||||
bundle "install", :artifice => "compact_index"
|
bundle "install", :artifice => "compact_index"
|
||||||
end
|
end
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo4, "crass", "1.0.6"
|
c.repo_gem gem_repo4, "crass", "1.0.6"
|
||||||
c.repo_gem gem_repo4, "loofah", "2.12.0"
|
c.repo_gem gem_repo4, "loofah", "2.12.0"
|
||||||
c.repo_gem gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
|
c.repo_gem gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
|
||||||
|
|
|
@ -11,7 +11,7 @@ RSpec.describe "bundle lock" do
|
||||||
gem "foo"
|
gem "foo"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem repo, "actionmailer", "2.3.2"
|
c.repo_gem repo, "actionmailer", "2.3.2"
|
||||||
c.repo_gem repo, "actionpack", "2.3.2"
|
c.repo_gem repo, "actionpack", "2.3.2"
|
||||||
c.repo_gem repo, "activerecord", "2.3.2"
|
c.repo_gem repo, "activerecord", "2.3.2"
|
||||||
|
@ -67,7 +67,7 @@ RSpec.describe "bundle lock" do
|
||||||
|
|
||||||
# No checksums because no way to get them from a file uri source
|
# No checksums because no way to get them from a file uri source
|
||||||
# + no existing lockfile that has them
|
# + no existing lockfile that has them
|
||||||
expect(out).to eq(@lockfile.strip.gsub(/ sha256-[a-f0-9]+$/, ""))
|
expect(out).to eq(remove_checksums_from_lockfile(@lockfile.chomp))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "prints a lockfile when there is an existing lockfile with --print" do
|
it "prints a lockfile when there is an existing lockfile with --print" do
|
||||||
|
@ -75,7 +75,7 @@ RSpec.describe "bundle lock" do
|
||||||
|
|
||||||
bundle "lock --print"
|
bundle "lock --print"
|
||||||
|
|
||||||
expect(out).to eq(@lockfile.strip)
|
expect(out).to eq(@lockfile.chomp)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "writes a lockfile when there is no existing lockfile" do
|
it "writes a lockfile when there is no existing lockfile" do
|
||||||
|
@ -83,7 +83,7 @@ RSpec.describe "bundle lock" do
|
||||||
|
|
||||||
# No checksums because no way to get them from a file uri source
|
# No checksums because no way to get them from a file uri source
|
||||||
# + no existing lockfile that has them
|
# + no existing lockfile that has them
|
||||||
expect(read_lockfile).to eq(@lockfile.gsub(/ sha256-[a-f0-9]+$/, ""))
|
expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "writes a lockfile when there is an outdated lockfile using --update" do
|
it "writes a lockfile when there is an outdated lockfile using --update" do
|
||||||
|
@ -98,7 +98,7 @@ RSpec.describe "bundle lock" do
|
||||||
bundle "lock --update", :env => { "BUNDLE_FROZEN" => "true" }
|
bundle "lock --update", :env => { "BUNDLE_FROZEN" => "true" }
|
||||||
|
|
||||||
# No checksums for the updated gems
|
# No checksums for the updated gems
|
||||||
expect(read_lockfile).to eq(@lockfile.gsub(/( \(2\.3\.2\)) sha256-[a-f0-9]+$/, "\\1"))
|
expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile, " (2.3.2)"))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not fetch remote specs when using the --local option" do
|
it "does not fetch remote specs when using the --local option" do
|
||||||
|
@ -125,7 +125,7 @@ RSpec.describe "bundle lock" do
|
||||||
foo
|
foo
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem repo, "foo", "1.0", :empty => true}
|
#{gem_no_checksum "foo", "1.0"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -141,7 +141,7 @@ RSpec.describe "bundle lock" do
|
||||||
bundle "lock --lockfile=lock"
|
bundle "lock --lockfile=lock"
|
||||||
|
|
||||||
expect(out).to match(/Writing lockfile to.+lock/)
|
expect(out).to match(/Writing lockfile to.+lock/)
|
||||||
expect(read_lockfile("lock")).to eq(@lockfile.gsub(/ sha256-[a-f0-9]+$/, ""))
|
expect(read_lockfile("lock")).to eq(remove_checksums_from_lockfile(@lockfile))
|
||||||
expect { read_lockfile }.to raise_error(Errno::ENOENT)
|
expect { read_lockfile }.to raise_error(Errno::ENOENT)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ RSpec.describe "bundle lock" do
|
||||||
bundle "install"
|
bundle "install"
|
||||||
bundle "lock --lockfile=lock"
|
bundle "lock --lockfile=lock"
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem repo, "actionmailer", "2.3.2"
|
c.repo_gem repo, "actionmailer", "2.3.2"
|
||||||
c.repo_gem repo, "actionpack", "2.3.2"
|
c.repo_gem repo, "actionpack", "2.3.2"
|
||||||
c.repo_gem repo, "activerecord", "2.3.2"
|
c.repo_gem repo, "activerecord", "2.3.2"
|
||||||
|
@ -208,7 +208,7 @@ RSpec.describe "bundle lock" do
|
||||||
|
|
||||||
bundle "lock --update rails rake"
|
bundle "lock --update rails rake"
|
||||||
|
|
||||||
expect(read_lockfile).to eq(@lockfile.gsub(/( \((?:2\.3\.2|13\.0\.1)\)) sha256-[a-f0-9]+$/, "\\1"))
|
expect(read_lockfile).to eq(remove_checksums_from_lockfile(@lockfile, "(2.3.2)", "(13.0.1)"))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "preserves unknown checksum algorithms" do
|
it "preserves unknown checksum algorithms" do
|
||||||
|
@ -626,10 +626,10 @@ RSpec.describe "bundle lock" do
|
||||||
mixlib-shellout
|
mixlib-shellout
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem gem_repo4, "ffi", "1.9.14", "x86-mingw32", :empty => true}
|
#{gem_no_checksum "ffi", "1.9.14", "x86-mingw32"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "gssapi", "1.2.0", :empty => true}
|
#{gem_no_checksum "gssapi", "1.2.0"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "mixlib-shellout", "2.2.6", "universal-mingw32", :empty => true}
|
#{gem_no_checksum "mixlib-shellout", "2.2.6", "universal-mingw32"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "win32-process", "0.8.3", :empty => true}
|
#{gem_no_checksum "win32-process", "0.8.3"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -661,12 +661,12 @@ RSpec.describe "bundle lock" do
|
||||||
mixlib-shellout
|
mixlib-shellout
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem gem_repo4, "ffi", "1.9.14", :empty => true}
|
#{gem_no_checksum "ffi", "1.9.14"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "ffi", "1.9.14", "x86-mingw32", :empty => true}
|
#{gem_no_checksum "ffi", "1.9.14", "x86-mingw32"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "gssapi", "1.2.0", :empty => true}
|
#{gem_no_checksum "gssapi", "1.2.0"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "mixlib-shellout", "2.2.6", :empty => true}
|
#{gem_no_checksum "mixlib-shellout", "2.2.6"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "mixlib-shellout", "2.2.6", "universal-mingw32", :empty => true}
|
#{gem_no_checksum "mixlib-shellout", "2.2.6", "universal-mingw32"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "win32-process", "0.8.3", :empty => true}
|
#{gem_no_checksum "win32-process", "0.8.3"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -747,8 +747,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", :empty => true}
|
#{gem_no_checksum "libv8", "8.4.255.0", "x86_64-darwin-19"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-20", :empty => true}
|
#{gem_no_checksum "libv8", "8.4.255.0", "x86_64-darwin-20"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -957,7 +957,7 @@ RSpec.describe "bundle lock" do
|
||||||
it "does not implicitly update" do
|
it "does not implicitly update" do
|
||||||
bundle "lock"
|
bundle "lock"
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem repo, "actionmailer", "2.3.2"
|
c.repo_gem repo, "actionmailer", "2.3.2"
|
||||||
c.repo_gem repo, "actionpack", "2.3.2"
|
c.repo_gem repo, "actionpack", "2.3.2"
|
||||||
c.repo_gem repo, "activerecord", "2.3.2"
|
c.repo_gem repo, "activerecord", "2.3.2"
|
||||||
|
@ -1014,15 +1014,13 @@ RSpec.describe "bundle lock" do
|
||||||
gemfile gemfile.gsub('"foo"', '"foo", "2.0"')
|
gemfile gemfile.gsub('"foo"', '"foo", "2.0"')
|
||||||
bundle "lock"
|
bundle "lock"
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem repo, "actionmailer", "2.3.2"
|
c.repo_gem repo, "actionmailer", "2.3.2"
|
||||||
c.repo_gem repo, "actionpack", "2.3.2"
|
c.repo_gem repo, "actionpack", "2.3.2"
|
||||||
c.repo_gem repo, "activerecord", "2.3.2"
|
c.repo_gem repo, "activerecord", "2.3.2"
|
||||||
c.repo_gem repo, "activeresource", "2.3.2"
|
c.repo_gem repo, "activeresource", "2.3.2"
|
||||||
c.repo_gem repo, "activesupport", "2.3.2"
|
c.repo_gem repo, "activesupport", "2.3.2"
|
||||||
# We don't have a checksum for foo 2,
|
c.no_checksum "foo", "2.0"
|
||||||
# since it is not downloaded by bundle lock, therefore we don't include it
|
|
||||||
# c.repo_gem repo, "foo", "2.0"
|
|
||||||
c.repo_gem repo, "rails", "2.3.2"
|
c.repo_gem repo, "rails", "2.3.2"
|
||||||
c.repo_gem repo, "rake", "13.0.1"
|
c.repo_gem repo, "rake", "13.0.1"
|
||||||
c.repo_gem repo, "weakling", "0.0.3"
|
c.repo_gem repo, "weakling", "0.0.3"
|
||||||
|
@ -1060,7 +1058,7 @@ RSpec.describe "bundle lock" do
|
||||||
weakling
|
weakling
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{expected_checksums.prepend(" ").lines(:chomp => true).append(" foo (2.0)").sort.join("\n")}
|
#{expected_checksums}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -1137,8 +1135,8 @@ RSpec.describe "bundle lock" do
|
||||||
debug
|
debug
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem gem_repo4, "debug", "1.6.3", :empty => true}
|
#{gem_no_checksum "debug", "1.6.3"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "irb", "1.5.0", :empty => true}
|
#{gem_no_checksum "irb", "1.5.0"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -1444,8 +1442,8 @@ RSpec.describe "bundle lock" do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem(gem_repo4, "foo", "1.0", :empty => true)}
|
#{gem_no_checksum "foo", "1.0"}
|
||||||
#{checksum_for_repo_gem(gem_repo4, "nokogiri", "1.14.2", :empty => true)}
|
#{gem_no_checksum "nokogiri", "1.14.2"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -1531,10 +1529,10 @@ RSpec.describe "bundle lock" do
|
||||||
govuk_app_config
|
govuk_app_config
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem gem_repo4, "actionpack", "7.0.4.3", :empty => true}
|
#{gem_no_checksum "actionpack", "7.0.4.3"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "activesupport", "7.0.4.3", :empty => true}
|
#{gem_no_checksum "activesupport", "7.0.4.3"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "govuk_app_config", "4.13.0", :empty => true}
|
#{gem_no_checksum "govuk_app_config", "4.13.0"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "railties", "7.0.4.3", :empty => true}
|
#{gem_no_checksum "railties", "7.0.4.3"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
|
|
@ -509,7 +509,7 @@ RSpec.describe "bundle update" do
|
||||||
|
|
||||||
original_lockfile = lockfile
|
original_lockfile = lockfile
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo4, "activesupport", "6.0.4.1"
|
c.repo_gem gem_repo4, "activesupport", "6.0.4.1"
|
||||||
c.repo_gem gem_repo4, "tzinfo", "1.2.9"
|
c.repo_gem gem_repo4, "tzinfo", "1.2.9"
|
||||||
end
|
end
|
||||||
|
@ -541,7 +541,7 @@ RSpec.describe "bundle update" do
|
||||||
|
|
||||||
# needed because regressing to versions already present on the system
|
# needed because regressing to versions already present on the system
|
||||||
# won't add a checksum
|
# won't add a checksum
|
||||||
expected_lockfile = expected_lockfile.gsub(/ sha256-[a-f0-9]+$/, "")
|
expected_lockfile = remove_checksums_from_lockfile(expected_lockfile)
|
||||||
|
|
||||||
lockfile original_lockfile
|
lockfile original_lockfile
|
||||||
bundle "update"
|
bundle "update"
|
||||||
|
|
|
@ -449,7 +449,7 @@ RSpec.describe "bundle install from an existing gemspec" do
|
||||||
it "keeps all platform dependencies in the lockfile" do
|
it "keeps all platform dependencies in the lockfile" do
|
||||||
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
|
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = 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", "java"
|
||||||
c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32
|
c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32
|
||||||
|
@ -493,7 +493,7 @@ RSpec.describe "bundle install from an existing gemspec" do
|
||||||
it "keeps all platform dependencies in the lockfile" do
|
it "keeps all platform dependencies in the lockfile" do
|
||||||
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
|
expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = 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", "java"
|
||||||
c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32
|
c.repo_gem gem_repo2, "platform_specific", "1.0", x64_mingw32
|
||||||
|
@ -538,7 +538,7 @@ RSpec.describe "bundle install from an existing gemspec" do
|
||||||
it "keeps all platform dependencies in the lockfile" do
|
it "keeps all platform dependencies in the lockfile" do
|
||||||
expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 RUBY"
|
expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 RUBY"
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = 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", "java"
|
||||||
|
|
|
@ -39,9 +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", :empty => true}
|
#{gem_no_checksum "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", :empty => true}
|
#{gem_no_checksum "thin", "1.0"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
|
|
@ -121,8 +121,8 @@ RSpec.describe "bundle install with explicit source paths" do
|
||||||
demo!
|
demo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
aaa (1.0)
|
#{gem_no_checksum("aaa", "1.0")}
|
||||||
demo (1.0)
|
#{gem_no_checksum("demo", "1.0")}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -364,8 +364,8 @@ RSpec.describe "bundle install with explicit source paths" do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
foo (0.1.0)
|
#{gem_no_checksum("foo", "0.1.0")}
|
||||||
#{checksum_for_repo_gem gem_repo4, "graphql", "2.0.15"}
|
#{checksum_for_repo_gem(gem_repo4, "graphql", "2.0.15")}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -692,8 +692,8 @@ RSpec.describe "bundle install with explicit source paths" do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
foo (1.0)
|
#{gem_no_checksum("foo", "1.0")}
|
||||||
#{checksum_for_repo_gem gem_repo1, "rack", "0.9.1"}
|
#{checksum_for_repo_gem(gem_repo1, "rack", "0.9.1")}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -724,8 +724,8 @@ RSpec.describe "bundle install with explicit source paths" do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
foo (1.0)
|
#{gem_no_checksum("foo", "1.0")}
|
||||||
#{checksum_for_repo_gem gem_repo1, "rack", "0.9.1"}
|
#{checksum_for_repo_gem(gem_repo1, "rack", "0.9.1")}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -762,8 +762,8 @@ RSpec.describe "bundle install with explicit source paths" do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
foo (1.0)
|
#{gem_no_checksum("foo", "1.0")}
|
||||||
#{checksum_for_repo_gem gem_repo1, "rack", "0.9.1"}
|
#{checksum_for_repo_gem(gem_repo1, "rack", "0.9.1")}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -797,9 +797,9 @@ RSpec.describe "bundle install with explicit source paths" do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
foo (1.0)
|
#{gem_no_checksum("foo", "1.0")}
|
||||||
#{checksum_for_repo_gem gem_repo1, "rack", "0.9.1"}
|
#{checksum_for_repo_gem(gem_repo1, "rack", "0.9.1")}
|
||||||
#{checksum_for_repo_gem gem_repo1, "rake", "13.0.1"}
|
#{checksum_for_repo_gem(gem_repo1, "rake", "13.0.1")}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -850,8 +850,8 @@ RSpec.describe "bundle install with explicit source paths" do
|
||||||
foo!
|
foo!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
foo (1.0)
|
#{gem_no_checksum("foo", "1.0")}
|
||||||
rack (0.9.1)
|
#{gem_no_checksum("rack", "0.9.1")}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
|
|
@ -426,7 +426,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", :empty => true)}
|
#{gem_no_checksum "platform_specific", "1.0", "java"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
|
|
@ -284,7 +284,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
|
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
|
||||||
expect(err).to include("Installed from: https://gem.repo2")
|
expect(err).to include("Installed from: https://gem.repo2")
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo3, "depends_on_rack", "1.0.1"
|
c.repo_gem gem_repo3, "depends_on_rack", "1.0.1"
|
||||||
c.repo_gem gem_repo2, "rack", "1.0.0"
|
c.repo_gem gem_repo2, "rack", "1.0.0"
|
||||||
end
|
end
|
||||||
|
@ -706,7 +706,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
expect(the_bundle).to include_gems("concurrent-ruby 1.1.8")
|
expect(the_bundle).to include_gems("concurrent-ruby 1.1.8")
|
||||||
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9")
|
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9")
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "activesupport", "6.0.3.4"
|
c.repo_gem gem_repo2, "activesupport", "6.0.3.4"
|
||||||
c.repo_gem gem_repo2, "concurrent-ruby", "1.1.8"
|
c.repo_gem gem_repo2, "concurrent-ruby", "1.1.8"
|
||||||
c.repo_gem gem_repo2, "connection_pool", "2.2.3"
|
c.repo_gem gem_repo2, "connection_pool", "2.2.3"
|
||||||
|
@ -809,7 +809,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
|
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
|
||||||
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
|
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "activesupport", "6.1.2.1"
|
c.repo_gem gem_repo2, "activesupport", "6.1.2.1"
|
||||||
c.repo_gem gem_repo2, "concurrent-ruby", "1.1.9"
|
c.repo_gem gem_repo2, "concurrent-ruby", "1.1.9"
|
||||||
c.repo_gem gem_repo2, "connection_pool", "2.2.3"
|
c.repo_gem gem_repo2, "connection_pool", "2.2.3"
|
||||||
|
@ -881,7 +881,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
|
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
|
||||||
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
|
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "activesupport", "6.0.3.4"
|
c.repo_gem gem_repo2, "activesupport", "6.0.3.4"
|
||||||
c.repo_gem gem_repo2, "concurrent-ruby", "1.1.9"
|
c.repo_gem gem_repo2, "concurrent-ruby", "1.1.9"
|
||||||
c.repo_gem gem_repo2, "connection_pool", "2.2.3"
|
c.repo_gem gem_repo2, "connection_pool", "2.2.3"
|
||||||
|
@ -1006,7 +1006,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "installs from the default source without any warnings or errors and generates a proper lockfile" do
|
it "installs from the default source without any warnings or errors and generates a proper lockfile" do
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo3, "handsoap", "0.2.5.5"
|
c.repo_gem gem_repo3, "handsoap", "0.2.5.5"
|
||||||
c.repo_gem gem_repo2, "nokogiri", "1.11.1"
|
c.repo_gem gem_repo2, "nokogiri", "1.11.1"
|
||||||
c.repo_gem gem_repo2, "racca", "1.5.2"
|
c.repo_gem gem_repo2, "racca", "1.5.2"
|
||||||
|
@ -1567,7 +1567,7 @@ 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|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "capybara", "2.5.0"
|
c.repo_gem gem_repo2, "capybara", "2.5.0"
|
||||||
c.repo_gem gem_repo4, "mime-types", "3.0.0"
|
c.repo_gem gem_repo4, "mime-types", "3.0.0"
|
||||||
end
|
end
|
||||||
|
@ -1686,7 +1686,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
it "handles that fine" do
|
it "handles that fine" do
|
||||||
bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
|
bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo4, "pdf-writer", "1.1.8"
|
c.repo_gem gem_repo4, "pdf-writer", "1.1.8"
|
||||||
c.repo_gem gem_repo2, "ruport", "1.7.0.3"
|
c.repo_gem gem_repo2, "ruport", "1.7.0.3"
|
||||||
end
|
end
|
||||||
|
@ -1741,7 +1741,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
it "handles that fine" do
|
it "handles that fine" do
|
||||||
bundle "install --verbose", :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
|
bundle "install --verbose", :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo4, "pdf-writer", "1.1.8"
|
c.repo_gem gem_repo4, "pdf-writer", "1.1.8"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -528,7 +528,7 @@ RSpec.describe "bundle install with specific platforms" do
|
||||||
|
|
||||||
bundle "update"
|
bundle "update"
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo4, "sorbet", "0.5.10160"
|
c.repo_gem gem_repo4, "sorbet", "0.5.10160"
|
||||||
c.repo_gem gem_repo4, "sorbet-runtime", "0.5.10160"
|
c.repo_gem gem_repo4, "sorbet-runtime", "0.5.10160"
|
||||||
c.repo_gem gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
|
c.repo_gem gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
|
||||||
|
@ -626,8 +626,8 @@ RSpec.describe "bundle install with specific platforms" do
|
||||||
sorbet-static
|
sorbet-static
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem gem_repo4, "nokogiri", "1.13.0", "x86_64-darwin", :empty => true}
|
#{gem_no_checksum "nokogiri", "1.13.0", "x86_64-darwin"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "sorbet-static", "0.5.10601", "x86_64-darwin", :empty => true}
|
#{gem_no_checksum "sorbet-static", "0.5.10601", "x86_64-darwin"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -682,7 +682,7 @@ RSpec.describe "bundle install with specific platforms" do
|
||||||
|
|
||||||
bundle "update"
|
bundle "update"
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo4, "sorbet", "0.5.10160"
|
c.repo_gem gem_repo4, "sorbet", "0.5.10160"
|
||||||
c.repo_gem gem_repo4, "sorbet-runtime", "0.5.10160"
|
c.repo_gem gem_repo4, "sorbet-runtime", "0.5.10160"
|
||||||
c.repo_gem gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
|
c.repo_gem gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
|
||||||
|
@ -836,7 +836,7 @@ RSpec.describe "bundle install with specific platforms" do
|
||||||
|
|
||||||
CHECKSUMS
|
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-20"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-21", :empty => true}
|
#{gem_no_checksum "sorbet-static", "0.5.10549", "universal-darwin-21"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -899,8 +899,8 @@ RSpec.describe "bundle install with specific platforms" do
|
||||||
tzinfo (~> 1.2)
|
tzinfo (~> 1.2)
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem gem_repo4, "nokogiri", "1.13.8", :empty => true}
|
#{gem_no_checksum "nokogiri", "1.13.8"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "nokogiri", "1.13.8", Gem::Platform.local, :empty => true}
|
#{gem_no_checksum "nokogiri", "1.13.8", Gem::Platform.local}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -955,8 +955,8 @@ RSpec.describe "bundle install with specific platforms" do
|
||||||
rack
|
rack
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem gem_repo4, "concurrent-ruby", "1.2.2", :empty => true}
|
#{gem_no_checksum "concurrent-ruby", "1.2.2"}
|
||||||
#{checksum_for_repo_gem gem_repo4, "rack", "3.0.7", :empty => true}
|
#{gem_no_checksum "rack", "3.0.7"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
|
|
@ -882,7 +882,7 @@ The checksum of /versions does not match the checksum provided by the server! So
|
||||||
gem "rack"
|
gem "rack"
|
||||||
G
|
G
|
||||||
|
|
||||||
api_checksum = Spec::Checksums::ChecksumsBuilder.new.repo_gem(gem_repo1, "rack", "1.0.0").first.checksums.fetch("sha256")
|
api_checksum = checksum_for_repo_gem(gem_repo1, "rack", "1.0.0").split("sha256-").last
|
||||||
|
|
||||||
gem_path = if Bundler.feature_flag.global_gem_cache?
|
gem_path = if Bundler.feature_flag.global_gem_cache?
|
||||||
default_cache_path.dirname.join("cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "rack-1.0.0.gem")
|
default_cache_path.dirname.join("cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "rack-1.0.0.gem")
|
||||||
|
|
|
@ -161,8 +161,8 @@ 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", :empty => true)}
|
#{gem_no_checksum "bar", "2.0.0"}
|
||||||
#{checksum_for_repo_gem(gem_repo4, "foo", "9.0.0", :empty => true)}
|
#{gem_no_checksum "foo", "9.0.0"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
|
|
@ -279,7 +279,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "rack-obama"
|
gem "rack-obama"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "rack", "1.0.0"
|
c.repo_gem gem_repo2, "rack", "1.0.0"
|
||||||
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
||||||
end
|
end
|
||||||
|
@ -313,7 +313,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "rack-obama", ">= 1.0"
|
gem "rack-obama", ">= 1.0"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "rack", "1.0.0"
|
c.repo_gem gem_repo2, "rack", "1.0.0"
|
||||||
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
||||||
end
|
end
|
||||||
|
@ -355,7 +355,7 @@ RSpec.describe "the lockfile format" do
|
||||||
end
|
end
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "rack", "1.0.0"
|
c.repo_gem gem_repo2, "rack", "1.0.0"
|
||||||
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
||||||
end
|
end
|
||||||
|
@ -396,7 +396,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "net-sftp"
|
gem "net-sftp"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "net-sftp", "1.1.1"
|
c.repo_gem gem_repo2, "net-sftp", "1.1.1"
|
||||||
c.repo_gem gem_repo2, "net-ssh", "1.0"
|
c.repo_gem gem_repo2, "net-ssh", "1.0"
|
||||||
end
|
end
|
||||||
|
@ -684,8 +684,8 @@ RSpec.describe "the lockfile format" do
|
||||||
ckeditor!
|
ckeditor!
|
||||||
|
|
||||||
CHECKSUMS
|
CHECKSUMS
|
||||||
#{checksum_for_repo_gem(gem_repo4, "ckeditor", "4.0.8", :empty => true)}
|
#{gem_no_checksum "ckeditor", "4.0.8"}
|
||||||
#{checksum_for_repo_gem(gem_repo4, "orm_adapter", "0.4.1", :empty => true)}
|
#{gem_no_checksum "orm_adapter", "0.4.1"}
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
|
@ -814,7 +814,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "rack", :source => "#{file_uri_for(gem_repo2)}/"
|
gem "rack", :source => "#{file_uri_for(gem_repo2)}/"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "rack", "1.0.0"
|
c.repo_gem gem_repo2, "rack", "1.0.0"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -847,7 +847,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "rack-obama"
|
gem "rack-obama"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "actionpack", "2.3.2"
|
c.repo_gem gem_repo2, "actionpack", "2.3.2"
|
||||||
c.repo_gem gem_repo2, "activesupport", "2.3.2"
|
c.repo_gem gem_repo2, "activesupport", "2.3.2"
|
||||||
c.repo_gem gem_repo2, "rack", "1.0.0"
|
c.repo_gem gem_repo2, "rack", "1.0.0"
|
||||||
|
@ -891,7 +891,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "rails"
|
gem "rails"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "actionmailer", "2.3.2"
|
c.repo_gem gem_repo2, "actionmailer", "2.3.2"
|
||||||
c.repo_gem gem_repo2, "actionpack", "2.3.2"
|
c.repo_gem gem_repo2, "actionpack", "2.3.2"
|
||||||
c.repo_gem gem_repo2, "activerecord", "2.3.2"
|
c.repo_gem gem_repo2, "activerecord", "2.3.2"
|
||||||
|
@ -952,7 +952,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem 'double_deps'
|
gem 'double_deps'
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "double_deps", "1.0"
|
c.repo_gem gem_repo2, "double_deps", "1.0"
|
||||||
c.repo_gem gem_repo2, "net-ssh", "1.0"
|
c.repo_gem gem_repo2, "net-ssh", "1.0"
|
||||||
end
|
end
|
||||||
|
@ -987,7 +987,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "rack-obama", ">= 1.0", :require => "rack/obama"
|
gem "rack-obama", ">= 1.0", :require => "rack/obama"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "rack", "1.0.0"
|
c.repo_gem gem_repo2, "rack", "1.0.0"
|
||||||
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
||||||
end
|
end
|
||||||
|
@ -1021,7 +1021,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "rack-obama", ">= 1.0", :group => :test
|
gem "rack-obama", ">= 1.0", :group => :test
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "rack", "1.0.0"
|
c.repo_gem gem_repo2, "rack", "1.0.0"
|
||||||
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
c.repo_gem gem_repo2, "rack-obama", "1.0"
|
||||||
end
|
end
|
||||||
|
@ -1239,7 +1239,7 @@ RSpec.describe "the lockfile format" do
|
||||||
gem "platform_specific"
|
gem "platform_specific"
|
||||||
G
|
G
|
||||||
|
|
||||||
expected_checksums = construct_checksum_section do |c|
|
expected_checksums = checksum_section do |c|
|
||||||
c.repo_gem gem_repo2, "platform_specific", "1.0", "universal-java-16"
|
c.repo_gem gem_repo2, "platform_specific", "1.0", "universal-java-16"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,10 @@ RSpec.describe "real world edgecases", :realworld => true do
|
||||||
require "bundler/source/rubygems/remote"
|
require "bundler/source/rubygems/remote"
|
||||||
require "bundler/fetcher"
|
require "bundler/fetcher"
|
||||||
rubygem = Bundler.ui.silence do
|
rubygem = Bundler.ui.silence do
|
||||||
source = Bundler::Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org"))
|
remote = Bundler::Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org"))
|
||||||
fetcher = Bundler::Fetcher.new(source)
|
source = Bundler::Source::Rubygems.new
|
||||||
index = fetcher.specs([#{name.dump}], nil)
|
fetcher = Bundler::Fetcher.new(remote)
|
||||||
|
index = fetcher.specs([#{name.dump}], source)
|
||||||
requirement = Gem::Requirement.create(#{requirement.dump})
|
requirement = Gem::Requirement.create(#{requirement.dump})
|
||||||
index.search(#{name.dump}).select {|spec| requirement.satisfied_by?(spec.version) }.last
|
index.search(#{name.dump}).select {|spec| requirement.satisfied_by?(spec.version) }.last
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,49 +3,80 @@
|
||||||
module Spec
|
module Spec
|
||||||
module Checksums
|
module Checksums
|
||||||
class ChecksumsBuilder
|
class ChecksumsBuilder
|
||||||
def initialize
|
def initialize(&block)
|
||||||
@checksums = []
|
@checksums = {}
|
||||||
|
yield self if block_given?
|
||||||
end
|
end
|
||||||
|
|
||||||
def repo_gem(gem_repo, gem_name, gem_version, platform = nil, empty: false)
|
def repo_gem(repo, name, version, platform = Gem::Platform::RUBY)
|
||||||
gem_file = if platform
|
gem_file = File.join(repo, "gems", "#{Bundler::GemHelpers.spec_full_name(name, version, platform)}.gem")
|
||||||
"#{gem_repo}/gems/#{gem_name}-#{gem_version}-#{platform}.gem"
|
File.open(gem_file, "rb") do |f|
|
||||||
else
|
checksums = Bundler::Checksum.from_io(f, "ChecksumsBuilder")
|
||||||
"#{gem_repo}/gems/#{gem_name}-#{gem_version}.gem"
|
checksum_entry(checksums, name, version, platform)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
checksum = { "sha256" => sha256_checksum(gem_file) } unless empty
|
def no_checksum(name, version, platform = Gem::Platform::RUBY)
|
||||||
@checksums << Bundler::Checksum.new(gem_name, gem_version, platform, checksum)
|
checksum_entry(nil, name, version, platform)
|
||||||
|
end
|
||||||
|
|
||||||
|
def checksum_entry(checksums, name, version, platform = Gem::Platform::RUBY)
|
||||||
|
lock_name = Bundler::GemHelpers.lock_name(name, version, platform)
|
||||||
|
@checksums[lock_name] = checksums
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_lock
|
def to_lock
|
||||||
@checksums.map(&:to_lock).sort.join.strip
|
@checksums.map do |lock_name, checksums|
|
||||||
|
checksums &&= " #{checksums.map(&:to_lock).join(",")}"
|
||||||
|
" #{lock_name}#{checksums}\n"
|
||||||
|
end.sort.join.strip
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
def checksum_section(&block)
|
||||||
|
ChecksumsBuilder.new(&block).to_lock
|
||||||
|
end
|
||||||
|
|
||||||
def sha256_checksum(file)
|
def checksum_for_repo_gem(*args)
|
||||||
File.open(file) do |f|
|
checksum_section do |c|
|
||||||
digest = Bundler::SharedHelpers.digest(:SHA256).new
|
c.repo_gem(*args)
|
||||||
digest << f.read(16_384) until f.eof?
|
end
|
||||||
|
end
|
||||||
|
|
||||||
digest.hexdigest!
|
def gem_no_checksum(*args)
|
||||||
|
checksum_section do |c|
|
||||||
|
c.no_checksum(*args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# if prefixes is given, removes all checksums where the line
|
||||||
|
# has any of the prefixes on the line before the checksum
|
||||||
|
# otherwise, removes all checksums from the lockfile
|
||||||
|
def remove_checksums_from_lockfile(lockfile, *prefixes)
|
||||||
|
head, remaining = lockfile.split(/^CHECKSUMS$/, 2)
|
||||||
|
checksums, tail = remaining.split("\n\n", 2)
|
||||||
|
|
||||||
|
prefixes =
|
||||||
|
if prefixes.empty?
|
||||||
|
nil
|
||||||
|
else
|
||||||
|
/(#{prefixes.map {|p| Regexp.escape(p) }.join("|")})/
|
||||||
|
end
|
||||||
|
|
||||||
|
checksums = checksums.each_line.map do |line|
|
||||||
|
if prefixes.nil? || line.match?(prefixes)
|
||||||
|
line.gsub(/ sha256-[a-f0-9]{64}/i, "")
|
||||||
|
else
|
||||||
|
line
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def construct_checksum_section
|
head.concat(
|
||||||
checksums = ChecksumsBuilder.new
|
"CHECKSUMS",
|
||||||
|
checksums.join,
|
||||||
yield checksums
|
"\n\n",
|
||||||
|
tail
|
||||||
checksums.to_lock
|
)
|
||||||
end
|
|
||||||
|
|
||||||
def checksum_for_repo_gem(*args, **kwargs)
|
|
||||||
construct_checksum_section do |c|
|
|
||||||
c.repo_gem(*args, **kwargs)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue