Blame SOURCES/ruby-bundler-raise-error-in-dependency-confusion-tests.patch

a448a4
diff --git a/spec/bundler/bundler/definition_dep_confusion_spec.rb b/spec/bundler/bundler/definition_dep_confusion_spec.rb
a448a4
new file mode 100644
a448a4
index 0000000000..9fee464960
a448a4
--- /dev/null
a448a4
+++ b/spec/bundler/bundler/definition_dep_confusion_spec.rb
a448a4
@@ -0,0 +1,257 @@
a448a4
+# frozen_string_literal: true
a448a4
+
a448a4
+require "bundler/definition"
a448a4
+
a448a4
+RSpec.describe Bundler::Definition do
a448a4
+  before do
a448a4
+    allow(Bundler::SharedHelpers).to receive(:find_gemfile) { Pathname.new("Gemfile") }
a448a4
+  end
a448a4
+
a448a4
+  let(:sources) { Bundler::SourceList.new }
a448a4
+  subject { Bundler::Definition.new(nil, [], sources, []) }
a448a4
+
a448a4
+  describe "#validate_dependency_confusion!" do
a448a4
+    before do
a448a4
+      subject.instance_variable_set(:@remote, remote)
a448a4
+    end
a448a4
+
a448a4
+    context "when it's not remote" do
a448a4
+      let(:remote) { false }
a448a4
+
a448a4
+      it "should neither raise an error nor warn" do
a448a4
+        expect(subject).not_to receive(:raise_error_or_warn_dependency_confusion)
a448a4
+        subject.send(:validate_dependency_confusion!)
a448a4
+      end
a448a4
+    end
a448a4
+
a448a4
+    context "when it's remote" do
a448a4
+      before do
a448a4
+        allow(sources).to receive(:non_global_rubygems_sources).and_return(non_global_rubygems_sources)
a448a4
+      end
a448a4
+
a448a4
+      let(:remote) { true }
a448a4
+
a448a4
+      context "when the number of non-global source is zero" do
a448a4
+        let(:non_global_rubygems_sources) { [] }
a448a4
+
a448a4
+        it "should neither raise an error nor warn" do
a448a4
+          expect(subject).not_to receive(:raise_error_or_warn_dependency_confusion)
a448a4
+          subject.send(:validate_dependency_confusion!)
a448a4
+        end
a448a4
+      end
a448a4
+
a448a4
+      context "when there are any non dependency API non global sources" do
a448a4
+        let(:non_global_rubygems_sources) do
a448a4
+          [
a448a4
+            double("non-global-source-0", :dependency_api_available? => true, :to_s => "a"),
a448a4
+            double("non-global-source-1", :dependency_api_available? => false, :to_s => "b"),
a448a4
+            double("non-global-source-2", :dependency_api_available? => false, :to_s => "c"),
a448a4
+          ]
a448a4
+        end
a448a4
+
a448a4
+        it "should raise an error or warn" do
a448a4
+          expect(subject).to receive(:raise_error_or_warn_dependency_confusion).with(<<-M.strip)
a448a4
+Your Gemfile contains scoped sources that don't implement a dependency API, namely:
a448a4
+
a448a4
+  * b
a448a4
+  * c
a448a4
+
a448a4
+Using the above gem servers may result in installing unexpected gems. To resolve this warning, make sure you use gem servers that implement dependency APIs, such as gemstash or geminabox gem servers.
a448a4
+          M
a448a4
+          subject.send(:validate_dependency_confusion!)
a448a4
+        end
a448a4
+      end
a448a4
+
a448a4
+      context "when all the non global sources implement dependency API" do
a448a4
+        before do
a448a4
+          allow(subject).to receive(:indirect_dependency_names_in_non_global_rubygems_soruces).and_return(indirect_dependency_names)
a448a4
+          subject.instance_variable_set(:@index, index)
a448a4
+        end
a448a4
+
a448a4
+        let(:non_global_rubygems_sources) do
a448a4
+          [
a448a4
+            double("non-global-source-0", :dependency_api_available? => true, :to_s => "a"),
a448a4
+            double("non-global-source-1", :dependency_api_available? => true, :to_s => "b"),
a448a4
+          ]
a448a4
+        end
a448a4
+
a448a4
+        let(:index) { double("index", :sources => index_sources) }
a448a4
+        let(:index_sources) do
a448a4
+          [
a448a4
+            double("index-source-1", :spec_names => ["a1", "a2"]),
a448a4
+            double("index-source-2", :spec_names => ["a2", "b1", "b2"]),
a448a4
+            double("index-source-3", :spec_names => ["b2"])
a448a4
+          ]
a448a4
+        end
a448a4
+
a448a4
+        context "when there is not an indirect dependency in the non global sources" do
a448a4
+          let(:indirect_dependency_names) {[]}
a448a4
+
a448a4
+          it "should neither raise an error nor warn" do
a448a4
+            expect(subject).not_to receive(:raise_error_or_warn_dependency_confusion)
a448a4
+            subject.send(:validate_dependency_confusion!)
a448a4
+          end
a448a4
+        end
a448a4
+
a448a4
+        context "when there is an indirect dependency in the non global sources" do
a448a4
+
a448a4
+          context "when the indirect dependency doesn't exist in another source" do
a448a4
+            let(:indirect_dependency_names) {["a1", "b1"]}
a448a4
+
a448a4
+            it "should neither raise an error nor warn" do
a448a4
+              expect(subject).not_to receive(:raise_error_or_warn_dependency_confusion)
a448a4
+              subject.send(:validate_dependency_confusion!)
a448a4
+            end
a448a4
+          end
a448a4
+
a448a4
+          context "when the indirect dependency also exists in anotehr source" do
a448a4
+            let(:indirect_dependency_names) {["a1", "a2", "b2"]}
a448a4
+
a448a4
+            it "should raise an error or warn" do
a448a4
+              expect(subject).to receive(:raise_error_or_warn_dependency_confusion).with(<<-M.strip)
a448a4
+Your Gemfile contains implicit dependency gems a2, b2 on the scoped sources, namely:
a448a4
+
a448a4
+  * a
a448a4
+  * b
a448a4
+
a448a4
+Using implicit dependency gems on the above sources may result in installing unexpected gems. To suppress this message, make sure you set the gems explicitly in the Gemfile.
a448a4
+              M
a448a4
+              subject.send(:validate_dependency_confusion!)
a448a4
+            end
a448a4
+          end
a448a4
+        end
a448a4
+      end
a448a4
+    end
a448a4
+  end
a448a4
+
a448a4
+  describe "#indirect_dependency_names_in_non_global_rubygems_soruces" do
a448a4
+    before do
a448a4
+      subject.instance_variable_set(:@dependencies, dependencies)
a448a4
+      allow(sources).to receive(:non_global_rubygems_sources).and_return(non_global_rubygems_sources)
a448a4
+    end
a448a4
+
a448a4
+    # Direct dependencies
a448a4
+    let(:dependencies) do
a448a4
+      [
a448a4
+        double("dependency-0", :name => "g0"),
a448a4
+        double("dependency-1", :name => "g3")
a448a4
+      ]
a448a4
+    end
a448a4
+    let(:non_global_rubygems_sources) do
a448a4
+      [
a448a4
+        double("non-global-source-0", :specs => index_0, :to_s => "s0"),
a448a4
+        double("non-global-source-1", :specs => index_1, :to_s => "s1"),
a448a4
+      ]
a448a4
+    end
a448a4
+    let(:index_0) do
a448a4
+      # All the dependencies in the source-0.
a448a4
+      index = double("index-0", :dependency_names => ["g0", "g1", "g2", "g5"])
a448a4
+      allow(index).to receive(:local_search) do |query|
a448a4
+        return_map = {
a448a4
+          "g1" => [double("spec", :class => Bundler::StubSpecification, :to_s => "g1")],
a448a4
+          "g2" => [double("spec", :class => Bundler::EndpointSpecification, :to_s => "g2")],
a448a4
+          "g5" => [double("spec", :class => Bundler::EndpointSpecification, :to_s => "g5")]
a448a4
+        }
a448a4
+        return_map[query]
a448a4
+      end
a448a4
+      index
a448a4
+    end
a448a4
+    let(:index_1) do
a448a4
+      # All the dependencies in the source-1.
a448a4
+      index = double("index-1", :dependency_names => ["g3", "g4", "g5"])
a448a4
+      allow(index).to receive(:local_search) do |query|
a448a4
+        return_map = {
a448a4
+          "g4" => [double("spec", :class => Bundler::EndpointSpecification, :to_s => "g4")],
a448a4
+          "g5" => [double("spec", :class => Bundler::EndpointSpecification, :to_s => "g5")]
a448a4
+        }
a448a4
+        return_map[query]
a448a4
+      end
a448a4
+      index
a448a4
+    end
a448a4
+
a448a4
+    it "should return only indirect dependencies of endpoint specification" do
a448a4
+      expect(subject.send(:indirect_dependency_names_in_non_global_rubygems_soruces)).to eq(["g2", "g4", "g5"])
a448a4
+    end
a448a4
+  end
a448a4
+
a448a4
+  describe "#raise_error_or_warn_dependency_confusion" do
a448a4
+    before do
a448a4
+      allow(subject).to receive(:warn_on_dependnecy_confusion?).and_return(warn_on_dependnecy_confusion)
a448a4
+    end
a448a4
+
a448a4
+    context "when #warn_on_dependnecy_confusion? returns false" do
a448a4
+      let(:warn_on_dependnecy_confusion) { false }
a448a4
+
a448a4
+      it "should raise an error" do
a448a4
+        expect(Bundler.ui).not_to receive(:warn)
a448a4
+        expect do
a448a4
+          subject.send(:raise_error_or_warn_dependency_confusion, "This is a message.")
a448a4
+        end.to raise_error(Bundler::SecurityError, "This is a message. " \
a448a4
+          "Or set the environment variable BUNDLE_WARN_ON_DEPENDENCY_CONFUSION.")
a448a4
+      end
a448a4
+    end
a448a4
+
a448a4
+    context "when #warn_on_dependnecy_confusion? returns true" do
a448a4
+      let(:warn_on_dependnecy_confusion) { true }
a448a4
+
a448a4
+      it "should warn" do
a448a4
+        expect(Bundler.ui).to receive(:warn).with(<<-W.strip)
a448a4
+This is a message.
a448a4
+W
a448a4
+        subject.send(:raise_error_or_warn_dependency_confusion, "This is a message.")
a448a4
+      end
a448a4
+    end
a448a4
+  end
a448a4
+
a448a4
+  describe "#warn_on_dependnecy_confusion?" do
a448a4
+    context "when BUNDLE_WARN_ON_DEPENDENCY_CONFUSION is set" do
a448a4
+      it "should return true" do
a448a4
+        with_env({"BUNDLE_WARN_ON_DEPENDENCY_CONFUSION" => "1"}) do
a448a4
+          expect(subject.send(:warn_on_dependnecy_confusion?)).to be_truthy
a448a4
+        end
a448a4
+      end
a448a4
+    end
a448a4
+
a448a4
+    context "when BUNDLE_WARN_ON_DEPENDENCY_CONFUSION is not set" do
a448a4
+      it "should return false" do
a448a4
+        with_env({"BUNDLE_WARN_ON_DEPENDENCY_CONFUSION" => nil}) do
a448a4
+          expect(subject.send(:warn_on_dependnecy_confusion?)).to be_falsy
a448a4
+        end
a448a4
+      end
a448a4
+    end
a448a4
+  end
a448a4
+
a448a4
+  describe "#disable_dependency_confusion_check?" do
a448a4
+    context "when BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK is set" do
a448a4
+      it "should return true" do
a448a4
+        with_env({"BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK" => "1"}) do
a448a4
+          expect(subject.send(:disable_dependency_confusion_check?)).to be_truthy
a448a4
+        end
a448a4
+      end
a448a4
+    end
a448a4
+
a448a4
+    context "when BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK is not set" do
a448a4
+      it "should return false" do
a448a4
+        with_env({"BUNDLE_DISABLE_DEPENDENCY_CONFUSION_CHECK" => nil}) do
a448a4
+          expect(subject.send(:disable_dependency_confusion_check?)).to be_falsy
a448a4
+        end
a448a4
+      end
a448a4
+    end
a448a4
+  end
a448a4
+
a448a4
+  def with_env(env={})
a448a4
+    begin
a448a4
+      tmp_env = {}
a448a4
+      env.each do |key, value|
a448a4
+        tmp_env[key] = ENV.delete key
a448a4
+        ENV[key] = value
a448a4
+      end
a448a4
+
a448a4
+      yield
a448a4
+    ensure
a448a4
+      tmp_env.each do |key, value|
a448a4
+        ENV[key] = value
a448a4
+      end
a448a4
+    end
a448a4
+  end
a448a4
+end
a448a4
-- 
a448a4
2.31.1
a448a4