summaryrefslogtreecommitdiff
path: root/spec/bundler/install/gemfile/sources_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/bundler/install/gemfile/sources_spec.rb')
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb630
1 files changed, 493 insertions, 137 deletions
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
index 89c812e5d5..a5ba76f4d9 100644
--- a/spec/bundler/install/gemfile/sources_spec.rb
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -27,18 +27,72 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
+ it "refuses to install mismatched checksum because one gem has been tampered with", bundler: "< 3" do
+ lockfile <<~L
+ GEM
+ remote: https://gem.repo3/
+ remote: https://gem.repo1/
+ specs:
+ rack (1.0.0)
- expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
- expect(err).to include("Installed from: https://gem.repo1")
- expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
+ PLATFORMS
+ #{local_platform}
+
+ DEPENDENCIES
+ depends_on_rack!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+
+ bundle :install, artifice: "compact_index", raise_on_error: false
+
+ expect(exitstatus).to eq(37)
+ expect(err).to eq <<~E.strip
+ [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
+ Bundler found mismatched checksums. This is a potential security risk.
+ #{checksum_to_lock(gem_repo1, "rack", "1.0.0")}
+ from the API at https://gem.repo1/
+ #{checksum_to_lock(gem_repo3, "rack", "1.0.0")}
+ from the API at https://gem.repo3/
+
+ Mismatched checksums each have an authoritative source:
+ 1. the API at https://gem.repo1/
+ 2. the API at https://gem.repo3/
+ You may need to alter your Gemfile sources to resolve this issue.
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
end
- it "fails", :bundler => "3" do
- bundle :instal, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include("Each source after the first must include a block")
- expect(exitstatus).to eq(4)
+ context "when checksum validation is disabled" do
+ before do
+ bundle "config set --local disable_checksum_validation true"
+ end
+
+ it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", bundler: "< 3" do
+ bundle :install, artifice: "compact_index"
+
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(err).to include("Installed from: https://gem.repo1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", source: "remote1")
+ end
+
+ it "does not use the full index unnecessarily", bundler: "< 3" do
+ bundle :install, artifice: "compact_index", verbose: true
+
+ expect(out).to include("https://gem.repo1/versions")
+ expect(out).to include("https://gem.repo3/versions")
+ expect(out).not_to include("https://gem.repo1/quick/Marshal.4.8/")
+ expect(out).not_to include("https://gem.repo3/quick/Marshal.4.8/")
+ end
+
+ it "fails", bundler: "3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
+ expect(err).to include("Each source after the first must include a block")
+ expect(exitstatus).to eq(4)
+ end
end
end
@@ -54,21 +108,49 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "warns about ambiguous gems, but installs anyway", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
+ it "warns about ambiguous gems, but installs anyway", bundler: "< 3" do
+ bundle :install, artifice: "compact_index"
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: https://gem.repo1")
- expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", source: "remote1")
end
- it "fails", :bundler => "3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ it "fails", bundler: "3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
end
end
+ context "without source affinity, and a stdlib gem present in one of the sources", :ruby_repo do
+ let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" }
+
+ before do
+ build_repo2 do
+ build_gem "json", default_json_version
+ end
+
+ build_repo4 do
+ build_gem "foo" do |s|
+ s.add_dependency "json", default_json_version
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+ source "https://gem.repo4"
+
+ gem "foo"
+ G
+ end
+
+ it "works in standalone mode", bundler: "< 3" do
+ gem_checksum = checksum_digest(gem_repo4, "foo", "1.0")
+ bundle "install --standalone", artifice: "compact_index", env: { "BUNDLER_SPEC_FOO_CHECKSUM" => gem_checksum }
+ end
+ end
+
context "with source affinity" do
context "with sources given by a block" do
before do
@@ -95,20 +177,20 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the gems without any warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("rack-obama 1.0.0")
- expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote1")
+ expect(the_bundle).to include_gems("rack 1.0.0", source: "remote1")
end
it "can cache and deploy" do
- bundle :cache, :artifice => "compact_index"
+ bundle :cache, artifice: "compact_index"
expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/rack-obama-1.0.gem")).to exist
bundle "config set --local deployment true"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0")
end
@@ -128,7 +210,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo3"
gem "rack-obama" # should come from repo3!
gem "rack", :source => "https://gem.repo1"
@@ -168,9 +250,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the same source without any warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
end
end
@@ -185,18 +267,18 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the same source without any warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
# In https://github.com/bundler/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
end
end
end
@@ -218,7 +300,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "and not in any other sources" do
before do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo2"
source "https://gem.repo3" do
gem "depends_on_rack"
@@ -243,11 +325,63 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
+ it "fails when the two sources don't have the same checksum", bundler: "< 3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
+
+ expect(err).to eq(<<~E.strip)
+ [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
+ Bundler found mismatched checksums. This is a potential security risk.
+ #{checksum_to_lock(gem_repo2, "rack", "1.0.0")}
+ from the API at https://gem.repo2/
+ #{checksum_to_lock(gem_repo1, "rack", "1.0.0")}
+ from the API at https://gem.repo1/
+
+ Mismatched checksums each have an authoritative source:
+ 1. the API at https://gem.repo2/
+ 2. the API at https://gem.repo1/
+ You may need to alter your Gemfile sources to resolve this issue.
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
+ expect(exitstatus).to eq(37)
+ end
+
+ it "fails when the two sources agree, but the local gem calculates a different checksum", bundler: "< 3" do
+ rack_checksum = "c0ffee11" * 8
+ bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_RACK_CHECKSUM" => rack_checksum }, raise_on_error: false
+
+ expect(err).to eq(<<~E.strip)
+ [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
+ Bundler found mismatched checksums. This is a potential security risk.
+ rack (1.0.0) sha256=#{rack_checksum}
+ from the API at https://gem.repo2/
+ and the API at https://gem.repo1/
+ #{checksum_to_lock(gem_repo2, "rack", "1.0.0")}
+ from the gem at #{default_bundle_path("cache", "rack-1.0.0.gem")}
+
+ If you trust the API at https://gem.repo2/, to resolve this issue you can:
+ 1. remove the gem at #{default_bundle_path("cache", "rack-1.0.0.gem")}
+ 2. run `bundle install`
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
+ expect(exitstatus).to eq(37)
+ end
+
+ it "installs from the other source and warns about ambiguous gems when the sources have the same checksum", bundler: "< 3" do
+ gem_checksum = checksum_digest(gem_repo2, "rack", "1.0.0")
+ bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_RACK_CHECKSUM" => gem_checksum, "DEBUG" => "1" }
+
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: https://gem.repo2")
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo3, "depends_on_rack", "1.0.1"
+ c.checksum gem_repo2, "rack", "1.0.0"
+ end
+
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo1/
@@ -262,11 +396,51 @@ RSpec.describe "bundle install with gems on multiple sources" do
rack
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
depends_on_rack!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ previous_lockfile = lockfile
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
+ expect(lockfile).to eq(previous_lockfile)
+ end
+
+ it "installs from the other source and warns about ambiguous gems when checksum validation is disabled", bundler: "< 3" do
+ bundle "config set --local disable_checksum_validation true"
+ bundle :install, artifice: "compact_index"
+
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(err).to include("Installed from: https://gem.repo2")
+
+ checksums = checksums_section_when_existing do |c|
+ c.no_checksum "depends_on_rack", "1.0.1"
+ c.no_checksum "rack", "1.0.0"
+ end
+
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://gem.repo1/
+ remote: https://gem.repo2/
+ specs:
+ rack (1.0.0)
+
+ GEM
+ remote: https://gem.repo3/
+ specs:
+ depends_on_rack (1.0.1)
+ rack
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ depends_on_rack!
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -276,8 +450,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(lockfile).to eq(previous_lockfile)
end
- it "fails", :bundler => "3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ it "fails", bundler: "3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
@@ -301,8 +475,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
end
- it "installs the dependency from the pinned source without warning", :bundler => "< 3" do
- bundle :install, :artifice => "compact_index"
+ it "installs the dependency from the pinned source without warning", bundler: "< 3" do
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
@@ -310,14 +484,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
# In https://github.com/rubygems/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
- it "fails", :bundler => "3" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ it "fails", bundler: "3" do
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
@@ -345,12 +519,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "fails" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/ or installed locally.")
+ bundle :install, artifice: "compact_index", raise_on_error: false
+ expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/, cached gems or installed locally.")
end
end
- context "when an indirect dependency can't be found in the aggregate rubygems source", :bundler => "< 3" do
+ context "when an indirect dependency can't be found in the aggregate rubygems source", bundler: "< 3" do
before do
build_repo2
@@ -370,8 +544,16 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "fails" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include("Could not find gem 'missing', which is required by gem 'depends_on_missing', in any of the sources.")
+ bundle :install, artifice: "compact_index", raise_on_error: false
+ expect(err).to end_with <<~E.strip
+ Could not find compatible versions
+
+ Because every version of depends_on_missing depends on missing >= 0
+ and missing >= 0 could not be found in any of the sources,
+ depends_on_missing cannot be used.
+ So, because Gemfile depends on depends_on_missing >= 0,
+ version solving has failed.
+ E
end
end
@@ -406,11 +588,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the top-level source without warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2")
- expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote2")
+ expect(the_bundle).to include_gems("unrelated_gem 1.0.0", source: "remote3")
end
end
@@ -424,10 +606,16 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "does not find the dependency" do
- bundle :install, :artifice => "compact_index", :raise_on_error => false
- expect(err).to include(
- "Could not find gem 'rack', which is required by gem 'depends_on_rack', in rubygems repository https://gem.repo2/ or installed locally."
- )
+ bundle :install, artifice: "compact_index", raise_on_error: false
+ expect(err).to end_with <<~E.strip
+ Could not find compatible versions
+
+ Because every version of depends_on_rack depends on rack >= 0
+ and rack >= 0 could not be found in rubygems repository https://gem.repo2/, cached gems or installed locally,
+ depends_on_rack cannot be used.
+ So, because Gemfile depends on depends_on_rack >= 0,
+ version solving has failed.
+ E
end
end
@@ -445,12 +633,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the top-level source without warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
expect(run("require 'rack'; puts RACK")).to eq("1.0.0")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0")
- expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2")
- expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", source: "remote2")
+ expect(the_bundle).to include_gems("unrelated_gem 1.0.0", source: "remote3")
end
end
end
@@ -484,10 +672,10 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the top-level source" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0")
- expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote2")
- expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", :source => "remote3")
+ expect(the_bundle).to include_gems("rack 1.0.0", source: "remote2")
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", source: "remote3")
end
end
@@ -501,8 +689,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the pinned source" do
- bundle :install, :artifice => "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ bundle :install, artifice: "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
end
end
@@ -520,8 +708,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs the dependency from the pinned source without warning" do
- bundle :install, :artifice => "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
+ bundle :install, artifice: "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", source: "remote3")
end
end
end
@@ -595,6 +783,21 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
+ @locked_checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "activesupport", "6.0.3.4"
+ c.checksum gem_repo2, "concurrent-ruby", "1.1.8"
+ c.checksum gem_repo2, "connection_pool", "2.2.3"
+ c.checksum gem_repo2, "i18n", "1.8.9"
+ c.checksum gem_repo2, "minitest", "5.14.3"
+ c.checksum gem_repo2, "rack", "2.2.3"
+ c.checksum gem_repo2, "redis", "4.2.5"
+ c.checksum gem_repo2, "sidekiq", "6.1.3"
+ c.checksum gem_repo3, "sidekiq-pro", "5.2.1"
+ c.checksum gem_repo2, "thread_safe", "0.3.6"
+ c.checksum gem_repo2, "tzinfo", "1.2.9"
+ c.checksum gem_repo2, "zeitwerk", "2.4.2"
+ end
+
lockfile <<~L
GEM
remote: https://gem.repo2/
@@ -626,19 +829,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
zeitwerk (2.4.2)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activesupport
sidekiq-pro!
-
+ #{@locked_checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "does not install newer versions but updates the lockfile format when running bundle install in non frozen mode, and doesn't warn" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).to be_empty
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
@@ -682,22 +885,22 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activesupport
sidekiq-pro!
-
+ #{@locked_checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns", :bundler => "< 3" do
+ it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns", bundler: "< 3" do
initial_lockfile = lockfile
bundle "config set --local frozen true"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -711,11 +914,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(lockfile).to eq(initial_lockfile)
end
- it "fails when running bundle install in frozen mode", :bundler => "3" do
+ it "fails when running bundle install in frozen mode", bundler: "3" do
initial_lockfile = lockfile
bundle "config set --local frozen true"
- bundle :install, :artifice => "compact_index", :raise_on_error => false
+ bundle :install, artifice: "compact_index", raise_on_error: false
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -723,15 +926,21 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "splits sections and upgrades gems when running bundle update, and doesn't warn" do
- bundle "update --all", :artifice => "compact_index"
+ bundle "update --all", artifice: "compact_index"
expect(err).to be_empty
expect(the_bundle).not_to include_gems("activesupport 6.0.3.4")
expect(the_bundle).to include_gems("activesupport 6.1.2.1")
+ @locked_checksums.checksum gem_repo2, "activesupport", "6.1.2.1"
+
expect(the_bundle).not_to include_gems("tzinfo 1.2.9")
expect(the_bundle).to include_gems("tzinfo 2.0.4")
+ @locked_checksums.checksum gem_repo2, "tzinfo", "2.0.4"
+ @locked_checksums.delete "thread_safe"
+
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
+ @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9"
expect(lockfile).to eq <<~L
GEM
@@ -766,19 +975,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activesupport
sidekiq-pro!
-
+ #{@locked_checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "upgrades the lockfile format and upgrades the requested gem when running bundle update with an argument" do
- bundle "update concurrent-ruby", :artifice => "compact_index"
+ bundle "update concurrent-ruby", artifice: "compact_index"
expect(err).to be_empty
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
@@ -788,6 +997,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
+ @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9"
+
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo2/
@@ -822,12 +1033,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activesupport
sidekiq-pro!
-
+ #{@locked_checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -836,8 +1047,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved" do
before do
- build_lib "activesupport", "7.0.0.alpha", :path => lib_path("rails/activesupport")
- build_lib "rails", "7.0.0.alpha", :path => lib_path("rails") do |s|
+ build_lib "activesupport", "7.0.0.alpha", path: lib_path("rails/activesupport")
+ build_lib "rails", "7.0.0.alpha", path: lib_path("rails") do |s|
s.add_dependency "activesupport", "= 7.0.0.alpha"
end
@@ -859,11 +1070,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs all gems without warning" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", "rails 7.0.0.alpha")
- expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", :source => "path@#{lib_path("rails/activesupport")}")
- expect(the_bundle).to include_gems("rails 7.0.0.alpha", :source => "path@#{lib_path("rails")}")
+ expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", source: "path@#{lib_path("rails/activesupport")}")
+ expect(the_bundle).to include_gems("rails 7.0.0.alpha", source: "path@#{lib_path("rails")}")
end
end
@@ -895,6 +1106,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the default source without any warnings or errors and generates a proper lockfile" do
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo3, "handsoap", "0.2.5.5"
+ c.checksum gem_repo2, "nokogiri", "1.11.1"
+ c.checksum gem_repo2, "racca", "1.5.2"
+ end
+
expected_lockfile = <<~L
GEM
remote: https://gem.repo2/
@@ -910,30 +1127,30 @@ RSpec.describe "bundle install with gems on multiple sources" do
nokogiri (>= 1.2.3)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
handsoap!
nokogiri
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
- bundle "install --verbose", :artifice => "compact_index"
+ bundle "install --verbose", artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
- expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
- expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
+ expect(the_bundle).to include_gems("handsoap 0.2.5.5", source: "remote3")
+ expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", source: "remote2")
expect(lockfile).to eq(expected_lockfile)
# Even if the gems are already installed
FileUtils.rm bundled_app_lock
- bundle "install --verbose", :artifice => "compact_index"
+ bundle "install --verbose", artifice: "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
- expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
- expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
+ expect(the_bundle).to include_gems("handsoap 0.2.5.5", source: "remote3")
+ expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", source: "remote2")
expect(lockfile).to eq(expected_lockfile)
end
end
@@ -944,7 +1161,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "not_in_repo1", "1.0.0"
end
- install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index", raise_on_error: false
source "https://gem.repo3"
gem "not_in_repo1", :source => "https://gem.repo1"
G
@@ -957,7 +1174,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "with an existing lockfile" do
before do
- system_gems "rack-0.9.1", "rack-1.0.0", :path => default_bundle_path
+ system_gems "rack-0.9.1", "rack-1.0.0", path: default_bundle_path
lockfile <<-L
GEM
@@ -970,7 +1187,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
rack (0.9.1)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
rack!
@@ -1000,11 +1217,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
rack (0.9.1)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
rack!
-
+ #{checksums_section}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1022,7 +1239,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
rack (0.9.1)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
rack!
@@ -1047,20 +1264,48 @@ RSpec.describe "bundle install with gems on multiple sources" do
lockfile aggregate_gem_section_lockfile
end
- it "installs the existing lockfile but prints a warning", :bundler => "< 3" do
+ it "installs the existing lockfile but prints a warning when checksum validation is disabled", bundler: "< 3" do
bundle "config set --local deployment true"
+ bundle "config set --local disable_checksum_validation true"
- bundle "install", :artifice => "compact_index"
+ bundle "install", artifice: "compact_index"
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
- expect(the_bundle).to include_gems("rack 0.9.1", :source => "remote3")
+ expect(the_bundle).to include_gems("rack 0.9.1", source: "remote3")
end
- it "refuses to install the existing lockfile and prints an error", :bundler => "3" do
+ it "prints a checksum warning when the checksums from both sources do not match", bundler: "< 3" do
bundle "config set --local deployment true"
- bundle "install", :artifice => "compact_index", :raise_on_error =>false
+ bundle "install", artifice: "compact_index", raise_on_error: false
+
+ api_checksum1 = checksum_digest(gem_repo1, "rack", "0.9.1")
+ api_checksum3 = checksum_digest(gem_repo3, "rack", "0.9.1")
+
+ expect(exitstatus).to eq(37)
+ expect(err).to eq(<<~E.strip)
+ [DEPRECATED] Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure.
+ Bundler found mismatched checksums. This is a potential security risk.
+ rack (0.9.1) sha256=#{api_checksum3}
+ from the API at https://gem.repo3/
+ rack (0.9.1) sha256=#{api_checksum1}
+ from the API at https://gem.repo1/
+
+ Mismatched checksums each have an authoritative source:
+ 1. the API at https://gem.repo3/
+ 2. the API at https://gem.repo1/
+ You may need to alter your Gemfile sources to resolve this issue.
+
+ To ignore checksum security warnings, disable checksum validation with
+ `bundle config set --local disable_checksum_validation true`
+ E
+ end
+
+ it "refuses to install the existing lockfile and prints an error", bundler: "3" do
+ bundle "config set --local deployment true"
+
+ bundle "install", artifice: "compact_index", raise_on_error: false
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -1080,7 +1325,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "does not unlock the non-path gem after install" do
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
bundle %(exec ruby -e 'puts "OK"')
@@ -1093,7 +1338,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
before do
system_gems "rack-0.9.1"
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
gem "rack" # should come from repo1!
G
@@ -1122,7 +1367,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
bundle "config set --local path ../gems/system"
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
# And then we add some new versions...
update_repo4 do
@@ -1133,7 +1378,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "allows them to be unlocked separately" do
# And install this gemfile, updating only foo.
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source 'https://gem.repo1'
gem 'rack'
gem 'foo', '~> 0.2', :source => 'https://gem.repo4'
@@ -1157,7 +1402,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_git "git1"
build_git "git2"
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
gem "rails"
@@ -1173,7 +1418,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "does not re-resolve" do
- bundle :install, :artifice => "compact_index", :verbose => true
+ bundle :install, artifice: "compact_index", verbose: true
expect(out).to include("using resolution from the lockfile")
expect(out).not_to include("re-resolving dependencies")
end
@@ -1182,7 +1427,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a gem is installed to system gems" do
before do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
gem "rack"
G
@@ -1196,7 +1441,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
# When this gemfile is installed...
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
source "https://gem.repo4" do
@@ -1218,14 +1463,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
G
# But we should still be able to find rack 2.0.1.1.forked and install it
- bundle :install, :artifice => "compact_index"
+ bundle :install, artifice: "compact_index"
end
end
end
describe "source changed to one containing a higher version of a dependency" do
before do
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
gem "rack"
@@ -1239,11 +1484,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "bar"
end
- build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
+ build_lib("gemspec_test", path: tmp.join("gemspec_test")) do |s|
s.add_dependency "bar", "=1.0.0"
end
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo2"
gem "rack"
gemspec :path => "#{tmp.join("gemspec_test")}"
@@ -1261,11 +1506,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "bar"
end
- build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
+ build_lib("gemspec_test", path: tmp.join("gemspec_test")) do |s|
s.add_development_dependency "bar"
end
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo1"
source "https://gem.repo4" do
@@ -1290,7 +1535,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "example", "1.0.2"
end
- install_gemfile <<-G, :artifice => "compact_index"
+ install_gemfile <<-G, artifice: "compact_index"
source "https://gem.repo4"
gem "example", :source => "https://gem.repo2"
@@ -1299,14 +1544,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
bundle "info example"
expect(out).to include("example (0.1.0)")
- system_gems "example-1.0.2", :path => default_bundle_path, :gem_repo => gem_repo4
+ system_gems "example-1.0.2", path: default_bundle_path, gem_repo: gem_repo4
- bundle "update example --verbose", :artifice => "compact_index"
+ bundle "update example --verbose", artifice: "compact_index"
expect(out).not_to include("Using example 1.0.2")
expect(out).to include("Using example 0.1.0")
end
- it "fails inmmediately with a helpful error when a rubygems source does not exist and bundler/setup is required" do
+ it "fails immediately with a helpful error when a rubygems source does not exist and bundler/setup is required" do
gemfile <<-G
source "https://gem.repo1"
@@ -1315,17 +1560,15 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- simulate_bundler_version_when_missing_prerelease_default_gem_activation do
- ruby <<~R, :raise_on_error => false
- require 'bundler/setup'
- R
- end
+ ruby <<~R, raise_on_error: false
+ require 'bundler/setup'
+ R
expect(last_command).to be_failure
expect(err).to include("Could not find gem 'example' in locally installed gems.")
end
- it "fails inmmediately with a helpful error when a non retriable network error happens while resolving sources" do
+ it "fails immediately with a helpful error when a non retriable network error happens while resolving sources" do
gemfile <<-G
source "https://gem.repo1"
@@ -1334,13 +1577,13 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- bundle "install", :artifice => nil, :raise_on_error => false
+ bundle "install", artifice: nil, raise_on_error: false
expect(last_command).to be_failure
expect(err).to include("Could not reach host gem.repo4. Check your network connection and try again.")
end
- context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "< 3" do
+ context "when an indirect dependency is available from multiple ambiguous sources", bundler: "< 3" do
it "succeeds but warns, suggesting a source block" do
build_repo4 do
build_gem "depends_on_rack" do |s|
@@ -1349,7 +1592,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "rack"
end
- install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index", raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
source "https://gem.repo4" do
@@ -1360,7 +1603,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
gem "thin"
end
G
- expect(err).to eq strip_whitespace(<<-EOS).strip
+ expect(err).to eq <<~EOS.strip
Warning: The gem 'rack' was found in multiple relevant sources.
* rubygems repository https://gem.repo1/
* rubygems repository https://gem.repo4/
@@ -1371,7 +1614,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "3" do
+ context "when an indirect dependency is available from multiple ambiguous sources", bundler: "3" do
it "raises, suggesting a source block" do
build_repo4 do
build_gem "depends_on_rack" do |s|
@@ -1380,7 +1623,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "rack"
end
- install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ install_gemfile <<-G, artifice: "compact_index", raise_on_error: false
source "#{file_uri_for(gem_repo1)}"
source "https://gem.repo4" do
gem "depends_on_rack"
@@ -1390,7 +1633,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
expect(last_command).to be_failure
- expect(err).to eq strip_whitespace(<<-EOS).strip
+ expect(err).to eq <<~EOS.strip
The gem 'rack' was found in multiple relevant sources.
* rubygems repository https://gem.repo1/
* rubygems repository https://gem.repo4/
@@ -1434,16 +1677,23 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (3.3.1)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
+
+ CHECKSUMS
L
end
it "upgrades the lockfile correctly" do
- bundle "lock --update", :artifice => "compact_index"
+ bundle "lock --update", artifice: "compact_index"
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo2, "capybara", "2.5.0"
+ c.checksum gem_repo4, "mime-types", "3.0.0"
+ end
expect(lockfile).to eq <<~L
GEM
@@ -1458,12 +1708,70 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (3.0.0)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
+ #{checksums}
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ end
+ end
+
+ context "when default source includes old gems with nil required_ruby_version" do
+ before do
+ build_repo2 do
+ build_gem "ruport", "1.7.0.3" do |s|
+ s.add_dependency "pdf-writer", "1.1.8"
+ end
+ end
+
+ build_repo gem_repo4 do
+ build_gem "pdf-writer", "1.1.8"
+ end
+
+ path = "#{gem_repo4}/#{Gem::MARSHAL_SPEC_DIR}/pdf-writer-1.1.8.gemspec.rz"
+ spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path)))
+ spec.instance_variable_set(:@required_ruby_version, nil)
+ File.open(path, "wb") do |f|
+ f.write Gem.deflate(Marshal.dump(spec))
+ end
+
+ gemfile <<~G
+ source "https://localgemserver.test"
+
+ gem "ruport", "= 1.7.0.3", :source => "https://localgemserver.test/extra"
+ G
+ end
+
+ it "handles that fine" do
+ bundle "install", artifice: "compact_index_extra", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "pdf-writer", "1.1.8"
+ c.checksum gem_repo2, "ruport", "1.7.0.3"
+ end
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: https://localgemserver.test/
+ specs:
+ pdf-writer (1.1.8)
+
+ GEM
+ remote: https://localgemserver.test/extra/
+ specs:
+ ruport (1.7.0.3)
+ pdf-writer (= 1.1.8)
+
+ PLATFORMS
+ #{lockfile_platforms}
+
+ DEPENDENCIES
+ ruport (= 1.7.0.3)!
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1497,7 +1805,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
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 }
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "pdf-writer", "1.1.8"
+ c.checksum gem_repo2, "ruport", "1.7.0.3"
+ end
expect(lockfile).to eq <<~L
GEM
@@ -1512,11 +1825,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
pdf-writer (= 1.1.8)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
ruport (= 1.7.0.3)!
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1544,7 +1857,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
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 }
+
+ checksums = checksums_section_when_existing do |c|
+ c.checksum gem_repo4, "pdf-writer", "1.1.8"
+ end
expect(lockfile).to eq <<~L
GEM
@@ -1553,14 +1870,53 @@ RSpec.describe "bundle install with gems on multiple sources" do
pdf-writer (1.1.8)
PLATFORMS
- #{specific_local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
pdf-writer (= 1.1.8)
-
+ #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
end
+
+ context "when mistakenly adding a top level gem already depended on and cached under the wrong source" do
+ before do
+ build_repo4 do
+ build_gem "some_private_gem", "0.1.0" do |s|
+ s.add_dependency "example", "~> 1.0"
+ end
+ end
+
+ build_repo2 do
+ build_gem "example", "1.0.0"
+ end
+
+ install_gemfile <<~G, artifice: "compact_index"
+ source "https://gem.repo2"
+
+ source "https://gem.repo4" do
+ gem "some_private_gem"
+ end
+ G
+
+ gemfile <<~G
+ source "https://gem.repo2"
+
+ source "https://gem.repo4" do
+ gem "some_private_gem"
+ gem "example" # MISTAKE, example is not available at gem.repo4
+ end
+ G
+ end
+
+ it "shows a proper error message and does not generate a corrupted lockfile" do
+ expect do
+ bundle :install, artifice: "compact_index", raise_on_error: false, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ end.not_to change { lockfile }
+
+ expect(err).to include("Could not find gem 'example' in rubygems repository https://gem.repo4/")
+ end
+ end
end