summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Bundler Bot <bot@bundler.io>2017-08-12 14:18:37 +0000
committerThe Bundler Bot <bot@bundler.io>2017-08-12 14:18:37 +0000
commit76b251b03dc7ffea7e45bd3c6ea2c75ebf5c523d (patch)
treea06b933bec92f4eba2ada03e2e829602d67686b9
parent66facbb67665f30e97db2b2c4c9c127399e9a935 (diff)
parentc9c4f23e46673ac953b34774934447c779b25e0b (diff)
downloadbundler-76b251b03dc7ffea7e45bd3c6ea2c75ebf5c523d.tar.gz
Auto merge of #5658 - adrian-gomez:passowrds_on_remotes, r=segiddins
Allow to add username and password to a remote during a deployment This is my first PR to bundler, so if something is out of place let me know and I'll do my best to correct it. The issue I'm trying to fix is allowing to change a remote on a frozen bundler for the same remote adding username and password. In our dev boxes we have configured bundle to store the username and password for a given domain, but on our qa boxes we don't want to do that for various reasons. As far as I can tell this should not have any negative side effects as we are keeping the same remote but only adding some auth to it
-rw-r--r--.rubocop.yml3
-rw-r--r--lib/bundler/definition.rb12
-rw-r--r--lib/bundler/settings.rb1
-rw-r--r--lib/bundler/source.rb4
-rw-r--r--lib/bundler/source/path.rb4
-rw-r--r--lib/bundler/source/rubygems.rb16
-rw-r--r--lib/bundler/source_list.rb32
-rw-r--r--man/bundle-config.ronn3
-rw-r--r--spec/install/deploy_spec.rb76
9 files changed, 140 insertions, 11 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index d1241ec52f..f12289800a 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -100,6 +100,9 @@ Style/TrailingCommaInArguments:
Performance/FlatMap:
Enabled: false
+Security/YAMLLoad:
+ Enabled: false
+
# Metrics
# We've chosen to use Rubocop only for style, and not for complexity or quality checks.
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 19f1c1c929..fea66f4245 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -410,8 +410,8 @@ module Bundler
# Check if it is possible that the source is only changed thing
if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
- new_sources.reject! {|source| source.is_a_path? && source.path.exist? }
- deleted_sources.reject! {|source| source.is_a_path? && source.path.exist? }
+ new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
+ deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
end
if @locked_sources != gemfile_sources
@@ -639,7 +639,7 @@ module Bundler
if !locked_gem_sources.empty? && !actual_remotes.empty?
locked_gem_sources.each do |locked_gem|
# Merge the remotes from the Gemfile into the Gemfile.lock
- changes |= locked_gem.replace_remotes(actual_remotes)
+ changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes])
end
end
@@ -967,5 +967,11 @@ module Bundler
requirements
end.values
end
+
+ def equivalent_rubygems_remotes?(source)
+ return false unless source.is_a?(Source::Rubygems)
+
+ Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
+ end
end
end
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index a23264ecf4..d19cc18dd6 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -10,6 +10,7 @@ module Bundler
BOOL_KEYS = %w[
allow_bundler_dependency_conflicts
+ allow_deployment_source_credential_changes
allow_offline_install
auto_install
cache_all
diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb
index 48f73d960e..38e001535c 100644
--- a/lib/bundler/source.rb
+++ b/lib/bundler/source.rb
@@ -46,6 +46,10 @@ module Bundler
"#<#{self.class}:0x#{object_id} #{self}>"
end
+ def path?
+ instance_of?(Bundler::Source::Path)
+ end
+
private
def version_color(spec_version, locked_spec_version)
diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb
index 310a30f1ec..806ba81935 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -116,10 +116,6 @@ module Bundler
Bundler.root
end
- def is_a_path?
- instance_of?(Path)
- end
-
def expanded_original_path
@expanded_original_path ||= expand(original_path)
end
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index 511216a5c5..70dc5ac038 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -219,13 +219,21 @@ module Bundler
@remotes.unshift(uri) unless @remotes.include?(uri)
end
- def replace_remotes(other_remotes)
+ def equivalent_remotes?(other_remotes)
+ other_remotes.map(&method(:remove_auth)) == @remotes.map(&method(:remove_auth))
+ end
+
+ def replace_remotes(other_remotes, allow_equivalent = false)
return false if other_remotes == @remotes
+ equivalent = allow_equivalent && equivalent_remotes?(other_remotes)
+
@remotes = []
other_remotes.reverse_each do |r|
add_remote r.to_s
end
+
+ !equivalent
end
def unmet_deps
@@ -297,7 +305,7 @@ module Bundler
end
def suppress_configured_credentials(remote)
- remote_nouser = remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s
+ remote_nouser = remove_auth(remote)
if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser]
remote_nouser
else
@@ -305,6 +313,10 @@ module Bundler
end
end
+ def remove_auth(remote)
+ remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s
+ end
+
def installed_specs
@installed_specs ||= Index.build do |idx|
Bundler.rubygems.all_specs.reverse_each do |spec|
diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb
index dd5a07afd7..ac2adacb3d 100644
--- a/lib/bundler/source_list.rb
+++ b/lib/bundler/source_list.rb
@@ -73,7 +73,7 @@ module Bundler
end
def get(source)
- source_list_for(source).find {|s| source == s }
+ source_list_for(source).find {|s| equal_source?(source, s) || equivalent_source?(source, s) }
end
def lock_sources
@@ -101,7 +101,7 @@ module Bundler
replacement_sources.detect {|s| s.is_a?(Source::Rubygems) }
@rubygems_aggregate = replacement_rubygems if replacement_rubygems
- return true if lock_sources.to_set != replacement_sources.to_set
+ return true if !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources)
return true if replacement_rubygems && rubygems_remotes.to_set != replacement_rubygems.remotes.to_set
false
@@ -154,5 +154,33 @@ module Bundler
"protocol to keep your data secure."
end
end
+
+ def equal_sources?(lock_sources, replacement_sources)
+ lock_sources.to_set == replacement_sources.to_set
+ end
+
+ def equal_source?(source, other_source)
+ source == other_source
+ end
+
+ def equivalent_source?(source, other_source)
+ return false unless Bundler.settings[:allow_deployment_source_credential_changes] && source.is_a?(Source::Rubygems)
+
+ equivalent_rubygems_sources?([source], [other_source])
+ end
+
+ def equivalent_sources?(lock_sources, replacement_sources)
+ return false unless Bundler.settings[:allow_deployment_source_credential_changes]
+
+ lock_rubygems_sources, lock_other_sources = lock_sources.partition {|s| s.is_a?(Source::Rubygems) }
+ replacement_rubygems_sources, replacement_other_sources = replacement_sources.partition {|s| s.is_a?(Source::Rubygems) }
+
+ equivalent_rubygems_sources?(lock_rubygems_sources, replacement_rubygems_sources) && equal_sources?(lock_other_sources, replacement_other_sources)
+ end
+
+ def equivalent_rubygems_sources?(lock_sources, replacement_sources)
+ actual_remotes = replacement_sources.map(&:remotes).flatten.uniq
+ lock_sources.all? {|s| s.equivalent_remotes?(actual_remotes) }
+ end
end
end
diff --git a/man/bundle-config.ronn b/man/bundle-config.ronn
index 8e5e776a98..32cc640f60 100644
--- a/man/bundle-config.ronn
+++ b/man/bundle-config.ronn
@@ -121,6 +121,9 @@ learn more about their operation in [bundle install(1)][bundle-install].
* `allow_bundler_dependency_conflicts` (`BUNDLE_ALLOW_BUNDLER_DEPENDENCY_CONFLICTS`):
Allow resolving to specifications that have dependencies on `bundler` that
are incompatible with the running Bundler version.
+* `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`):
+ When in deployment mode, allow changing the credentials to a gem's source.
+ Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path`
* `allow_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`):
Allow Bundler to use cached data when installing without network access.
* `auto_install` (`BUNDLE_AUTO_INSTALL`):
diff --git a/spec/install/deploy_spec.rb b/spec/install/deploy_spec.rb
index 11cf38a577..de812b5e65 100644
--- a/spec/install/deploy_spec.rb
+++ b/spec/install/deploy_spec.rb
@@ -295,6 +295,82 @@ RSpec.describe "install with --deployment or --frozen" do
expect(out).not_to include("You have deleted from the Gemfile")
end
+ context "when replacing a host with the same host with credentials" do
+ let(:success_message) do
+ if Bundler::VERSION.split(".", 2).first == "1"
+ "Could not reach host localgemserver.test"
+ else
+ "Bundle complete!"
+ end
+ end
+
+ before do
+ install_gemfile <<-G
+ source "http://user_name:password@localgemserver.test/"
+ gem "rack"
+ G
+
+ lockfile <<-G
+ GEM
+ remote: http://localgemserver.test/
+ specs:
+ rack (1.0.0)
+
+ PLATFORMS
+ #{local}
+
+ DEPENDENCIES
+ rack
+ G
+ end
+
+ it "prevents the replace by default" do
+ bundle :install, forgotten_command_line_options(:deployment => true)
+
+ expect(out).to match(/The list of sources changed/)
+ end
+
+ context "when allow_deployment_source_credential_changes is true" do
+ before { bundle! "config allow_deployment_source_credential_changes true" }
+
+ it "allows the replace" do
+ bundle :install, forgotten_command_line_options(:deployment => true)
+
+ expect(out).to match(/#{success_message}/)
+ end
+ end
+
+ context "when allow_deployment_source_credential_changes is false" do
+ before { bundle! "config allow_deployment_source_credential_changes false" }
+
+ it "prevents the replace" do
+ bundle :install, forgotten_command_line_options(:deployment => true)
+
+ expect(out).to match(/The list of sources changed/)
+ end
+ end
+
+ context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is true" do
+ before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "true" }
+
+ it "allows the replace" do
+ bundle :install, forgotten_command_line_options(:deployment => true)
+
+ expect(out).to match(/#{success_message}/)
+ end
+ end
+
+ context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is false" do
+ before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "false" }
+
+ it "prevents the replace" do
+ bundle :install, forgotten_command_line_options(:deployment => true)
+
+ expect(out).to match(/The list of sources changed/)
+ end
+ end
+ end
+
it "remembers that the bundle is frozen at runtime" do
bundle! :lock