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

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