[前][次][番号順一覧][スレッド一覧]

ruby-changes:54962

From: hsbt <ko1@a...>
Date: Tue, 5 Mar 2019 12:33:06 +0900 (JST)
Subject: [ruby-changes:54962] hsbt:r67168 (trunk): Merge RubyGems upstream: 56c0bbb69e4506bda7ef7f447dfec5db820df20b

hsbt	2019-03-05 12:32:58 +0900 (Tue, 05 Mar 2019)

  New Revision: 67168

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=67168

  Log:
    Merge RubyGems upstream: 56c0bbb69e4506bda7ef7f447dfec5db820df20b
    
      It fixed the multiple vulnerabilities.
      https://blog.rubygems.org/2019/03/05/security-advisories-2019-03.html

  Modified files:
    trunk/lib/rubygems/command_manager.rb
    trunk/lib/rubygems/commands/install_command.rb
    trunk/lib/rubygems/commands/owner_command.rb
    trunk/lib/rubygems/commands/push_command.rb
    trunk/lib/rubygems/commands/update_command.rb
    trunk/lib/rubygems/commands/yank_command.rb
    trunk/lib/rubygems/dependency_list.rb
    trunk/lib/rubygems/gemcutter_utilities.rb
    trunk/lib/rubygems/installer.rb
    trunk/lib/rubygems/installer_test_case.rb
    trunk/lib/rubygems/package.rb
    trunk/lib/rubygems/requirement.rb
    trunk/lib/rubygems/resolver/activation_request.rb
    trunk/lib/rubygems/test_case.rb
    trunk/lib/rubygems/test_utilities.rb
    trunk/lib/rubygems/user_interaction.rb
    trunk/test/rubygems/test_gem.rb
    trunk/test/rubygems/test_gem_command_manager.rb
    trunk/test/rubygems/test_gem_commands_install_command.rb
    trunk/test/rubygems/test_gem_commands_owner_command.rb
    trunk/test/rubygems/test_gem_commands_push_command.rb
    trunk/test/rubygems/test_gem_commands_update_command.rb
    trunk/test/rubygems/test_gem_commands_yank_command.rb
    trunk/test/rubygems/test_gem_indexer.rb
    trunk/test/rubygems/test_gem_installer.rb
    trunk/test/rubygems/test_gem_package.rb
    trunk/test/rubygems/test_gem_requirement.rb
    trunk/test/rubygems/test_gem_specification.rb
    trunk/test/rubygems/test_gem_text.rb
Index: lib/rubygems/resolver/activation_request.rb
===================================================================
--- lib/rubygems/resolver/activation_request.rb	(revision 67167)
+++ lib/rubygems/resolver/activation_request.rb	(revision 67168)
@@ -77,7 +77,7 @@ class Gem::Resolver::ActivationRequest https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/activation_request.rb#L77
   # The full name of the specification to be activated.
 
   def full_name
-    @spec.full_name
+    name_tuple.full_name
   end
 
   alias_method :to_s, :full_name
@@ -183,4 +183,17 @@ class Gem::Resolver::ActivationRequest https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/activation_request.rb#L183
     @spec.version
   end
 
+  ##
+  # The platform of this activation request's specification
+
+  def platform
+    @spec.platform
+  end
+
+  private
+
+  def name_tuple
+    @name_tuple ||= Gem::NameTuple.new(name, version, platform)
+  end
+
 end
Index: lib/rubygems/command_manager.rb
===================================================================
--- lib/rubygems/command_manager.rb	(revision 67167)
+++ lib/rubygems/command_manager.rb	(revision 67168)
@@ -7,6 +7,7 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/command_manager.rb#L7
 
 require 'rubygems/command'
 require 'rubygems/user_interaction'
+require 'rubygems/text'
 
 ##
 # The command manager registers and installs all the individual sub-commands
@@ -32,6 +33,7 @@ require 'rubygems/user_interaction' https://github.com/ruby/ruby/blob/trunk/lib/rubygems/command_manager.rb#L33
 
 class Gem::CommandManager
 
