summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHomu <homu@barosl.com>2016-04-18 13:05:09 +0900
committerHomu <homu@barosl.com>2016-04-18 13:05:09 +0900
commit61f1c2313f5cc07fe389a2ec5d1931f8cc61b004 (patch)
tree39493b527a77e9817517cc663889561752a17984
parent9d2676ed2b9a58ff9251ff55210747c5a07ab201 (diff)
parent4d05a21c05f7dce6f932ebbce7705fd7fbab324a (diff)
downloadbundler-61f1c2313f5cc07fe389a2ec5d1931f8cc61b004.tar.gz
Auto merge of #4425 - RochesterinNYC:print-sanitized-urls-for-git-sources, r=segiddins
Print sanitized urls with removed credentials for git sources on `bundle install` If your environment includes `user1:password1` for your `GITHUB_CREDENTIALS` and you have something like the following in your `Gemfile`: ``` git "https://#{ENV['GITHUB_CREDENTIALS']}:x-oauth-basic@github.com/company/private-repo" do gem 'be_excellent', ref: '83623' end ``` the output for `bundle install` is: ``` bundle Using be_excellent 0.0.1 from https://user1:password1@github.com/company/private-repo (at master@53534b2) ``` This PR sanitizes this output and removes the credentials so the output would be: ``` bundle Using be_excellent 0.0.1 from https://github.com/company/private-repo (at master@53534b2) ``` - Also handles oauth tokens (ex. `https://oauth_token:x-oauth-basic@github.com/company/private-repo`) Related to: bundler/bundler-features#111
-rw-r--r--lib/bundler.rb1
-rw-r--r--lib/bundler/source/git/git_proxy.rb14
-rw-r--r--lib/bundler/uri_credentials_filter.rb36
-rw-r--r--spec/bundler/uri_credentials_filter_spec.rb127
-rw-r--r--spec/install/gemfile/git_spec.rb34
5 files changed, 207 insertions, 5 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 8288f839e1..ace1e7f3c4 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -52,6 +52,7 @@ module Bundler
autoload :SourceList, "bundler/source_list"
autoload :RubyGemsGemInstaller, "bundler/rubygems_gem_installer"
autoload :UI, "bundler/ui"
+ autoload :URICredentialsFilter, "bundler/uri_credentials_filter"
class << self
attr_writer :bundle_path
diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb
index 19e0db86fa..9b0e95d18c 100644
--- a/lib/bundler/source/git/git_proxy.rb
+++ b/lib/bundler/source/git/git_proxy.rb
@@ -86,12 +86,12 @@ module Bundler
def checkout
if path.exist?
return if has_revision_cached?
- Bundler.ui.info "Fetching #{uri}"
+ Bundler.ui.info "Fetching #{URICredentialsFilter.credential_filtered_uri(uri)}"
in_path do
git_retry %(fetch --force --quiet --tags #{uri_escaped_with_configured_credentials} "refs/heads/*:refs/heads/*")
end
else
- Bundler.ui.info "Fetching #{uri}"
+ Bundler.ui.info "Fetching #{URICredentialsFilter.credential_filtered_uri(uri)}"
SharedHelpers.filesystem_access(path.dirname) do |p|
FileUtils.mkdir_p(p)
end
@@ -145,10 +145,14 @@ module Bundler
end
def git(command, check_errors = true, error_msg = nil)
- raise GitNotAllowedError.new(command) unless allow?
+ command_with_no_credentials = URICredentialsFilter.credential_filtered_string(command, uri)
+ raise GitNotAllowedError.new(command_with_no_credentials) unless allow?
+
out = SharedHelpers.with_clean_git_env { `git #{command}` }
- raise GitCommandError.new(command, path, error_msg) if check_errors && !$?.success?
- out
+
+ stdout_with_no_credentials = URICredentialsFilter.credential_filtered_string(out, uri)
+ raise GitCommandError.new(command_with_no_credentials, path, error_msg) if check_errors && !$?.success?
+ stdout_with_no_credentials
end
def has_revision_cached?
diff --git a/lib/bundler/uri_credentials_filter.rb b/lib/bundler/uri_credentials_filter.rb
new file mode 100644
index 0000000000..997a307533
--- /dev/null
+++ b/lib/bundler/uri_credentials_filter.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+module Bundler
+ module URICredentialsFilter
+ module_function
+
+ def credential_filtered_uri(uri_to_anonymize)
+ return uri_to_anonymize if uri_to_anonymize.nil?
+ uri = uri_to_anonymize.dup
+ uri = URI(uri.to_s) unless uri.is_a?(URI)
+ if uri.userinfo
+ # oauth authentication
+ if uri.password == "x-oauth-basic" || uri.password == "x"
+ # URI as string does not display with password if no user is set
+ oauth_designation = uri.password
+ uri.user = oauth_designation
+ end
+ uri.password = nil
+ end
+ return uri if uri_to_anonymize.is_a?(URI)
+ return uri.to_s if uri_to_anonymize.is_a?(String)
+ rescue URI::InvalidURIError # uri is not canonical uri scheme
+ uri
+ end
+
+ def credential_filtered_string(str_to_filter, uri)
+ return str_to_filter if uri.nil? || str_to_filter.nil?
+ str_with_no_credentials = str_to_filter.dup
+ anonymous_uri_str = credential_filtered_uri(uri).to_s
+ uri_str = uri.to_s
+ if anonymous_uri_str != uri_str
+ str_with_no_credentials = str_with_no_credentials.gsub(uri_str, anonymous_uri_str)
+ end
+ str_with_no_credentials
+ end
+ end
+end
diff --git a/spec/bundler/uri_credentials_filter_spec.rb b/spec/bundler/uri_credentials_filter_spec.rb
new file mode 100644
index 0000000000..b890c0ce5f
--- /dev/null
+++ b/spec/bundler/uri_credentials_filter_spec.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+require "spec_helper"
+
+describe Bundler::URICredentialsFilter do
+ subject { described_class }
+
+ describe "#credential_filtered_uri" do
+ shared_examples_for "original type of uri is maintained" do
+ it "maintains same type for return value as uri input type" do
+ expect(subject.credential_filtered_uri(uri)).to be_kind_of(uri.class)
+ end
+ end
+
+ shared_examples_for "sensitive credentials in uri are filtered out" do
+ context "authentication using oauth credentials" do
+ context "specified via 'x-oauth-basic'" do
+ let(:credentials) { "oauth_token:x-oauth-basic@" }
+
+ it "returns the uri without the oauth token" do
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(URI("https://x-oauth-basic@github.com/company/private-repo").to_s)
+ end
+
+ it_behaves_like "original type of uri is maintained"
+ end
+
+ context "specified via 'x'" do
+ let(:credentials) { "oauth_token:x@" }
+
+ it "returns the uri without the oauth token" do
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(URI("https://x@github.com/company/private-repo").to_s)
+ end
+
+ it_behaves_like "original type of uri is maintained"
+ end
+ end
+
+ context "authentication using login credentials" do
+ let(:credentials) { "username1:hunter3@" }
+
+ it "returns the uri without the password" do
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(URI("https://username1@github.com/company/private-repo").to_s)
+ end
+
+ it_behaves_like "original type of uri is maintained"
+ end
+
+ context "authentication without credentials" do
+ let(:credentials) { "" }
+
+ it "returns the same uri" do
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(uri.to_s)
+ end
+
+ it_behaves_like "original type of uri is maintained"
+ end
+ end
+
+ context "uri is a uri object" do
+ let(:uri) { URI("https://#{credentials}github.com/company/private-repo") }
+
+ it_behaves_like "sensitive credentials in uri are filtered out"
+ end
+
+ context "uri is a uri string" do
+ let(:uri) { "https://#{credentials}github.com/company/private-repo" }
+
+ it_behaves_like "sensitive credentials in uri are filtered out"
+ end
+
+ context "uri is a non-uri format string (ex. path)" do
+ let(:uri) { "/path/to/repo" }
+
+ it "returns the same uri" do
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(uri.to_s)
+ end
+
+ it_behaves_like "original type of uri is maintained"
+ end
+
+ context "uri is nil" do
+ let(:uri) { nil }
+
+ it "returns nil" do
+ expect(subject.credential_filtered_uri(uri)).to be_nil
+ end
+
+ it_behaves_like "original type of uri is maintained"
+ end
+ end
+
+ describe "#credential_filtered_string" do
+ let(:str_to_filter) { "This is a git message containing a uri #{uri}!" }
+ let(:credentials) { "" }
+ let(:uri) { URI("https://#{credentials}github.com/company/private-repo") }
+
+ context "with a uri that contains credentials" do
+ let(:credentials) { "oauth_token:x-oauth-basic@" }
+
+ it "returns the string without the sensitive credentials" do
+ expect(subject.credential_filtered_string(str_to_filter, uri)).to eq(
+ "This is a git message containing a uri https://x-oauth-basic@github.com/company/private-repo!")
+ end
+ end
+
+ context "that does not contains credentials" do
+ it "returns the same string" do
+ expect(subject.credential_filtered_string(str_to_filter, uri)).to eq(str_to_filter)
+ end
+ end
+
+ context "string to filter is nil" do
+ let(:str_to_filter) { nil }
+
+ it "returns nil" do
+ expect(subject.credential_filtered_string(str_to_filter, uri)).to be_nil
+ end
+ end
+
+ context "uri to filter out is nil" do
+ let(:uri) { nil }
+
+ it "returns the same string" do
+ expect(subject.credential_filtered_string(str_to_filter, uri)).to eq(str_to_filter)
+ end
+ end
+ end
+end
diff --git a/spec/install/gemfile/git_spec.rb b/spec/install/gemfile/git_spec.rb
index 5081d35fa7..2cb62b424e 100644
--- a/spec/install/gemfile/git_spec.rb
+++ b/spec/install/gemfile/git_spec.rb
@@ -1102,4 +1102,38 @@ describe "bundle install with git sources" do
end
end
end
+
+ context "git sources that include credentials" do
+ context "that are username and password" do
+ let(:credentials) { "user1:password1" }
+
+ it "does not display the password" do
+ install_gemfile <<-G, :expect_err => true
+ git "https://#{credentials}@github.com/company/private-repo" do
+ gem "foo"
+ end
+ G
+
+ bundle :install, :expect_err => true
+ expect(out).to_not include("password1")
+ expect(out).to include("Fetching https://user1@github.com/company/private-repo")
+ end
+ end
+
+ context "that is an oauth token" do
+ let(:credentials) { "oauth_token" }
+
+ it "displays the oauth scheme but not the oauth token" do
+ install_gemfile <<-G, :expect_err => true
+ git "https://#{credentials}:x-oauth-basic@github.com/company/private-repo" do
+ gem "foo"
+ end
+ G
+
+ bundle :install, :expect_err => true
+ expect(out).to_not include("oauth_token")
+ expect(out).to include("Fetching https://x-oauth-basic@github.com/company/private-repo")
+ end
+ end
+ end
end