[rubygems/rubygems] Diagnose the bundler connection
https://github.com/rubygems/rubygems/commit/0aae094c89
This commit is contained in:
parent
ae308ae523
commit
cba7408017
@ -1,5 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "uri"
|
||||||
|
|
||||||
module Bundler
|
module Bundler
|
||||||
class CLI::Doctor::SSL
|
class CLI::Doctor::SSL
|
||||||
attr_reader :options
|
attr_reader :options
|
||||||
@ -12,6 +14,7 @@ module Bundler
|
|||||||
return unless openssl_installed?
|
return unless openssl_installed?
|
||||||
|
|
||||||
output_ssl_environment
|
output_ssl_environment
|
||||||
|
bundler_success = bundler_connection_successful?
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -32,6 +35,10 @@ module Bundler
|
|||||||
@verify_mode ||= mode.then {|mod| OpenSSL::SSL.const_get("verify_#{mod}".upcase) }
|
@verify_mode ||= mode.then {|mod| OpenSSL::SSL.const_get("verify_#{mod}".upcase) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def uri
|
||||||
|
@uri ||= URI("https://#{host}")
|
||||||
|
end
|
||||||
|
|
||||||
def openssl_installed?
|
def openssl_installed?
|
||||||
require "openssl"
|
require "openssl"
|
||||||
|
|
||||||
@ -55,5 +62,38 @@ module Bundler
|
|||||||
MESSAGE
|
MESSAGE
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bundler_connection_successful?
|
||||||
|
Bundler.ui.info("\nTrying connections to #{uri}:\n")
|
||||||
|
|
||||||
|
bundler_uri = Gem::URI(uri.to_s)
|
||||||
|
Bundler::Fetcher.new(
|
||||||
|
Bundler::Source::Rubygems::Remote.new(bundler_uri)
|
||||||
|
).send(:connection).request(bundler_uri)
|
||||||
|
|
||||||
|
Bundler.ui.info("Bundler: success")
|
||||||
|
|
||||||
|
true
|
||||||
|
rescue StandardError => error
|
||||||
|
Bundler.ui.warn("Bundler: failed (#{Explanation.explain_bundler_or_rubygems_error(error)})")
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
module Explanation
|
||||||
|
extend self
|
||||||
|
|
||||||
|
def explain_bundler_or_rubygems_error(error)
|
||||||
|
case error.message
|
||||||
|
when /certificate verify failed/
|
||||||
|
"certificate verification"
|
||||||
|
when /read server hello A/
|
||||||
|
"SSL/TLS protocol version mismatch"
|
||||||
|
when /tlsv1 alert protocol version/
|
||||||
|
"requested TLS version is too old"
|
||||||
|
else
|
||||||
|
error.message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -15,8 +15,6 @@ begin
|
|||||||
rescue LoadError
|
rescue LoadError
|
||||||
end
|
end
|
||||||
|
|
||||||
uri = URI("https://#{host}")
|
|
||||||
|
|
||||||
if defined?(RUBY_DESCRIPTION)
|
if defined?(RUBY_DESCRIPTION)
|
||||||
ruby_version = RUBY_DESCRIPTION
|
ruby_version = RUBY_DESCRIPTION
|
||||||
else
|
else
|
||||||
@ -45,30 +43,6 @@ def show_ssl_certs
|
|||||||
puts
|
puts
|
||||||
end
|
end
|
||||||
|
|
||||||
def error_reason(error)
|
|
||||||
case error.message
|
|
||||||
when /certificate verify failed/
|
|
||||||
"certificate verification"
|
|
||||||
when /read server hello A/
|
|
||||||
"SSL/TLS protocol version mismatch"
|
|
||||||
when /tlsv1 alert protocol version/
|
|
||||||
"requested TLS version is too old"
|
|
||||||
else
|
|
||||||
error.message
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "Trying connections to #{uri.to_s}:"
|
|
||||||
puts
|
|
||||||
begin
|
|
||||||
b_uri = defined?(Bundler::URI) ? Bundler::URI(uri.to_s) : uri
|
|
||||||
Bundler::Fetcher.new(Bundler::Source::Rubygems::Remote.new(b_uri)).send(:connection).request(b_uri)
|
|
||||||
bundler_status = "✅ success"
|
|
||||||
rescue => error
|
|
||||||
bundler_status = "❌ failed (#{error_reason(error)})"
|
|
||||||
end
|
|
||||||
puts "Bundler: #{bundler_status}"
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
require 'rubygems/remote_fetcher'
|
require 'rubygems/remote_fetcher'
|
||||||
Gem::RemoteFetcher.fetcher.fetch_path(uri)
|
Gem::RemoteFetcher.fetcher.fetch_path(uri)
|
||||||
|
@ -3,16 +3,28 @@
|
|||||||
require "bundler/cli"
|
require "bundler/cli"
|
||||||
require "bundler/cli/doctor"
|
require "bundler/cli/doctor"
|
||||||
require "bundler/cli/doctor/ssl"
|
require "bundler/cli/doctor/ssl"
|
||||||
|
require_relative "../support/artifice/helpers/artifice"
|
||||||
|
require "bundler/vendored_persistent.rb"
|
||||||
|
|
||||||
RSpec.describe "bundle doctor ssl" do
|
RSpec.describe "bundle doctor ssl" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
|
require_rack
|
||||||
|
require_relative "../support/artifice/helpers/endpoint"
|
||||||
|
|
||||||
|
@dummy_endpoint = Class.new(Endpoint) do
|
||||||
|
get "/" do
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@previous_level = Bundler.ui.level
|
@previous_level = Bundler.ui.level
|
||||||
Bundler.ui.instance_variable_get(:@warning_history).clear
|
Bundler.ui.instance_variable_get(:@warning_history).clear
|
||||||
Bundler.ui.level = "info"
|
Bundler.ui.level = "info"
|
||||||
|
Artifice.activate_with(@dummy_endpoint)
|
||||||
end
|
end
|
||||||
|
|
||||||
after(:each) do
|
after(:each) do
|
||||||
Bundler.ui.level = @previous_level
|
Bundler.ui.level = @previous_level
|
||||||
|
Artifice.deactivate
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when a diagnostic fails" do
|
context "when a diagnostic fails" do
|
||||||
@ -27,6 +39,63 @@ RSpec.describe "bundle doctor ssl" do
|
|||||||
|
|
||||||
expect { subject.run }.to output("").to_stdout.and output(expected_err).to_stderr
|
expect { subject.run }.to output("").to_stdout.and output(expected_err).to_stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "fails due to certificate verification" do
|
||||||
|
net_http = Class.new(Artifice::Net::HTTP) do
|
||||||
|
def connect
|
||||||
|
raise OpenSSL::SSL::SSLError, "certificate verify failed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Artifice.replace_net_http(net_http)
|
||||||
|
|
||||||
|
expected_out = <<~MSG
|
||||||
|
Here's your OpenSSL environment:
|
||||||
|
|
||||||
|
OpenSSL: #{OpenSSL::VERSION}
|
||||||
|
Compiled with: #{OpenSSL::OPENSSL_VERSION}
|
||||||
|
Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
|
||||||
|
|
||||||
|
Trying connections to https://rubygems.org:
|
||||||
|
MSG
|
||||||
|
|
||||||
|
expected_err = <<~MSG
|
||||||
|
Bundler: failed (certificate verification)
|
||||||
|
|
||||||
|
MSG
|
||||||
|
|
||||||
|
subject = Bundler::CLI::Doctor::SSL.new({})
|
||||||
|
expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails due to a too old tls version" do
|
||||||
|
subject = Bundler::CLI::Doctor::SSL.new({})
|
||||||
|
|
||||||
|
net_http = Class.new(Artifice::Net::HTTP) do
|
||||||
|
def connect
|
||||||
|
raise OpenSSL::SSL::SSLError, "read server hello A"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Artifice.replace_net_http(net_http)
|
||||||
|
|
||||||
|
expected_out = <<~MSG
|
||||||
|
Here's your OpenSSL environment:
|
||||||
|
|
||||||
|
OpenSSL: #{OpenSSL::VERSION}
|
||||||
|
Compiled with: #{OpenSSL::OPENSSL_VERSION}
|
||||||
|
Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
|
||||||
|
|
||||||
|
Trying connections to https://rubygems.org:
|
||||||
|
MSG
|
||||||
|
|
||||||
|
expected_err = <<~MSG
|
||||||
|
Bundler: failed (SSL/TLS protocol version mismatch)
|
||||||
|
|
||||||
|
MSG
|
||||||
|
|
||||||
|
expect { subject.run }.to output(expected_out).to_stdout.and output(expected_err).to_stderr
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when no diagnostic fails" do
|
context "when no diagnostic fails" do
|
||||||
@ -37,6 +106,10 @@ RSpec.describe "bundle doctor ssl" do
|
|||||||
OpenSSL: #{OpenSSL::VERSION}
|
OpenSSL: #{OpenSSL::VERSION}
|
||||||
Compiled with: #{OpenSSL::OPENSSL_VERSION}
|
Compiled with: #{OpenSSL::OPENSSL_VERSION}
|
||||||
Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
|
Loaded with: #{OpenSSL::OPENSSL_LIBRARY_VERSION}
|
||||||
|
|
||||||
|
Trying connections to https://rubygems.org:
|
||||||
|
Bundler: success
|
||||||
|
|
||||||
MSG
|
MSG
|
||||||
|
|
||||||
subject = Bundler::CLI::Doctor::SSL.new({})
|
subject = Bundler::CLI::Doctor::SSL.new({})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user