+  include Gem::Text
   include Gem::UserInteraction
 
   BUILTIN_COMMANDS = [ # :nodoc:
@@ -145,12 +147,12 @@ class Gem::CommandManager https://github.com/ruby/ruby/blob/trunk/lib/rubygems/command_manager.rb#L147
   def run(args, build_args=nil)
     process_args(args, build_args)
   rescue StandardError, Timeout::Error => ex
-    alert_error "While executing gem ... (#{ex.class})\n    #{ex}"
+    alert_error clean_text("While executing gem ... (#{ex.class})\n    #{ex}")
     ui.backtrace ex
 
     terminate_interaction(1)
   rescue Interrupt
-    alert_error "Interrupted"
+    alert_error clean_text("Interrupted")
     terminate_interaction(1)
   end
 
@@ -167,8 +169,14 @@ class Gem::CommandManager https://github.com/ruby/ruby/blob/trunk/lib/rubygems/command_manager.rb#L169
     when '-v', '--version' then
       say Gem::VERSION
       terminate_interaction 0
+    when '--no-ri', '--no-rdoc' then
+      # This was added to compensate for a deprecation warning not being shown
+      # in Rubygems 2.x.x.
+      # TODO: Remove when Rubygems 3.1 is released.
+      alert_error "Invalid option: #{args.first}. Use --no-document instead."
+      terminate_interaction 1
     when /^-/ then
-      alert_error "Invalid option: #{args.first}. See 'gem --help'."
+      alert_error clean_text("Invalid option: #{args.first}. See 'gem --help'.")
       terminate_interaction 1
     else
       cmd_name = args.shift.downcase
@@ -224,7 +232,7 @@ class Gem::CommandManager https://github.com/ruby/ruby/blob/trunk/lib/rubygems/command_manager.rb#L232
     rescue Exception => e
       e = load_error if load_error
 
-      alert_error "Loading command: #{command_name} (#{e.class})\n\t#{e}"
+      alert_error clean_text("Loading command: #{command_name} (#{e.class})\n\t#{e}")
       ui.backtrace e
     end
   end
Index: lib/rubygems/dependency_list.rb
===================================================================
--- lib/rubygems/dependency_list.rb	(revision 67167)
+++ lib/rubygems/dependency_list.rb	(revision 67168)
@@ -135,7 +135,7 @@ class Gem::DependencyList https://github.com/ruby/ruby/blob/trunk/lib/rubygems/dependency_list.rb#L135
   end
 
   ##
-  # Is is ok to remove a gemspec from the dependency list?
+  # It is ok to remove a gemspec from the dependency list?
   #
   # If removing the gemspec creates breaks a currently ok dependency, then it
   # is NOT ok to remove the gemspec.
Index: lib/rubygems/test_case.rb
===================================================================
--- lib/rubygems/test_case.rb	(revision 67167)
+++ lib/rubygems/test_case.rb	(revision 67168)
@@ -134,6 +134,12 @@ class Gem::TestCase < (defined?(Minitest https://github.com/ruby/ruby/blob/trunk/lib/rubygems/test_case.rb#L134
     assert File.exist?(path), msg
   end
 
+  def assert_directory_exists(path, msg = nil)
+    msg = message(msg) { "Expected path '#{path}' to be a directory" }
+    assert_path_exists path
+    assert File.directory?(path), msg
+  end
+
   ##
   # Sets the ENABLE_SHARED entry in RbConfig::CONFIG to +value+ and restores
   # the original value when the block ends
Index: lib/rubygems/user_interaction.rb
===================================================================
--- lib/rubygems/user_interaction.rb	(revision 67167)
+++ lib/rubygems/user_interaction.rb	(revision 67168)
@@ -7,6 +7,7 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/user_interaction.rb#L7
 
 require 'rubygems/util'
 require 'rubygems/deprecate'
+require 'rubygems/text'
 
 ##
 # Module that defines the default UserInteraction.  Any class including this
@@ -14,6 +15,8 @@ require 'rubygems/deprecate' https://github.com/ruby/ruby/blob/trunk/lib/rubygems/user_interaction.rb#L15
 
 module Gem::DefaultUserInteraction
 
+  include Gem::Text
+
   ##
   # The default UI is a class variable of the singleton class for this
   # module.
@@ -162,7 +165,7 @@ module Gem::UserInteraction https://github.com/ruby/ruby/blob/trunk/lib/rubygems/user_interaction.rb#L165
   # is true.
 
   def verbose(msg = nil)
-    say(msg || yield) if Gem.configuration.really_verbose
+    say(clean_text(msg || yield)) if Gem.configuration.really_verbose
   end
 end
 
Index: lib/rubygems/installer_test_case.rb
===================================================================
--- lib/rubygems/installer_test_case.rb	(revision 67167)
+++ lib/rubygems/installer_test_case.rb	(revision 67168)
@@ -120,9 +120,9 @@ class Gem::InstallerTestCase < Gem::Test https://github.com/ruby/ruby/blob/trunk/lib/rubygems/installer_test_case.rb#L120
   # The executable is also written to the bin dir in @tmpdir and the installed
   # gem directory for +spec+.
 
-  def util_make_exec(spec = @spec, shebang = "#!/usr/bin/ruby")
+  def util_make_exec(spec = @spec, shebang = "#!/usr/bin/ruby", bindir = "bin")
     spec.executables = %w[executable]
-    spec.files << 'bin/executable'
+    spec.bindir = bindir
 
     exec_path = spec.bin_file "executable"
     write_file exec_path do |io|
Index: lib/rubygems/gemcutter_utilities.rb
===================================================================
--- lib/rubygems/gemcutter_utilities.rb	(revision 67167)
+++ lib/rubygems/gemcutter_utilities.rb	(revision 67168)
@@ -1,11 +1,14 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/gemcutter_utilities.rb#L1
 # frozen_string_literal: true
 require 'rubygems/remote_fetcher'
+require 'rubygems/text'
 
 ##
 # Utility methods for using the RubyGems API.
 
 module Gem::GemcutterUtilities
 
+  include Gem::Text
+
   # TODO: move to Gem::Command
   OptionParser.accept Symbol do |value|
     value.to_sym
@@ -94,8 +97,22 @@ module Gem::GemcutterUtilities https://github.com/ruby/ruby/blob/trunk/lib/rubygems/gemcutter_utilities.rb#L97
     uri = URI.parse "#{self.host}/#{path}"
 
     request_method = Net::HTTP.const_get method.to_s.capitalize
+    response = Gem::RemoteFetcher.fetcher.request(uri, request_method, &block)
+    return response unless mfa_unauthorized?(response)
+
+    Gem::RemoteFetcher.fetcher.request(uri, request_method) do |req|
+      req.add_field "OTP", get_otp
+      block.call(req)
+    end
+  end
 
-    Gem::RemoteFetcher.fetcher.request(uri, request_method, &block)
+  def mfa_unauthorized?(response)
+    response.kind_of?(Net::HTTPUnauthorized) && response.body.start_with?('You have enabled multifactor authentication')
+  end
+
+  def get_otp
+    say 'You have enabled multi-factor authentication. Please enter OTP code.'
+    ask 'Code: '
   end
 
   ##
@@ -123,13 +140,7 @@ module Gem::GemcutterUtilities https://github.com/ruby/ruby/blob/trunk/lib/rubygems/gemcutter_utilities.rb#L140
     response = rubygems_api_request(:get, "api/v1/api_key",
                                     sign_in_host) do |request|
       request.basic_auth email, password
-    end
-
-    if need_otp? response
-      response = rubygems_api_request(:get, "api/v1/api_key", sign_in_host) do |request|
-        request.basic_auth email, password
-        request.add_field "OTP", options[:otp]
-      end
+      request.add_field "OTP", options[:otp] if options[:otp]
     end
 
     with_response response do |resp|
@@ -164,30 +175,24 @@ module Gem::GemcutterUtilities https://github.com/ruby/ruby/blob/trunk/lib/rubygems/gemcutter_utilities.rb#L175
       if block_given?
         yield response
       else
-        say response.body
+        say clean_text(response.body)
       end
     else
       message = response.body
       message = "#{error_prefix}: #{message}" if error_prefix
 
-      say message
+      say clean_text(message)
       terminate_interaction 1 # TODO: question this
     end
   end
 
   ##
   # Returns true when the user has enabled multifactor authentication from
-  # +response+ text.
+  # +response+ text and no otp provided by options.
+
+
 
-  def need_otp?(response)
-    return unless response.kind_of?(Net::HTTPUnauthorized) &&
-        response.body.start_with?('You have enabled multifactor authentication')
-    return true if options[:otp]
 
-    say 'You have enabled multi-factor authentication. Please enter OTP code.'
-    options[:otp] = ask 'Code: '
-    true
-  end
 
   def set_api_key(host, key)
     if host == Gem::DEFAULT_HOST
Index: lib/rubygems/commands/owner_command.rb
===================================================================
--- lib/rubygems/commands/owner_command.rb	(revision 67167)
+++ lib/rubygems/commands/owner_command.rb	(revision 67168)
@@ -2,9 +2,11 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/owner_command.rb#L2
 require 'rubygems/command'
 require 'rubygems/local_remote_options'
 require 'rubygems/gemcutter_utilities'
+require 'rubygems/text'
 
 class Gem::Commands::OwnerCommand < Gem::Command
 
+  include Gem::Text
   include Gem::LocalRemoteOptions
   include Gem::GemcutterUtilities
 
@@ -68,7 +70,7 @@ permission to. https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/owner_command.rb#L70
     end
 
     with_response response do |resp|
-      owners = Gem::SafeYAML.load resp.body
+      owners = Gem::SafeYAML.load clean_text(resp.body)
 
       say "Owners for gem: #{name}"
       owners.each do |owner|
@@ -89,11 +91,6 @@ permission to. https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/owner_command.rb#L91
     owners.each do |owner|
       begin
         response = send_owner_request(method, name, owner)
-
-        if need_otp? response
-          response = send_owner_request(method, name, owner, true)
-        end
-
         action = method == :delete ? "Removing" : "Adding"
 
         with_response response, "#{action} #{owner}"
@@ -105,11 +102,11 @@ permission to. https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/owner_command.rb#L102
 
   private
 
-  def send_owner_request(method, name, owner, use_otp = false)
+  def send_owner_request(method, name, owner)
     rubygems_api_request method, "api/v1/gems/#{name}/owners" do |request|
       request.set_form_data 'email' => owner
       request.add_field "Authorization", api_key
-      request.add_field "OTP", options[:otp] if use_otp
+      request.add_field "OTP", options[:otp] if options[:otp]
     end
   end
 
Index: lib/rubygems/commands/install_command.rb
===================================================================
--- lib/rubygems/commands/install_command.rb	(revision 67167)
+++ lib/rubygems/commands/install_command.rb	(revision 67168)
@@ -194,65 +194,21 @@ You can use `i` command instead of `inst https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/install_command.rb#L194
 
     req = Gem::Requirement.create(version)
 
-    if options[:ignore_dependencies]
-      install_gem_without_dependencies name, req
-    else
-      inst = Gem::DependencyInstaller.new options
-      request_set = inst.resolve_dependencies name, req
-
-      if options[:explain]
-        say "Gems to install:"
-
-        request_set.sorted_requests.each do |s|
-          # shows platform specific gems if used
-          say (plat = s.spec.platform) == Gem::Platform::RUBY ?
-            "  #{s.full_name}" :
-            "  #{s.full_name}-#{plat}"
-        end
-
-        return
-      else
-        @installed_specs.concat request_set.install options
-      end
+    dinst = Gem::DependencyInstaller.new options
 
-      show_install_errors inst.errors
-    end
-  end
+    request_set = dinst.resolve_dependencies name, req
 
-  def install_gem_without_dependencies(name, req) # :nodoc:
-    gem = nil
+    if options[:explain]
+      say "Gems to install:"
 
-    if local?
-      if name =~ /\.gem$/ and File.file? name
-        source = Gem::Source::SpecificFile.new name
-        spec = source.spec
-      else
-        source = Gem::Source::Local.new
-        spec = source.find_gem name, req
+      request_set.sorted_requests.each do |activation_request|
+        say "  #{activation_request.full_name}"
       end
-      gem = source.download spec if spec
-    end
-
-    if remote? and not gem
-      dependency = Gem::Dependency.new name, req
-      dependency.prerelease = options[:prerelease]
-
-      fetcher = Gem::RemoteFetcher.fetcher
-      gem = fetcher.download_to_cache dependency
+    else
+      @installed_specs.concat request_set.install options
     end
 
-    inst = Gem::Installer.at gem, options
-    inst.install
-
-    require 'rubygems/dependency_installer'
-    dinst = Gem::DependencyInstaller.new options
-    dinst.installed_gems.replace [inst.spec]
-
-    Gem.done_installing_hooks.each do |hook|
-      hook.call dinst, [inst.spec]
-    end unless Gem.done_installing_hooks.empty?
-
-    @installed_specs.push(inst.spec)
+    show_install_errors dinst.errors
   end
 
   def install_gems # :nodoc:
Index: lib/rubygems/commands/push_command.rb
===================================================================
--- lib/rubygems/commands/push_command.rb	(revision 67167)
+++ lib/rubygems/commands/push_command.rb	(revision 67168)
@@ -119,22 +119,18 @@ You can upgrade or downgrade to the late https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/push_command.rb#L119
 
     response = send_push_request(name, args)
 
-    if need_otp? response
-      response = send_push_request(name, args, true)
-    end
-
     with_response response
   end
 
   private
 
-  def send_push_request(name, args, use_otp = false)
+  def send_push_request(name, args)
     rubygems_api_request(*args) do |request|
       request.body = Gem.read_binary name
       request.add_field "Content-Length", request.body.size
       request.add_field "Content-Type",   "application/octet-stream"
       request.add_field "Authorization",  api_key
-      request.add_field "OTP", options[:otp] if use_otp
+      request.add_field "OTP", options[:otp] if options[:otp]
     end
   end
 
Index: lib/rubygems/commands/yank_command.rb
===================================================================
--- lib/rubygems/commands/yank_command.rb	(revision 67167)
+++ lib/rubygems/commands/yank_command.rb	(revision 67168)
@@ -33,6 +33,7 @@ data you will need to change them immedi https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/yank_command.rb#L33
 
     add_version_option("remove")
     add_platform_option("remove")
+    add_otp_option
 
     add_option('--host HOST',
                'Yank from another gemcutter-compatible host',
@@ -62,7 +63,10 @@ data you will need to change them immedi https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/yank_command.rb#L63
 
   def yank_gem(version, platform)
     say "Yanking gem from #{self.host}..."
-    yank_api_request(:delete, version, platform, "api/v1/gems/yank")
+    args = [:delete, version, platform, "api/v1/gems/yank"]
+    response = yank_api_request(*args)
+
+    say response.body
   end
 
   private
@@ -71,6 +75,7 @@ data you will need to change them immedi https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/yank_command.rb#L75
     name = get_one_gem_name
     response = rubygems_api_request(method, api, host) do |request|
       request.add_field("Authorization", api_key)
+      request.add_field("OTP", options[:otp]) if options[:otp]
 
       data = {
         'gem_name' => name,
@@ -80,7 +85,7 @@ data you will need to change them immedi https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/yank_command.rb#L85
 
       request.set_form_data data
     end
-    say response.body
+    response
   end
 
   def get_version_from_requirements(requirements)
Index: lib/rubygems/commands/update_command.rb
===================================================================
--- lib/rubygems/commands/update_command.rb	(revision 67167)
+++ lib/rubygems/commands/update_command.rb	(revision 67168)
@@ -97,8 +97,8 @@ command to remove old versions. https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/update_command.rb#L97
     if options[:explain]
       say "Gems to update:"
 
-      gems_to_update.each do |(name, version)|
-        say "  #{name}-#{version}"
+      gems_to_update.each do |name_tuple|
+        say "  #{name_tuple.full_name}"
       end
 
       return
@@ -146,18 +146,18 @@ command to remove old versions. https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/update_command.rb#L146
     hig
   end
 
-  def highest_remote_version(spec) # :nodoc:
+  def highest_remote_name_tuple(spec) # :nodoc:
     spec_tuples = fetch_remote_gems spec
 
     matching_gems = spec_tuples.select do |g,_|
       g.name == spec.name and g.match_platform?
     end
 
-    highest_remote_gem = matching_gems.max_by { |g,_| g.version }
+    highest_remote_gem = matching_gems.max
 
     highest_remote_gem ||= [Gem::NameTuple.null]
 
-    highest_remote_gem.first.version
+    highest_remote_gem.first
   end
 
   def install_rubygems(version) # :nodoc:
@@ -194,7 +194,7 @@ command to remove old versions. https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/update_command.rb#L194
     }
 
     gems_to_update = which_to_update hig, options[:args], :system
-    _, up_ver = gems_to_update.first
+    up_ver = gems_to_update.first.version
 
     target = if update_latest
                up_ver
@@ -226,8 +226,8 @@ command to remove old versions. https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/update_command.rb#L226
   end
 
   def update_gems(gems_to_update)
-    gems_to_update.uniq.sort.each do |(name, version)|
-      update_gem name, version
+    gems_to_update.uniq.sort.each do |name_tuple|
+      update_gem name_tuple.name, name_tuple.version
     end
 
     @updated
@@ -271,10 +271,12 @@ command to remove old versions. https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/update_command.rb#L271
       next if not gem_names.empty? and
               gem_names.none? { |name| name == l_spec.name }
 
-      highest_remote_ver = highest_remote_version l_spec
+      highest_remote_tup = highest_remote_name_tuple l_spec
+      highest_remote_ver = highest_remote_tup.version
+      highest_installed_ver = l_spec.version
 
-      if system or (l_spec.version < highest_remote_ver)
-        result << [l_spec.name, [l_spec.version, highest_remote_ver].max]
+      if system or (highest_installed_ver < highest_remote_ver)
+        result << Gem::NameTuple.new(l_spec.name, [highest_installed_ver, highest_remote_ver].max, highest_remote_tup.platform)
       end
     end
 
Index: lib/rubygems/requirement.rb
================================================ (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]