Rubygems: apply upstream patch to fix multiple vulnerabilities
authorAntonio Terceiro <terceiro@debian.org>
Sat, 24 Feb 2018 15:15:36 +0000 (12:15 -0300)
committerAntonio Terceiro <terceiro@debian.org>
Sun, 4 Mar 2018 16:30:49 +0000 (16:30 +0000)
https://www.ruby-lang.org/en/news/2018/02/17/multiple-vulnerabilities-in-rubygems/
https://blog.rubygems.org/2018/02/15/2.7.6-released.html

Gbp-Pq: Name 0006-Rubygems-apply-upstream-patch-to-fix-multiple-vulner.patch

58 files changed:
lib/rubygems.rb
lib/rubygems/commands/generate_index_command.rb
lib/rubygems/commands/owner_command.rb
lib/rubygems/commands/setup_command.rb
lib/rubygems/commands/unpack_command.rb
lib/rubygems/config_file.rb
lib/rubygems/ext/builder.rb
lib/rubygems/indexer.rb
lib/rubygems/installer.rb
lib/rubygems/package.rb
lib/rubygems/package/file_source.rb
lib/rubygems/package/old.rb
lib/rubygems/package/tar_header.rb
lib/rubygems/package/tar_writer.rb
lib/rubygems/request_set/lockfile.rb
lib/rubygems/security.rb
lib/rubygems/security/trust_dir.rb
lib/rubygems/server.rb
lib/rubygems/source.rb
lib/rubygems/specification.rb
lib/rubygems/stub_specification.rb
lib/rubygems/test_case.rb
lib/rubygems/test_utilities.rb
lib/rubygems/util.rb
lib/rubygems/validator.rb
test/rubygems/test_gem.rb
test/rubygems/test_gem_commands_cleanup_command.rb
test/rubygems/test_gem_commands_install_command.rb
test/rubygems/test_gem_commands_owner_command.rb
test/rubygems/test_gem_commands_push_command.rb
test/rubygems/test_gem_commands_setup_command.rb
test/rubygems/test_gem_commands_uninstall_command.rb
test/rubygems/test_gem_dependency_installer.rb
test/rubygems/test_gem_doctor.rb
test/rubygems/test_gem_ext_builder.rb
test/rubygems/test_gem_gem_runner.rb
test/rubygems/test_gem_gemcutter_utilities.rb
test/rubygems/test_gem_indexer.rb
test/rubygems/test_gem_install_update_options.rb
test/rubygems/test_gem_installer.rb
test/rubygems/test_gem_package.rb
test/rubygems/test_gem_package_old.rb
test/rubygems/test_gem_package_tar_header.rb
test/rubygems/test_gem_rdoc.rb
test/rubygems/test_gem_remote_fetcher.rb
test/rubygems/test_gem_request_set.rb
test/rubygems/test_gem_request_set_lockfile.rb
test/rubygems/test_gem_request_set_lockfile_parser.rb
test/rubygems/test_gem_request_set_lockfile_tokenizer.rb
test/rubygems/test_gem_resolver_git_specification.rb
test/rubygems/test_gem_server.rb
test/rubygems/test_gem_source.rb
test/rubygems/test_gem_source_git.rb
test/rubygems/test_gem_specification.rb
test/rubygems/test_gem_stub_specification.rb
test/rubygems/test_gem_util.rb
test/rubygems/test_gem_version.rb
test/rubygems/test_require.rb

index 0475ced164e91c1eb64895d15631421e20ebd760..2762bfcb88b1cfbff01b673134c30c34b395d1d0 100644 (file)
@@ -10,7 +10,7 @@ require 'rbconfig'
 require 'thread'
 
 module Gem
-  VERSION = "2.7.3"
+  VERSION = "2.7.6"
 end
 
 # Must be first since it unloads the prelude from 1.9.2
@@ -161,7 +161,7 @@ module Gem
   # these are defined in Ruby 1.8.7, hence the need for this convoluted setup.
 
   READ_BINARY_ERRORS = begin
-    read_binary_errors = [Errno::EACCES, Errno::EROFS]
+    read_binary_errors = [Errno::EACCES, Errno::EROFS, Errno::ENOSYS]
     read_binary_errors << Errno::ENOTSUP if Errno.const_defined?(:ENOTSUP)
     read_binary_errors
   end.freeze
@@ -171,7 +171,7 @@ module Gem
   # these are defined in Ruby 1.8.7.
 
   WRITE_BINARY_ERRORS = begin
-    write_binary_errors = []
+    write_binary_errors = [Errno::ENOSYS]
     write_binary_errors << Errno::ENOTSUP if Errno.const_defined?(:ENOTSUP)
     write_binary_errors
   end.freeze
@@ -871,19 +871,19 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
   # Safely read a file in binary mode on all platforms.
 
   def self.read_binary(path)
-    open path, 'rb+' do |f|
+    File.open path, 'rb+' do |f|
       f.flock(File::LOCK_EX)
       f.read
     end
   rescue *READ_BINARY_ERRORS
-    open path, 'rb' do |f|
+    File.open path, 'rb' do |f|
       f.read
     end
   rescue Errno::ENOLCK # NFS
     if Thread.main != Thread.current
       raise
     else
-      open path, 'rb' do |f|
+      File.open path, 'rb' do |f|
         f.read
       end
     end
index 01f1f88405d76977429f7f1376f131dab4356056..0b677b73a9567b82f957842ede78a2877bbe4005 100644 (file)
@@ -68,7 +68,7 @@ Marshal::MINOR_VERSION constants.  It is used to ensure compatibility.
 
     if not File.exist?(options[:directory]) or
        not File.directory?(options[:directory]) then
-      alert_error "unknown directory name #{directory}."
+      alert_error "unknown directory name #{options[:directory]}."
       terminate_interaction 1
     else
       indexer = Gem::Indexer.new options.delete(:directory), options
index 8e2271657a95436e623706499bf600a0ccc97417..637b5bdc4dfe6a6f83cb20a97d4bc712114c9016 100644 (file)
@@ -64,7 +64,7 @@ permission to.
     end
 
     with_response response do |resp|
-      owners = YAML.load resp.body
+      owners = Gem::SafeYAML.load resp.body
 
       say "Owners for gem: #{name}"
       owners.each do |owner|
index 5d1414d10203d929b980f0a4e7489845acf8c607..6966cde01a3f85c844ba8dc0162d355f4ef3b1d8 100644 (file)
@@ -350,7 +350,9 @@ By default, this RubyGems will install gem as:
   def install_default_bundler_gem
     return unless Gem::USE_BUNDLER_FOR_GEMDEPS
 
-    mkdir_p Gem::Specification.default_specifications_dir
+    specs_dir = Gem::Specification.default_specifications_dir
+    File.join(options[:destdir], specs_dir) unless Gem.win_platform?
+    mkdir_p specs_dir
 
     # Workaround for non-git environment.
     gemspec = File.open('bundler/bundler.gemspec', 'rb'){|f| f.read.gsub(/`git ls-files -z`/, "''") }
@@ -359,23 +361,36 @@ By default, this RubyGems will install gem as:
     bundler_spec = Gem::Specification.load("bundler/bundler.gemspec")
     bundler_spec.files = Dir.chdir("bundler") { Dir["{*.md,{lib,exe,man}/**/*}"] }
     bundler_spec.executables -= %w[bundler bundle_ruby]
-    Dir.entries(Gem::Specification.default_specifications_dir).
+
+    # Remove bundler-*.gemspec in default specification directory.
+    Dir.entries(specs_dir).
       select {|gs| gs.start_with?("bundler-") }.
-      each {|gs| File.delete(File.join(Gem::Specification.default_specifications_dir, gs)) }
+      each {|gs| File.delete(File.join(specs_dir, gs)) }
 
-    default_spec_path = File.join(Gem::Specification.default_specifications_dir, "#{bundler_spec.full_name}.gemspec")
+    default_spec_path = File.join(specs_dir, "#{bundler_spec.full_name}.gemspec")
     Gem.write_binary(default_spec_path, bundler_spec.to_ruby)
 
     bundler_spec = Gem::Specification.load(default_spec_path)
 
+    # Remove gemspec that was same version of vendored bundler.
+    normal_gemspec = File.join(Gem.default_dir, "specifications", "bundler-#{bundler_spec.version}.gemspec")
+    if File.file? normal_gemspec
+      File.delete normal_gemspec
+    end
+
+    # Remove gem files that were same version of vendored bundler.
     if File.directory? bundler_spec.gems_dir
       Dir.entries(bundler_spec.gems_dir).
-        select {|default_gem| File.basename(default_gem).match(/^bundler-#{Gem::Version::VERSION_PATTERN}$/) }.
+        select {|default_gem| File.basename(default_gem) == "bundler-#{bundler_spec.version}" }.
         each {|default_gem| rm_r File.join(bundler_spec.gems_dir, default_gem) }
     end
 
-    mkdir_p bundler_spec.bin_dir
-    bundler_spec.executables.each {|e| cp File.join("bundler", bundler_spec.bindir, e), File.join(bundler_spec.bin_dir, e) }
+    bundler_bin_dir = File.join(Gem.default_dir, 'gems', bundler_spec.full_name, bundler_spec.bindir)
+    File.join(options[:destdir], bundler_bin_dir) unless Gem.win_platform?
+    mkdir_p bundler_bin_dir
+    bundler_spec.executables.each do |e|
+      cp File.join("bundler", bundler_spec.bindir, e), File.join(bundler_bin_dir, e)
+    end
 
     if Gem.win_platform?
       require 'rubygems/installer'
index eb7f550673e710b837cc547e0e010047ba89a007..b873f20d280da2d33c3b9a867b459616cdf04004 100644 (file)
@@ -94,7 +94,7 @@ command help for an example.
 
         spec_file = File.basename spec.spec_file
 
-        open spec_file, 'w' do |io|
+        File.open spec_file, 'w' do |io|
           io.write metadata
         end
       else
@@ -176,7 +176,7 @@ command help for an example.
 
     metadata = nil
 
-    open path, Gem.binary_mode do |io|
+    File.open path, Gem.binary_mode do |io|
       tar = Gem::Package::TarReader.new io
       tar.each_entry do |entry|
         case entry.full_name
index a4efed0f5ab8f511359363c54e52d541d87044ea..c0d19dbfc273d2662fe2da1960f1ae7371b5e941 100644 (file)
@@ -458,7 +458,7 @@ if you believe they were disclosed to a third party.
 
   # Writes out this config file, replacing its source.
   def write
-    open config_file_name, 'w' do |io|
+    File.open config_file_name, 'w' do |io|
       io.write to_yaml
     end
   end
index a1619c97d7031e3b91fac2a9984ac28f0ed5d24a..eb9db199d56fcf20ab7fd71934fc3fd7b894ad8b 100644 (file)
@@ -212,7 +212,7 @@ EOF
 
     FileUtils.mkdir_p @spec.extension_dir
 
-    open destination, 'wb' do |io| io.puts output end
+    File.open destination, 'wb' do |io| io.puts output end
 
     destination
   end
index 871cc09d8d8ef466ad212bfda59a5218e2b3a1eb..3ea994414bef7f7df15014020c705d19e070fe14 100644 (file)
@@ -2,6 +2,7 @@
 require 'rubygems'
 require 'rubygems/package'
 require 'time'
+require 'tmpdir'
 
 begin
   gem 'builder'
@@ -64,7 +65,7 @@ class Gem::Indexer
     @build_modern = options[:build_modern]
 
     @dest_directory = directory
-    @directory = File.join(Dir.tmpdir, "gem_generate_index_#{$$}")
+    @directory = Dir.mktmpdir 'gem_generate_index'
 
     marshal_name = "Marshal.#{Gem.marshal_version}"
 
@@ -123,7 +124,7 @@ class Gem::Indexer
         marshal_name = File.join @quick_marshal_dir, spec_file_name
 
         marshal_zipped = Gem.deflate Marshal.dump(spec)
-        open marshal_name, 'wb' do |io| io.write marshal_zipped end
+        File.open marshal_name, 'wb' do |io| io.write marshal_zipped end
 
         files << marshal_name
 
@@ -261,7 +262,7 @@ class Gem::Indexer
 
     zipped = Gem.deflate data
 
-    open "#{filename}.#{extension}", 'wb' do |io|
+    File.open "#{filename}.#{extension}", 'wb' do |io|
       io.write zipped
     end
   end
@@ -427,7 +428,7 @@ class Gem::Indexer
 
     specs_index = compact_specs specs_index.uniq.sort
 
-    open dest, 'wb' do |io|
+    File.open dest, 'wb' do |io|
       Marshal.dump specs_index, io
     end
   end
index 0cbca0791b2e35db891751db35c7fa8e031f97d1..ee5fedeb64190daeaa73c5985647fb907e94e2e8 100644 (file)
@@ -206,7 +206,7 @@ class Gem::Installer
     ruby_executable = false
     existing = nil
 
-    open generated_bin, 'rb' do |io|
+    File.open generated_bin, 'rb' do |io|
       next unless io.gets =~ /^#!/ # shebang
       io.gets # blankline
 
@@ -427,7 +427,7 @@ class Gem::Installer
   # specifications directory.
 
   def write_spec
-    open spec_file, 'w' do |file|
+    File.open spec_file, 'w' do |file|
       spec.installed_by_version = Gem.rubygems_version
 
       file.puts spec.to_ruby_for_cache
@@ -464,7 +464,12 @@ class Gem::Installer
   def generate_bin # :nodoc:
     return if spec.executables.nil? or spec.executables.empty?
 
-    Dir.mkdir @bin_dir unless File.exist? @bin_dir
+    begin
+      Dir.mkdir @bin_dir
+    rescue SystemCallError
+      raise unless File.directory? @bin_dir
+    end
+
     raise Gem::FilePermissionError.new(@bin_dir) unless File.writable? @bin_dir
 
     spec.executables.each do |filename|
@@ -863,7 +868,7 @@ TEXT
 
     build_info_file = File.join build_info_dir, "#{spec.full_name}.info"
 
-    open build_info_file, 'w' do |io|
+    File.open build_info_file, 'w' do |io|
       @build_args.each do |arg|
         io.puts arg
       end
index 77811ed5ecaa773031ebb4a3a26c7d76115cc72b..b924122827ddb0701d387e023b80bca59da8c275 100644 (file)
@@ -219,7 +219,7 @@ class Gem::Package
       next unless stat.file?
 
       tar.add_file_simple file, stat.mode, stat.size do |dst_io|
-        open file, 'rb' do |src_io|
+        File.open file, 'rb' do |src_io|
           dst_io.write src_io.read 16384 until src_io.eof?
         end
       end
@@ -378,9 +378,9 @@ EOM
             File.dirname destination
           end
 
-        FileUtils.mkdir_p mkdir, mkdir_options
+        mkdir_p_safe mkdir, mkdir_options, destination_dir, entry.full_name
 
-        open destination, 'wb' do |out|
+        File.open destination, 'wb' do |out|
           out.write entry.read
           FileUtils.chmod entry.header.mode, destination
         end if entry.file?
@@ -416,20 +416,35 @@ EOM
     raise Gem::Package::PathError.new(filename, destination_dir) if
       filename.start_with? '/'
 
-    destination_dir = File.realpath destination_dir if
-      File.respond_to? :realpath
+    destination_dir = realpath destination_dir
     destination_dir = File.expand_path destination_dir
 
     destination = File.join destination_dir, filename
     destination = File.expand_path destination
 
     raise Gem::Package::PathError.new(destination, destination_dir) unless
-      destination.start_with? destination_dir
+      destination.start_with? destination_dir + '/'
 
     destination.untaint
     destination
   end
 
+  def mkdir_p_safe mkdir, mkdir_options, destination_dir, file_name
+    destination_dir = realpath File.expand_path(destination_dir)
+    parts = mkdir.split(File::SEPARATOR)
+    parts.reduce do |path, basename|
+      path = realpath path  unless path == ""
+      path = File.expand_path(path + File::SEPARATOR + basename)
+      lstat = File.lstat path rescue nil
+      if !lstat || !lstat.directory?
+        unless path.start_with? destination_dir and (FileUtils.mkdir path, mkdir_options rescue false)
+          raise Gem::Package::PathError.new(file_name, destination_dir)
+        end
+      end
+      path
+    end
+  end
+
   ##
   # Loads a Gem::Specification from the TarEntry +entry+
 
@@ -603,6 +618,10 @@ EOM
       raise Gem::Package::FormatError.new \
               'package content (data.tar.gz) is missing', @gem
     end
+
+    if duplicates = @files.group_by {|f| f }.select {|k,v| v.size > 1 }.map(&:first) and duplicates.any?
+      raise Gem::Security::Exception, "duplicate files in the package: (#{duplicates.map(&:inspect).join(', ')})"
+    end
   end
 
   ##
@@ -616,6 +635,16 @@ EOM
     raise Gem::Package::FormatError.new(e.message, entry.full_name)
   end
 
+  if File.respond_to? :realpath
+    def realpath file
+      File.realpath file
+    end
+  else
+    def realpath file
+      file
+    end
+  end
+
 end
 
 require 'rubygems/package/digest_io'
index 1a4dc4c824eb7d5d3709447fe296b17f2d7550bd..ecc3a686774f8af61204adf3d1d9fd7497cf1007 100644 (file)
@@ -23,11 +23,11 @@ class Gem::Package::FileSource < Gem::Package::Source # :nodoc: all
   end
 
   def with_write_io &block
-    open path, 'wb', &block
+    File.open path, 'wb', &block
   end
 
   def with_read_io &block
-    open path, 'rb', &block
+    File.open path, 'rb', &block
   end
 
 end
index f6e6e67c382a5ca50549977430bea5a838504bab..322d682ca8905658eaaae3adce23ab32ad37e3f7 100644 (file)
@@ -80,7 +80,7 @@ class Gem::Package::Old < Gem::Package
 
         FileUtils.mkdir_p File.dirname destination
 
-        open destination, 'wb', entry['mode'] do |out|
+        File.open destination, 'wb', entry['mode'] do |out|
           out.write file_data
         end
 
index c54bd14d578073e0fde31a606c598d4ad2cf343d..d5573571142e87089445fb6598cc7ed4803d3ba3 100644 (file)
@@ -104,25 +104,30 @@ class Gem::Package::TarHeader
     fields = header.unpack UNPACK_FORMAT
 
     new :name     => fields.shift,
-        :mode     => fields.shift.oct,
-        :uid      => fields.shift.oct,
-        :gid      => fields.shift.oct,
-        :size     => fields.shift.oct,
-        :mtime    => fields.shift.oct,
-        :checksum => fields.shift.oct,
+        :mode     => strict_oct(fields.shift),
+        :uid      => strict_oct(fields.shift),
+        :gid      => strict_oct(fields.shift),
+        :size     => strict_oct(fields.shift),
+        :mtime    => strict_oct(fields.shift),
+        :checksum => strict_oct(fields.shift),
         :typeflag => fields.shift,
         :linkname => fields.shift,
         :magic    => fields.shift,
-        :version  => fields.shift.oct,
+        :version  => strict_oct(fields.shift),
         :uname    => fields.shift,
         :gname    => fields.shift,
-        :devmajor => fields.shift.oct,
-        :devminor => fields.shift.oct,
+        :devmajor => strict_oct(fields.shift),
+        :devminor => strict_oct(fields.shift),
         :prefix   => fields.shift,
 
         :empty => empty
   end
 
+  def self.strict_oct(str)
+    return str.oct if str =~ /\A[0-7]*\z/
+    raise ArgumentError, "#{str.inspect} is not an octal string"
+  end
+
   ##
   # Creates a new TarHeader using +vals+
 
index f68b8d4c5ed51a745217e96f17dde2a6f4cbb3ee..390f7851a3c03611eb9ab768cc0f85865771cf76 100644 (file)
@@ -196,6 +196,8 @@ class Gem::Package::TarWriter
       digest_name == signer.digest_name
     end
 
+    raise "no #{signer.digest_name} in #{digests.values.compact}" unless signature_digest
+
     if signer.key then
       signature = signer.sign signature_digest.digest
 
index 7f6eadb939f924846aca452c39f04bf0a05a0465..76ad17d4862b7b6367a2869c09cc3e8d0792157f 100644 (file)
@@ -223,7 +223,7 @@ class Gem::RequestSet::Lockfile
   def write
     content = to_s
 
-    open "#{@gem_deps_file}.lock", 'w' do |io|
+    File.open "#{@gem_deps_file}.lock", 'w' do |io|
       io.write content
     end
   end
index 4690dd9230e00801b02b2e979d0a13460150528c..236577c5a3040783244cb9394938868e185f4760 100644 (file)
@@ -578,7 +578,7 @@ module Gem::Security
   def self.write pemmable, path, permissions = 0600, passphrase = nil, cipher = KEY_CIPHER
     path = File.expand_path path
 
-    open path, 'wb', permissions do |io|
+    File.open path, 'wb', permissions do |io|
       if passphrase and cipher
         io.write pemmable.to_pem cipher, passphrase
       else
index bf44975cc683a76546e565fd4fb33cccdf40ffc6..849cf3cd3e8ca371aeaed483b568f64542f1664f 100644 (file)
@@ -93,7 +93,7 @@ class Gem::Security::TrustDir
 
     destination = cert_path certificate
 
-    open destination, 'wb', @permissions[:trusted_cert] do |io|
+    File.open destination, 'wb', @permissions[:trusted_cert] do |io|
       io.write certificate.to_pem
     end
   end
index 93b3af36f8a4f1ae3bf0d9eccdc701f2480cdfdc..62c3dfe9cfb318434ebb5de1859c2e89ee4d62a0 100644 (file)
@@ -623,6 +623,18 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
       executables = nil if executables.empty?
       executables.last["is_last"] = true if executables
 
+      # Pre-process spec homepage for safety reasons
+      begin
+        homepage_uri = URI.parse(spec.homepage)
+        if [URI::HTTP, URI::HTTPS].member? homepage_uri.class
+          homepage_uri = spec.homepage
+        else
+          homepage_uri = "."
+        end
+      rescue URI::InvalidURIError
+        homepage_uri = "."
+      end
+
       specs << {
         "authors"             => spec.authors.sort.join(", "),
         "date"                => spec.date.to_s,
@@ -632,7 +644,7 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
         "only_one_executable" => (executables && executables.size == 1),
         "full_name"           => spec.full_name,
         "has_deps"            => !deps.empty?,
-        "homepage"            => spec.homepage,
+        "homepage"            => homepage_uri,
         "name"                => spec.name,
         "rdoc_installed"      => Gem::RDoc.new(spec).rdoc_installed?,
         "ri_installed"        => Gem::RDoc.new(spec).ri_installed?,
index bd84c217a7cab0107e03d8d95e99dc489ba58591..b28b85066077d909f8bc26ffe498958e8c5c5c8b 100644 (file)
@@ -160,7 +160,7 @@ class Gem::Source
     if update_cache? then
       FileUtils.mkdir_p cache_dir
 
-      open local_spec, 'wb' do |io|
+      File.open local_spec, 'wb' do |io|
         io.write spec
       end
     end
index 890c7c5f7e01004c21c1658543292a77e7d6b468..07fdd30a62aab01895f591e947249d59d45bb0c7 100644 (file)
@@ -15,6 +15,7 @@ require 'rubygems/basic_specification'
 require 'rubygems/stub_specification'
 require 'rubygems/util/list'
 require 'stringio'
+require 'uri'
 
 ##
 # The Specification class contains the information for a Gem.  Typically
@@ -2824,10 +2825,16 @@ http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard li
       raise Gem::InvalidSpecificationException, "#{lazy} is not a summary"
     end
 
-    if homepage and not homepage.empty? and
-       homepage !~ /\A[a-z][a-z\d+.-]*:/i then
-      raise Gem::InvalidSpecificationException,
-            "\"#{homepage}\" is not a URI"
+    # Make sure a homepage is valid HTTP/HTTPS URI
+    if homepage and not homepage.empty?
+      begin
+        homepage_uri = URI.parse(homepage)
+        unless [URI::HTTP, URI::HTTPS].member? homepage_uri.class
+          raise Gem::InvalidSpecificationException, "\"#{homepage}\" is not a valid HTTP URI"
+        end
+      rescue URI::InvalidURIError
+        raise Gem::InvalidSpecificationException, "\"#{homepage}\" is not a valid HTTP URI"
+      end
     end
 
     # Warnings
index 8337375ab4e90429cc3d815fb8284b1ff80a9bae..ae2effbc84604232fbd1d8db854f5c034a471ad4 100644 (file)
@@ -113,6 +113,8 @@ class Gem::StubSpecification < Gem::BasicSpecification
     unless @data
       begin
         saved_lineno = $.
+
+        # TODO It should be use `File.open`, but bundler-1.16.1 example expects Kernel#open.
         open loaded_from, OPEN_MODE do |file|
           begin
             file.readline # discard encoding line
index f7f216e5e3b55580255ebc2f9252b8f1dd3559d9..39aa4fc9a727611ac2936f6272c908c19a117508 100644 (file)
@@ -488,7 +488,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
 
     gemspec = "#{name}.gemspec"
 
-    open File.join(directory, gemspec), 'w' do |io|
+    File.open File.join(directory, gemspec), 'w' do |io|
       io.write git_spec.to_ruby
     end
 
@@ -592,7 +592,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
   # Reads a Marshal file at +path+
 
   def read_cache(path)
-    open path.dup.untaint, 'rb' do |io|
+    File.open path.dup.untaint, 'rb' do |io|
       Marshal.load io.read
     end
   end
@@ -612,7 +612,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
     dir = File.dirname path
     FileUtils.mkdir_p dir unless File.directory? dir
 
-    open path, 'wb' do |io|
+    File.open path, 'wb' do |io|
       yield io if block_given?
     end
 
@@ -727,7 +727,7 @@ class Gem::TestCase < MiniTest::Unit::TestCase
     install_default_specs(*specs)
 
     specs.each do |spec|
-      open spec.loaded_from, 'w' do |io|
+      File.open spec.loaded_from, 'w' do |io|
         io.write spec.to_ruby_for_cache
       end
     end
@@ -1363,7 +1363,7 @@ Also, a list:
       yield specification if block_given?
     end
 
-    open File.join(directory, "#{name}.gemspec"), 'w' do |io|
+    File.open File.join(directory, "#{name}.gemspec"), 'w' do |io|
       io.write vendor_spec.to_ruby
     end
 
index 686916ea02e73164c71daf614f26449d9174628d..83c9d2d0fe3f692091ea5fac3d1e7e0bfa687e03 100644 (file)
@@ -346,7 +346,7 @@ class Gem::TestCase::SpecFetcherSetup
   end
 
   def write_spec spec # :nodoc:
-    open spec.spec_file, 'w' do |io|
+    File.open spec.spec_file, 'w' do |io|
       io.write spec.to_ruby_for_cache
     end
   end
index 2de45c900b69ee10cd786b45aca33274dd8157bb..6c759100040d6a65d72d5261b14e4597f1c23559 100644 (file)
@@ -114,7 +114,8 @@ module Gem::Util
 
     here = File.expand_path directory
     loop do
-      Dir.chdir here, &block
+      Dir.chdir here, &block rescue Errno::EACCES
+
       new_here = File.expand_path('..', here)
       return if new_here == here # toplevel
       here = new_here
index 83448229bb34077c864024bbefc519323beb2f93..6842e4fa9c8d36900d126ba3b5d3b230f1a67018 100644 (file)
@@ -34,7 +34,7 @@ class Gem::Validator
   # gem_path:: [String] Path to gem file
 
   def verify_gem_file(gem_path)
-    open gem_path, Gem.binary_mode do |file|
+    File.open gem_path, Gem.binary_mode do |file|
       gem_data = file.read
       verify_gem gem_data
     end
@@ -109,7 +109,7 @@ class Gem::Validator
 
         good, gone, unreadable = nil, nil, nil, nil
 
-        open gem_path, Gem.binary_mode do |file|
+        File.open gem_path, Gem.binary_mode do |file|
           package = Gem::Package.new gem_path
 
           good, gone = package.contents.partition { |file_name|
@@ -134,7 +134,7 @@ class Gem::Validator
 
               source = File.join gem_directory, entry['path']
 
-              open source, Gem.binary_mode do |f|
+              File.open source, Gem.binary_mode do |f|
                 unless f.read == data then
                   errors[gem_name][entry['path']] = "Modified from original"
                 end
index 8a11cc2ecf2bafdefa8d37fb95e2206499b34bac..183771f0f3140e9bc23d798c42d6f113323fb3e0 100644 (file)
@@ -7,7 +7,7 @@ require 'pathname'
 require 'tmpdir'
 
 # TODO: push this up to test_case.rb once battle tested
-$SAFE=1
+
 $LOAD_PATH.map! do |path|
   path.dup.untaint
 end
@@ -463,7 +463,7 @@ class TestGem < Gem::TestCase
     assert File.directory?(util_cache_dir)
   end
 
-  unless win_platform? then # only for FS that support write protection
+  unless win_platform? || Process.uid.zero? then # only for FS that support write protection
     def test_self_ensure_gem_directories_write_protected
       gemdir = File.join @tempdir, "egd"
       FileUtils.rm_r gemdir rescue nil
@@ -775,7 +775,7 @@ class TestGem < Gem::TestCase
   end
 
   def test_self_read_binary
-    open 'test', 'w' do |io|
+    File.open 'test', 'w' do |io|
       io.write "\xCF\x80"
     end
 
@@ -1642,7 +1642,7 @@ class TestGem < Gem::TestCase
     spec = Gem::Specification.find { |s| s == spec }
     refute spec.activated?
 
-    open gem_deps_file, 'w' do |io|
+    File.open gem_deps_file, 'w' do |io|
       io.write 'gem "a"'
     end
 
@@ -1661,7 +1661,7 @@ class TestGem < Gem::TestCase
 
     refute spec.activated?
 
-    open 'gem.deps.rb', 'w' do |io|
+    File.open 'gem.deps.rb', 'w' do |io|
       io.write 'gem "a"'
     end
 
@@ -1705,7 +1705,7 @@ class TestGem < Gem::TestCase
 
     refute spec.activated?
 
-    open 'Gemfile', 'w' do |io|
+    File.open 'Gemfile', 'w' do |io|
       io.write 'gem "a"'
     end
 
@@ -1734,7 +1734,7 @@ class TestGem < Gem::TestCase
 
     refute spec.activated?
 
-    open 'gem.deps.rb', 'w' do |io|
+    File.open 'gem.deps.rb', 'w' do |io|
       io.write 'gem "a"'
     end
 
@@ -1749,7 +1749,7 @@ class TestGem < Gem::TestCase
     skip 'Insecure operation - read' if RUBY_VERSION <= "1.8.7"
     rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], 'x'
 
-    open 'x', 'w' do |io|
+    File.open 'x', 'w' do |io|
       io.write 'gem "a"'
     end
 
@@ -1790,7 +1790,7 @@ You may need to `gem install -g` to install missing gems
     spec = Gem::Specification.find { |s| s == spec }
     refute spec.activated?
 
-    open 'x', 'w' do |io|
+    File.open 'x', 'w' do |io|
       io.write 'gem "a"'
     end
 
index c55e1959758448a2010f8d3858b79629be8a805d..60d208fcc0bf78ee7c5c72a532ac9e8d5b25dbab 100644 (file)
@@ -158,7 +158,7 @@ class TestGemCommandsCleanupCommand < Gem::TestCase
     assert_path_exists @a_1_1.gem_dir
   ensure
     FileUtils.chmod 0755, @gemhome
-  end unless win_platform?
+  end unless win_platform? || Process.uid.zero?
 
   def test_execute_dry_run
     @cmd.options[:args] = %w[a]
index dd86a85038dbb9ac5401ef3af06accbc952d57b3..822d40e3f3370a2e9092711901ea7b5b1bcd27be 100644 (file)
@@ -131,6 +131,7 @@ class TestGemCommandsInstallCommand < Gem::TestCase
 
   def test_execute_no_user_install
     skip 'skipped on MS Windows (chmod has no effect)' if win_platform?
+    skip 'skipped in root privilege' if Process.uid.zero?
 
     specs = spec_fetcher do |fetcher|
       fetcher.gem 'a', 2
index 44652c10938bde279f8bb667895235acc17e383b..53cac4ce87ed20fb54ade196b274e13440eaf77c 100644 (file)
@@ -43,6 +43,31 @@ EOF
     assert_match %r{- 4}, @ui.output
   end
 
+  def test_show_owners_dont_load_objects
+    skip "testing a psych-only API" unless defined?(::Psych::DisallowedClass)
+
+    response = <<EOF
+---
+- email: !ruby/object:Object {}
+  id: 1
+  handle: user1
+- email: user2@example.com
+- id: 3
+  handle: user3
+- id: 4
+EOF
+
+    @fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, 'OK']
+
+    assert_raises Psych::DisallowedClass do
+      use_ui @ui do
+        @cmd.show_owners("freewill")
+      end
+    end
+
+  end
+
+
   def test_show_owners_setting_up_host_through_env_var
     response = "- email: user1@example.com\n"
     host = "http://rubygems.example"
index b888a741f05fdd3fb1c3f38bd7b65c7fec64831f..1c5dbfe23e474d9ea41d3032907802ade65d3986 100644 (file)
@@ -132,7 +132,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
     }
 
     FileUtils.mkdir_p File.dirname Gem.configuration.credentials_path
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write keys.to_yaml
     end
     Gem.configuration.load_api_keys
@@ -166,7 +166,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
     }
 
     FileUtils.mkdir_p File.dirname Gem.configuration.credentials_path
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write keys.to_yaml
     end
     Gem.configuration.load_api_keys
@@ -193,7 +193,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
     }
 
     FileUtils.mkdir_p File.dirname Gem.configuration.credentials_path
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write keys.to_yaml
     end
     Gem.configuration.load_api_keys
@@ -235,7 +235,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
     }
 
     FileUtils.mkdir_p File.dirname Gem.configuration.credentials_path
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write keys.to_yaml
     end
     Gem.configuration.load_api_keys
@@ -266,7 +266,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
     }
 
     FileUtils.mkdir_p File.dirname Gem.configuration.credentials_path
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write keys.to_yaml
     end
     Gem.configuration.load_api_keys
index 2136edb1be5c8d987b35bff307250f72e16ab895..f2541a24c7205a0175f96a35a3e5d29a3983e1f1 100644 (file)
@@ -6,6 +6,13 @@ require 'rubygems/commands/setup_command'
 
 class TestGemCommandsSetupCommand < Gem::TestCase
 
+  bundler_gemspec = File.expand_path("../../../bundler/lib/bundler/version.rb", __FILE__)
+  if File.exist?(bundler_gemspec)
+    BUNDLER_VERS = File.read(bundler_gemspec).match(/VERSION = "(#{Gem::Version::VERSION_PATTERN})"/)[1]
+  else
+    BUNDLER_VERS = "1.16.1"
+  end
+
   def setup
     super
 
@@ -16,27 +23,27 @@ class TestGemCommandsSetupCommand < Gem::TestCase
     FileUtils.mkdir_p 'bin'
     FileUtils.mkdir_p 'lib/rubygems/ssl_certs/rubygems.org'
 
-    open 'bin/gem',                   'w' do |io| io.puts '# gem'          end
-    open 'lib/rubygems.rb',           'w' do |io| io.puts '# rubygems.rb'  end
-    open 'lib/rubygems/test_case.rb', 'w' do |io| io.puts '# test_case.rb' end
-    open 'lib/rubygems/ssl_certs/rubygems.org/foo.pem', 'w' do |io| io.puts 'PEM'       end
+    File.open 'bin/gem',                   'w' do |io| io.puts '# gem'          end
+    File.open 'lib/rubygems.rb',           'w' do |io| io.puts '# rubygems.rb'  end
+    File.open 'lib/rubygems/test_case.rb', 'w' do |io| io.puts '# test_case.rb' end
+    File.open 'lib/rubygems/ssl_certs/rubygems.org/foo.pem', 'w' do |io| io.puts 'PEM'       end
 
     FileUtils.mkdir_p 'bundler/exe'
     FileUtils.mkdir_p 'bundler/lib/bundler'
 
-    open 'bundler/exe/bundle',        'w' do |io| io.puts '# bundle'       end
-    open 'bundler/lib/bundler.rb',    'w' do |io| io.puts '# bundler.rb'   end
-    open 'bundler/lib/bundler/b.rb',  'w' do |io| io.puts '# b.rb'         end
+    File.open 'bundler/exe/bundle',        'w' do |io| io.puts '# bundle'       end
+    File.open 'bundler/lib/bundler.rb',    'w' do |io| io.puts '# bundler.rb'   end
+    File.open 'bundler/lib/bundler/b.rb',  'w' do |io| io.puts '# b.rb'         end
 
     FileUtils.mkdir_p 'default/gems'
 
     gemspec = Gem::Specification.new
     gemspec.name = "bundler"
-    gemspec.version = "1.16.0"
+    gemspec.version = BUNDLER_VERS
     gemspec.bindir = "exe"
     gemspec.executables = ["bundle"]
 
-    open 'bundler/bundler.gemspec',   'w' do |io|
+    File.open 'bundler/bundler.gemspec',   'w' do |io|
       io.puts gemspec.to_ruby
     end
 
@@ -46,6 +53,11 @@ class TestGemCommandsSetupCommand < Gem::TestCase
     end
 
     FileUtils.mkdir_p File.join(Gem.default_dir, "specifications")
+
+    open(File.join(Gem.default_dir, "specifications", "bundler-#{BUNDLER_VERS}.gemspec"), 'w') do |io|
+      io.puts "# bundler-#{BUNDLER_VERS}"
+    end
+
     open(File.join(Gem.default_dir, "specifications", "bundler-audit-1.0.0.gemspec"), 'w') do |io|
       io.puts '# bundler-audit'
     end
@@ -134,13 +146,25 @@ class TestGemCommandsSetupCommand < Gem::TestCase
 
     default_dir = Gem::Specification.default_specifications_dir
 
+    # expect to remove other versions of bundler gemspecs on default specification directory.
     refute_path_exists File.join(default_dir, "bundler-1.15.4.gemspec")
-    refute_path_exists 'default/gems/bundler-1.15.4'
-
-    assert_path_exists File.join(default_dir, "bundler-1.16.0.gemspec")
-    assert_path_exists 'default/gems/bundler-1.16.0'
+    assert_path_exists File.join(default_dir, "bundler-#{BUNDLER_VERS}.gemspec")
 
+    # expect to not remove bundler-* gemspecs.
     assert_path_exists File.join(Gem.default_dir, "specifications", "bundler-audit-1.0.0.gemspec")
+
+    # expect to remove normal gem that was same version. because it's promoted default gems.
+    refute_path_exists File.join(Gem.default_dir, "specifications", "bundler-#{BUNDLER_VERS}.gemspec")
+
+    # expect to install default gems. It location was `site_ruby` directory on real world.
+    assert_path_exists "default/gems/bundler-#{BUNDLER_VERS}"
+
+    # expect to not remove other versions of bundler on `site_ruby`
+    assert_path_exists 'default/gems/bundler-1.15.4'
+
+    # TODO: We need to assert to remove same version of bundler on gem_dir directory(It's not site_ruby dir)
+
+    # expect to not remove bundler-* direcotyr.
     assert_path_exists 'default/gems/bundler-audit-1.0.0'
   end if Gem::USE_BUNDLER_FOR_GEMDEPS
 
@@ -162,14 +186,14 @@ class TestGemCommandsSetupCommand < Gem::TestCase
     FileUtils.mkdir_p lib_rubygems_defaults
     FileUtils.mkdir_p lib_bundler
 
-    open securerandom_rb,    'w' do |io| io.puts '# securerandom.rb'     end
+    File.open securerandom_rb,    'w' do |io| io.puts '# securerandom.rb'     end
 
-    open old_builder_rb,     'w' do |io| io.puts '# builder.rb'          end
-    open old_format_rb,      'w' do |io| io.puts '# format.rb'           end
-    open old_bundler_c_rb,   'w' do |io| io.puts '# c.rb'                end
+    File.open old_builder_rb,     'w' do |io| io.puts '# builder.rb'          end
+    File.open old_format_rb,      'w' do |io| io.puts '# format.rb'           end
+    File.open old_bundler_c_rb,   'w' do |io| io.puts '# c.rb'                end
 
-    open engine_defaults_rb, 'w' do |io| io.puts '# jruby.rb'            end
-    open os_defaults_rb,     'w' do |io| io.puts '# operating_system.rb' end
+    File.open engine_defaults_rb, 'w' do |io| io.puts '# jruby.rb'            end
+    File.open os_defaults_rb,     'w' do |io| io.puts '# operating_system.rb' end
 
     @cmd.remove_old_lib_files lib
 
@@ -191,7 +215,7 @@ class TestGemCommandsSetupCommand < Gem::TestCase
 
     @cmd.options[:previous_version] = Gem::Version.new '2.0.2'
 
-    open 'History.txt', 'w' do |io|
+    File.open 'History.txt', 'w' do |io|
       io.puts <<-History_txt
 # coding: UTF-8
 
index 2097ca7d4399bdd74a44b47cc191b0f132ebbb78..2fdff706e70c8e322f4ff240cbf3bfe8100ddee3 100644 (file)
@@ -92,7 +92,7 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase
     # Evil hack to prevent false removal success
     FileUtils.rm_f @executable
 
-    open @executable, "wb+" do |f| f.puts "binary" end
+    File.open @executable, "wb+" do |f| f.puts "binary" end
 
     @cmd.options[:executables] = true
     @cmd.options[:args] = [@spec.name]
@@ -204,7 +204,7 @@ class TestGemCommandsUninstallCommand < Gem::InstallerTestCase
     end
 
     assert Gem::Specification.find_all_by_name('dep_x').length > 0
-    assert Gem::Specification.find_all_by_name('x').length == 0
+    assert Gem::Specification.find_all_by_name('x').length.zero?
   end
 
   def test_execute_all
index e55cc75682b623a5747af2b077605569d157a008..3d762916685eb5aa22abcbc7a4773c2aaf0038a9 100644 (file)
@@ -424,7 +424,7 @@ class TestGemDependencyInstaller < Gem::TestCase
     extconf_rb = File.join @gemhome, 'gems', 'e-1', 'extconf.rb'
     FileUtils.mkdir_p File.dirname extconf_rb
 
-    open extconf_rb, 'w' do |io|
+    File.open extconf_rb, 'w' do |io|
       io.write <<-EXTCONF_RB
         require 'mkmf'
         create_makefile 'e'
index 39b8a1169286faf80eb9c5e8fe4b39968b31fb29..8db65d70cefc325ccdba0a0d43bbbefadd2a168b 100644 (file)
@@ -24,7 +24,7 @@ class TestGemDoctor < Gem::TestCase
 
     FileUtils.rm b.spec_file
 
-    open c.spec_file, 'w' do |io|
+    File.open c.spec_file, 'w' do |io|
       io.write 'this will raise an exception when evaluated.'
     end
 
@@ -77,7 +77,7 @@ Removed directory gems/c-2
 
     FileUtils.rm b.spec_file
 
-    open c.spec_file, 'w' do |io|
+    File.open c.spec_file, 'w' do |io|
       io.write 'this will raise an exception when evaluated.'
     end
 
index d142ef28daa3896c943e27460102c932df800182..3dabd3e350fc44ec408300397ad4d5e3b01ec087 100644 (file)
@@ -32,7 +32,7 @@ class TestGemExtBuilder < Gem::TestCase
     results = []
 
     Dir.chdir @ext do
-      open 'Makefile', 'w' do |io|
+      File.open 'Makefile', 'w' do |io|
         io.puts <<-MAKEFILE
 all:
 \t@#{Gem.ruby} -e "puts %Q{all: \#{ENV['DESTDIR']}}"
@@ -72,7 +72,7 @@ install:
     results = []
 
     Dir.chdir @ext do
-      open 'Makefile', 'w' do |io|
+      File.open 'Makefile', 'w' do |io|
         io.puts <<-MAKEFILE
 all:
 \t@#{Gem.ruby} -e "puts %Q{all: \#{ENV['DESTDIR']}}"
@@ -107,7 +107,7 @@ install:
 
     extconf_rb = File.join ext_dir, 'extconf.rb'
 
-    open extconf_rb, 'w' do |f|
+    File.open extconf_rb, 'w' do |f|
       f.write <<-'RUBY'
         require 'mkmf'
 
@@ -168,7 +168,7 @@ install:
 
     extconf_rb = File.join ext_dir, 'extconf.rb'
 
-    open extconf_rb, 'w' do |f|
+    File.open extconf_rb, 'w' do |f|
       f.write <<-'RUBY'
         require 'mkmf'
 
@@ -290,7 +290,7 @@ install:
 
     FileUtils.mkdir_p @spec.gem_dir
 
-    open File.join(@spec.gem_dir, "extconf.rb"), "w" do |f|
+    File.open File.join(@spec.gem_dir, "extconf.rb"), "w" do |f|
       f.write <<-'RUBY'
         puts "IN EXTCONF"
         extconf_args = File.join File.dirname(__FILE__), 'extconf_args'
@@ -323,7 +323,7 @@ install:
 
     build_info_file = File.join build_info_dir, "#{@spec.full_name}.info"
 
-    open build_info_file, 'w' do |io|
+    File.open build_info_file, 'w' do |io|
       io.puts '--with-foo-dir=/nonexistent'
     end
 
index 0a1faa404a8ed04603caae02533284d423342455..d68ac4da81e3906d1edb7dc97db8a281ae7fa7b5 100644 (file)
@@ -1,38 +1,6 @@
 # frozen_string_literal: true
 require 'rubygems/test_case'
-begin
-  gem_home_files = lambda{
-    if Dir.exist?(ENV["GEM_HOME"])
-      require "find"
-      ary = Find.find(ENV["GEM_HOME"]).to_a
-    else
-      []
-    end
-  }
-  prev_gem_home = ENV["GEM_HOME"]
-  prev_gem_home_files = gem_home_files.call
-  prev_threads = Thread.list.map{|e| e.inspect}
-
-  require 'rubygems/gem_runner'
-ensure
-  if $!
-    msg = <<eom
-***************
-PREV
-  GEM_HOME: #{prev_gem_home}
-  Files in GEM_HOME: #{prev_gem_home_files.inspect}
-  Threads: #{prev_threads.inspect}
-Current:
-  GEM_HOME: #{ENV["GEM_HOME"]}
-  Files in GEM_HOME: #{gem_home_files.call}
-  Threads: #{Thread.list.map{|e| e.inspect}.inspect}
-Exception: #{$!.message}
-eom
-    p $!.class
-    p $!.message.frozen?
-    raise $!.class, msg, $!.backtrace
-  end
-end
+require 'rubygems/gem_runner'
 
 class TestGemGemRunner < Gem::TestCase
 
index c3f9a7ea184c85156db55eeef3f094f739b9ed0a..286d59a78706e56c30e51a31948987c03796af50 100644 (file)
@@ -31,7 +31,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
 
     FileUtils.mkdir_p File.dirname Gem.configuration.credentials_path
 
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write keys.to_yaml
     end
 
@@ -46,7 +46,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
     keys = { :rubygems_api_key => 'KEY' }
     FileUtils.mkdir_p File.dirname Gem.configuration.credentials_path
 
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write keys.to_yaml
     end
 
@@ -59,7 +59,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
     keys = { :rubygems_api_key => 'KEY', :other => 'OTHER' }
     FileUtils.mkdir_p File.dirname Gem.configuration.credentials_path
 
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write keys.to_yaml
     end
 
@@ -163,7 +163,7 @@ class TestGemGemcutterUtilities < Gem::TestCase
     other_api_key = 'f46dbb18bb6a9c97cdc61b5b85c186a17403cdcbf'
 
     FileUtils.mkdir_p File.dirname(Gem.configuration.credentials_path)
-    open Gem.configuration.credentials_path, 'w' do |f|
+    File.open Gem.configuration.credentials_path, 'w' do |f|
       f.write Hash[:other_api_key, other_api_key].to_yaml
     end
     util_sign_in [api_key, 200, 'OK']
index a4a966e8de330032757d119fa4c0c7779f364ea0..5a9075e676a3f6be6fc57a3ab370a5663178d279 100644 (file)
@@ -39,8 +39,7 @@ class TestGemIndexer < Gem::TestCase
 
   def test_initialize
     assert_equal @tempdir, @indexer.dest_directory
-    assert_equal File.join(Dir.tmpdir, "gem_generate_index_#{$$}"),
-                 @indexer.directory
+    assert_match %r{#{Dir.mktmpdir('gem_generate_index').match(/.*-/)}}, @indexer.directory
 
     indexer = Gem::Indexer.new @tempdir
     assert indexer.build_modern
index e2d546307d1caa1fc6bc31ae2255299cf95972e4..371e408d2741dd5af61da3f673cdbfa7a234d113 100644 (file)
@@ -141,6 +141,8 @@ class TestGemInstallUpdateOptions < Gem::InstallerTestCase
   def test_user_install_disabled_read_only
     if win_platform?
       skip('test_user_install_disabled_read_only test skipped on MS Windows')
+    elsif Process.uid.zero?
+      skip('test_user_install_disabled_read_only test skipped in root privilege')
     else
       @cmd.handle_options %w[--no-user-install]
 
index 39095c7deefbfb07e84c2c53ae3c3a64581a4f80..93b048240713d549833c778cf04200ea51c83641 100644 (file)
@@ -140,7 +140,7 @@ end
       s.require_path = 'lib'
     end
 
-    open File.join(util_inst_bindir, 'executable'), 'w' do |io|
+    File.open File.join(util_inst_bindir, 'executable'), 'w' do |io|
      io.write <<-EXEC
 #!/usr/local/bin/ruby
 #
@@ -437,6 +437,8 @@ gem 'other', version
 
     if win_platform?
       skip('test_generate_bin_script_no_perms skipped on MS Windows')
+    elsif Process.uid.zero?
+      skip('test_generate_bin_script_no_perms skipped in root privilege')
     else
       FileUtils.chmod 0000, util_inst_bindir
 
@@ -529,6 +531,8 @@ gem 'other', version
 
     if win_platform?
       skip('test_generate_bin_symlink_no_perms skipped on MS Windows')
+    elsif Process.uid.zero?
+      skip('test_user_install_disabled_read_only test skipped in root privilege')
     else
       FileUtils.chmod 0000, util_inst_bindir
 
index cec1981c4c14f49040e955b5f8a361bde73ae98f..d1664cf285874e41cc0f6d3fb0130cce00bb0467 100644 (file)
@@ -24,7 +24,7 @@ class TestGemPackage < Gem::Package::TarTestCase
   end
 
   def test_class_new_old_format
-    open 'old_format.gem', 'wb' do |io|
+    File.open 'old_format.gem', 'wb' do |io|
       io.write SIMPLE_GEM
     end
 
@@ -45,7 +45,7 @@ class TestGemPackage < Gem::Package::TarTestCase
 
     FileUtils.mkdir 'lib'
 
-    open 'lib/code.rb', 'w' do |io|
+    File.open 'lib/code.rb', 'w' do |io|
       io.write '# lib/code.rb'
     end
 
@@ -110,8 +110,8 @@ class TestGemPackage < Gem::Package::TarTestCase
 
     FileUtils.mkdir_p 'lib/empty'
 
-    open 'lib/code.rb',  'w' do |io| io.write '# lib/code.rb'  end
-    open 'lib/extra.rb', 'w' do |io| io.write '# lib/extra.rb' end
+    File.open 'lib/code.rb',  'w' do |io| io.write '# lib/code.rb'  end
+    File.open 'lib/extra.rb', 'w' do |io| io.write '# lib/extra.rb' end
 
     package = Gem::Package.new 'bogus.gem'
     package.spec = spec
@@ -140,7 +140,7 @@ class TestGemPackage < Gem::Package::TarTestCase
     spec.files = %w[lib/code.rb lib/code_sym.rb]
 
     FileUtils.mkdir_p 'lib'
-    open 'lib/code.rb',  'w' do |io| io.write '# lib/code.rb'  end
+    File.open 'lib/code.rb',  'w' do |io| io.write '# lib/code.rb'  end
 
     # NOTE: 'code.rb' is correct, because it's relative to lib/code_sym.rb
     File.symlink('code.rb', 'lib/code_sym.rb')
@@ -179,7 +179,7 @@ class TestGemPackage < Gem::Package::TarTestCase
 
     FileUtils.mkdir 'lib'
 
-    open 'lib/code.rb', 'w' do |io|
+    File.open 'lib/code.rb', 'w' do |io|
       io.write '# lib/code.rb'
     end
 
@@ -218,7 +218,7 @@ class TestGemPackage < Gem::Package::TarTestCase
 
     FileUtils.mkdir 'lib'
 
-    open 'lib/code.rb', 'w' do |io|
+    File.open 'lib/code.rb', 'w' do |io|
       io.write '# lib/code.rb'
     end
 
@@ -261,7 +261,7 @@ class TestGemPackage < Gem::Package::TarTestCase
 
     FileUtils.mkdir 'lib'
 
-    open 'lib/code.rb', 'w' do |io|
+    File.open 'lib/code.rb', 'w' do |io|
       io.write '# lib/code.rb'
     end
 
@@ -311,7 +311,7 @@ class TestGemPackage < Gem::Package::TarTestCase
 
     FileUtils.mkdir 'lib'
 
-    open 'lib/code.rb', 'w' do |io|
+    File.open 'lib/code.rb', 'w' do |io|
       io.write '# lib/code.rb'
     end
 
@@ -348,7 +348,7 @@ class TestGemPackage < Gem::Package::TarTestCase
 
     FileUtils.mkdir 'lib'
 
-    open 'lib/code.rb', 'w' do |io|
+    File.open 'lib/code.rb', 'w' do |io|
       io.write '# lib/code.rb'
     end
 
@@ -408,7 +408,7 @@ class TestGemPackage < Gem::Package::TarTestCase
       end
     end
 
-    open 'empty.gem', 'wb' do |io|
+    File.open 'empty.gem', 'wb' do |io|
       io.write gem.string
     end
 
@@ -455,6 +455,31 @@ class TestGemPackage < Gem::Package::TarTestCase
                  File.read(extracted)
   end
 
+  def test_extract_symlink_parent
+   skip 'symlink not supported' if Gem.win_platform?
+
+   package = Gem::Package.new @gem
+
+   tgz_io = util_tar_gz do |tar|
+     tar.mkdir       'lib',               0755
+     tar.add_symlink 'lib/link', '../..', 0644
+     tar.add_file    'lib/link/outside.txt', 0644 do |io| io.write 'hi' end
+   end
+
+   # Extract into a subdirectory of @destination; if this test fails it writes
+   # a file outside destination_subdir, but we want the file to remain inside
+   # @destination so it will be cleaned up.
+   destination_subdir = File.join @destination, 'subdir'
+   FileUtils.mkdir_p destination_subdir
+
+   e = assert_raises Gem::Package::PathError do
+     package.extract_tar_gz tgz_io, destination_subdir
+   end
+
+   assert_equal("installing into parent path lib/link/outside.txt of " +
+                 "#{destination_subdir} is not allowed", e.message)
+  end
+
   def test_extract_tar_gz_directory
     package = Gem::Package.new @gem
 
@@ -566,6 +591,21 @@ class TestGemPackage < Gem::Package::TarTestCase
                  "#{@destination} is not allowed", e.message)
   end
 
+  def test_install_location_suffix
+    package = Gem::Package.new @gem
+
+    filename = "../#{File.basename(@destination)}suffix.rb"
+
+    e = assert_raises Gem::Package::PathError do
+      package.install_location filename, @destination
+    end
+
+    parent = File.expand_path File.join @destination, filename
+
+    assert_equal("installing into parent path #{parent} of " +
+                 "#{@destination} is not allowed", e.message)
+  end
+
   def test_load_spec
     entry = StringIO.new Gem.gzip @spec.to_yaml
     def entry.full_name() 'metadata.gz' end
@@ -620,7 +660,7 @@ class TestGemPackage < Gem::Package::TarTestCase
       end
     end
 
-    open 'mismatch.gem', 'wb' do |io|
+    File.open 'mismatch.gem', 'wb' do |io|
       io.write gem.string
     end
 
@@ -670,7 +710,7 @@ class TestGemPackage < Gem::Package::TarTestCase
       end
     end
 
-    open 'data_checksum_missing.gem', 'wb' do |io|
+    File.open 'data_checksum_missing.gem', 'wb' do |io|
       io.write gem.string
     end
 
@@ -723,6 +763,32 @@ class TestGemPackage < Gem::Package::TarTestCase
     assert_match %r%nonexistent.gem$%,           e.message
   end
 
+  def test_verify_duplicate_file
+    FileUtils.mkdir_p 'lib'
+    FileUtils.touch 'lib/code.rb'
+
+    build = Gem::Package.new @gem
+    build.spec = @spec
+    build.setup_signer
+    open @gem, 'wb' do |gem_io|
+      Gem::Package::TarWriter.new gem_io do |gem|
+        build.add_metadata gem
+        build.add_contents gem
+
+        gem.add_file_simple 'a.sig', 0444, 0
+        gem.add_file_simple 'a.sig', 0444, 0
+      end
+    end
+
+    package = Gem::Package.new @gem
+
+    e = assert_raises Gem::Security::Exception do
+      package.verify
+    end
+
+    assert_equal 'duplicate files in the package: ("a.sig")', e.message
+  end
+
   def test_verify_security_policy
     skip 'openssl is missing' unless defined?(OpenSSL::SSL)
 
@@ -773,14 +839,20 @@ class TestGemPackage < Gem::Package::TarTestCase
     FileUtils.mkdir 'lib'
     FileUtils.touch 'lib/code.rb'
 
-    open @gem, 'wb' do |gem_io|
+    File.open @gem, 'wb' do |gem_io|
       Gem::Package::TarWriter.new gem_io do |gem|
         build.add_metadata gem
         build.add_contents gem
 
         # write bogus data.tar.gz to foil signature
         bogus_data = Gem.gzip 'hello'
-        gem.add_file_simple 'data.tar.gz', 0444, bogus_data.length do |io|
+        fake_signer = Class.new do
+          def digest_name; 'SHA512'; end
+          def digest_algorithm; Digest(:SHA512); end
+          def key; 'key'; end
+          def sign(*); 'fake_sig'; end
+        end
+        gem.add_file_signed 'data2.tar.gz', 0444, fake_signer.new do |io|
           io.write bogus_data
         end
 
@@ -804,7 +876,7 @@ class TestGemPackage < Gem::Package::TarTestCase
   end
 
   def test_verify_truncate
-    open 'bad.gem', 'wb' do |io|
+    File.open 'bad.gem', 'wb' do |io|
       io.write File.read(@gem, 1024) # don't care about newlines
     end
 
index c15475b0c7d8a7587ad96245e43fbfdb5ae8024b..604981b3c1fc9f05f4d11e3471076323c08eba25 100644 (file)
@@ -7,7 +7,7 @@ class TestGemPackageOld < Gem::TestCase
   def setup
     super
 
-    open 'old_format.gem', 'wb' do |io|
+    File.open 'old_format.gem', 'wb' do |io|
       io.write SIMPLE_GEM
     end
 
index d33877057d0b91bef2b20163e22808edc4612a49..43f508df450938c90a59758954df5c940cd81979 100644 (file)
@@ -143,5 +143,26 @@ group\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
     assert_equal '012467', @tar_header.checksum
   end
 
+  def test_from_bad_octal
+    test_cases = [
+      "00000006,44\000", # bogus character
+      "00000006789\000", # non-octal digit
+      "+0000001234\000", # positive sign
+      "-0000001000\000", # negative sign
+      "0x000123abc\000", # radix prefix
+    ]
+
+    test_cases.each do |val|
+      header_s = @tar_header.to_s
+      # overwrite the size field
+      header_s[124, 12] = val
+      io = TempIO.new header_s
+      assert_raises ArgumentError do
+        new_header = Gem::Package::TarHeader.from io
+      end
+      io.close! if io.respond_to? :close!
+    end
+  end
+
 end
 
index 76ca8c45a94d7792044585d35b6e2249f6720ad7..0355883cb3c41fd08003068dade18eaa266fff5f 100644 (file)
@@ -223,6 +223,7 @@ class TestGemRDoc < Gem::TestCase
 
   def test_remove_unwritable
     skip 'chmod not supported' if Gem.win_platform?
+    skip 'skipped in root privilege' if Process.uid.zero?
     FileUtils.mkdir_p @a.base_dir
     FileUtils.chmod 0, @a.base_dir
 
@@ -251,6 +252,7 @@ class TestGemRDoc < Gem::TestCase
 
   def test_setup_unwritable
     skip 'chmod not supported' if Gem.win_platform?
+    skip 'skipped in root privilege' if Process.uid.zero?
     FileUtils.mkdir_p @a.doc_dir
     FileUtils.chmod 0, @a.doc_dir
 
index ee5ac77717520ed945a0a59244d4b7960a8c7a63..20e34e84e114ff910c564e6b18b7763d83c7f80c 100644 (file)
@@ -431,7 +431,7 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg==
     assert File.exist?(a1_cache_gem)
   end
 
-  unless win_platform? # File.chmod doesn't work
+  unless win_platform? || Process.uid.zero? # File.chmod doesn't work
     def test_download_local_read_only
       FileUtils.mv @a1_gem, @tempdir
       local_path = File.join @tempdir, @a1.file_name
index 3a48827481ab7bf38b52101f0ddee95f2fc0f881..5dc6c1518de743b493aef791fc7379a86fb3b76f 100644 (file)
@@ -52,7 +52,7 @@ class TestGemRequestSet < Gem::TestCase
     rs = Gem::RequestSet.new
     installed = []
 
-    open 'gem.deps.rb', 'w' do |io|
+    File.open 'gem.deps.rb', 'w' do |io|
       io.puts 'gem "a"'
       io.flush
 
@@ -78,7 +78,7 @@ class TestGemRequestSet < Gem::TestCase
 
     rs = Gem::RequestSet.new
 
-    open 'gem.deps.rb', 'w' do |io|
+    File.open 'gem.deps.rb', 'w' do |io|
       io.puts 'gem "a"'
       io.flush
 
@@ -104,7 +104,7 @@ Gems to install:
     rs = Gem::RequestSet.new
     installed = []
 
-    open 'gem.deps.rb', 'w' do |io|
+    File.open 'gem.deps.rb', 'w' do |io|
       io.puts 'gem "a"'
     end
 
@@ -128,7 +128,7 @@ Gems to install:
 
     rs = Gem::RequestSet.new
 
-    open 'gem.deps.rb', 'w' do |io|
+    File.open 'gem.deps.rb', 'w' do |io|
       io.puts 'gem "a"'
       io.flush
 
@@ -150,7 +150,7 @@ Gems to install:
     rs = Gem::RequestSet.new
     installed = []
 
-    open 'gem.deps.rb.lock', 'w' do |io|
+    File.open 'gem.deps.rb.lock', 'w' do |io|
       io.puts <<-LOCKFILE
 GEM
   remote: #{@gem_repo}
@@ -167,7 +167,7 @@ DEPENDENCIES
       LOCKFILE
     end
 
-    open 'gem.deps.rb', 'w' do |io|
+    File.open 'gem.deps.rb', 'w' do |io|
       io.puts 'gem "b"'
     end
 
@@ -190,7 +190,7 @@ DEPENDENCIES
     rs = Gem::RequestSet.new
     installed = []
 
-    open 'gem.deps.rb', 'w' do |io|
+    File.open 'gem.deps.rb', 'w' do |io|
       io.puts <<-GEM_DEPS
 gem "a"
 ruby "0"
index 908f97303e79a410a596bbfe47d7a51df920a4d3..7460b7efad21d7302052319e7f3afd15f60a6ae6 100644 (file)
@@ -31,7 +31,7 @@ class TestGemRequestSetLockfile < Gem::TestCase
   def write_lockfile lockfile
     @lock_file = File.expand_path "#{@gem_deps_file}.lock"
 
-    open @lock_file, 'w' do |io|
+    File.open @lock_file, 'w' do |io|
       io.write lockfile
     end
   end
@@ -387,7 +387,7 @@ DEPENDENCIES
           s.add_dependency 'c', '~> 1.0'
         end
 
-        open 'b.gemspec', 'w' do |io|
+        File.open 'b.gemspec', 'w' do |io|
           io.write b.to_ruby
         end
 
@@ -400,7 +400,7 @@ DEPENDENCIES
       Dir.chdir 'c' do
         c = Gem::Specification.new 'c', 1
 
-        open 'c.gemspec', 'w' do |io|
+        File.open 'c.gemspec', 'w' do |io|
           io.write c.to_ruby
         end
 
@@ -455,7 +455,7 @@ DEPENDENCIES
 
     gem_deps_lock_file = "#{@gem_deps_file}.lock"
 
-    open gem_deps_lock_file, 'w' do |io|
+    File.open gem_deps_lock_file, 'w' do |io|
       io.write 'hello'
     end
 
index 9946c522d9d0c5ff464a4e7441adc9828a80541b..f3517da43a7d5d47541ec538fae195da59e90313 100644 (file)
@@ -536,7 +536,7 @@ DEPENDENCIES
   end
 
   def write_lockfile lockfile
-    open @lock_file, 'w' do |io|
+    File.open @lock_file, 'w' do |io|
       io.write lockfile
     end
   end
index ab506a14e6954e541c3b269f9e5a27c52eb046bd..f4aba6d94ac178caa189881c1b2a56e27d00ff86 100644 (file)
@@ -295,7 +295,7 @@ GEM
   end
 
   def write_lockfile lockfile
-    open @lock_file, 'w' do |io|
+    File.open @lock_file, 'w' do |io|
       io.write lockfile
     end
   end
index 9e8e2c57153a84e214239d36d4360115e969a5e7..211757eb204aaf1aaca810a516769816ef6d000d 100644 (file)
@@ -70,7 +70,7 @@ class TestGemResolverGitSpecification < Gem::TestCase
     Dir.chdir 'git/a' do
       FileUtils.mkdir_p 'ext/lib'
 
-      open 'ext/extconf.rb', 'w' do |io|
+      File.open 'ext/extconf.rb', 'w' do |io|
         io.puts 'require "mkmf"'
         io.puts 'create_makefile "a"'
       end
index 6fe02e480f0d06cb1e705cf154f0fad747149dbb..a018e65512b08cf8ee7c094a04bc9f38eab02856 100644 (file)
@@ -100,7 +100,7 @@ class TestGemServer < Gem::TestCase
     specs_dir = File.join dir, 'specifications'
     FileUtils.mkdir_p specs_dir
 
-    open File.join(specs_dir, spec.spec_name), 'w' do |io|
+    File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
       io.write spec.to_ruby
     end
 
@@ -198,7 +198,7 @@ class TestGemServer < Gem::TestCase
 
     FileUtils.mkdir_p specs_dir
 
-    open File.join(specs_dir, spec.spec_name), 'w' do |io|
+    File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
       io.write spec.to_ruby
     end
 
@@ -339,7 +339,7 @@ class TestGemServer < Gem::TestCase
     specs_dir = File.join dir, 'specifications'
     FileUtils.mkdir_p specs_dir
 
-    open File.join(specs_dir, spec.spec_name), 'w' do |io|
+    File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
       io.write spec.to_ruby
     end
 
@@ -353,6 +353,171 @@ class TestGemServer < Gem::TestCase
     assert_match 'z 9', @res.body
   end
 
+
+  def test_xss_homepage_fix_289313
+    data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
+    dir = "#{@gemhome}2"
+
+    spec = util_spec 'xsshomepagegem', 1
+    spec.homepage = "javascript:confirm(document.domain)"
+
+    specs_dir = File.join dir, 'specifications'
+    FileUtils.mkdir_p specs_dir
+
+    open File.join(specs_dir, spec.spec_name), 'w' do |io|
+      io.write spec.to_ruby
+    end
+
+    server = Gem::Server.new dir, process_based_port, false
+
+    @req.parse data
+
+    server.root @req, @res
+
+    assert_equal 200, @res.status
+    assert_match 'xsshomepagegem 1', @res.body
+
+    # This verifies that the homepage for this spec is not displayed and is set to ".", because it's not a 
+    # valid HTTP/HTTPS URL and could be unsafe in an HTML context.  We would prefer to throw an exception here,
+    # but spec.homepage is currently free form and not currently required to be a URL, this behavior may be 
+    # validated in future versions of Gem::Specification.
+    #
+    # There are two variant we're checking here, one where rdoc is not present, and one where rdoc is present in the same regex:
+    #
+    # Variant #1 - rdoc not installed
+    #
+    #   <b>xsshomepagegem 1</b>
+    #
+    #
+    #  <span title="rdoc not installed">[rdoc]</span>
+    #
+    #
+    #
+    #  <a href="." title=".">[www]</a>
+    #
+    # Variant #2 - rdoc installed
+    #
+    #   <b>xsshomepagegem 1</b>
+    #
+    #
+    #  <a href="\/doc_root\/xsshomepagegem-1\/">\[rdoc\]<\/a>
+    #
+    #
+    #
+    #  <a href="." title=".">[www]</a>
+    regex_match = /xsshomepagegem 1<\/b>[\n\s]+(<span title="rdoc not installed">\[rdoc\]<\/span>|<a href="\/doc_root\/xsshomepagegem-1\/">\[rdoc\]<\/a>)[\n\s]+<a href="\." title="\.">\[www\]<\/a>/
+    assert_match regex_match, @res.body
+  end
+
+  def test_invalid_homepage
+    data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
+    dir = "#{@gemhome}2"
+
+    spec = util_spec 'invalidhomepagegem', 1
+    spec.homepage = "notavalidhomepageurl"
+
+    specs_dir = File.join dir, 'specifications'
+    FileUtils.mkdir_p specs_dir
+
+    open File.join(specs_dir, spec.spec_name), 'w' do |io|
+      io.write spec.to_ruby
+    end
+
+    server = Gem::Server.new dir, process_based_port, false
+
+    @req.parse data
+
+    server.root @req, @res
+
+    assert_equal 200, @res.status
+    assert_match 'invalidhomepagegem 1', @res.body
+
+    # This verifies that the homepage for this spec is not displayed and is set to ".", because it's not a 
+    # valid HTTP/HTTPS URL and could be unsafe in an HTML context.  We would prefer to throw an exception here,
+    # but spec.homepage is currently free form and not currently required to be a URL, this behavior may be 
+    # validated in future versions of Gem::Specification.
+    #
+    # There are two variant we're checking here, one where rdoc is not present, and one where rdoc is present in the same regex:
+    #
+    # Variant #1 - rdoc not installed
+    #
+    #   <b>invalidhomepagegem 1</b>
+    #
+    #
+    #  <span title="rdoc not installed">[rdoc]</span>
+    #
+    #
+    #
+    #  <a href="." title=".">[www]</a>
+    #
+    # Variant #2 - rdoc installed
+    #
+    #   <b>invalidhomepagegem 1</b>
+    #
+    #
+    #  <a href="\/doc_root\/invalidhomepagegem-1\/">\[rdoc\]<\/a>
+    #
+    #
+    #
+    #  <a href="." title=".">[www]</a>
+    regex_match = /invalidhomepagegem 1<\/b>[\n\s]+(<span title="rdoc not installed">\[rdoc\]<\/span>|<a href="\/doc_root\/invalidhomepagegem-1\/">\[rdoc\]<\/a>)[\n\s]+<a href="\." title="\.">\[www\]<\/a>/
+    assert_match regex_match, @res.body
+  end
+
+  def test_valid_homepage_http
+    data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
+    dir = "#{@gemhome}2"
+
+    spec = util_spec 'validhomepagegemhttp', 1
+    spec.homepage = "http://rubygems.org"
+
+    specs_dir = File.join dir, 'specifications'
+    FileUtils.mkdir_p specs_dir
+
+    open File.join(specs_dir, spec.spec_name), 'w' do |io|
+      io.write spec.to_ruby
+    end
+
+    server = Gem::Server.new dir, process_based_port, false
+
+    @req.parse data
+
+    server.root @req, @res
+
+    assert_equal 200, @res.status
+    assert_match 'validhomepagegemhttp 1', @res.body
+
+    regex_match = /validhomepagegemhttp 1<\/b>[\n\s]+(<span title="rdoc not installed">\[rdoc\]<\/span>|<a href="\/doc_root\/validhomepagegemhttp-1\/">\[rdoc\]<\/a>)[\n\s]+<a href="http:\/\/rubygems\.org" title="http:\/\/rubygems\.org">\[www\]<\/a>/
+    assert_match regex_match, @res.body
+  end
+
+  def test_valid_homepage_https
+    data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
+    dir = "#{@gemhome}2"
+
+    spec = util_spec 'validhomepagegemhttps', 1
+    spec.homepage = "https://rubygems.org"
+
+    specs_dir = File.join dir, 'specifications'
+    FileUtils.mkdir_p specs_dir
+
+    open File.join(specs_dir, spec.spec_name), 'w' do |io|
+      io.write spec.to_ruby
+    end
+
+    server = Gem::Server.new dir, process_based_port, false
+
+    @req.parse data
+
+    server.root @req, @res
+
+    assert_equal 200, @res.status
+    assert_match 'validhomepagegemhttps 1', @res.body
+
+    regex_match = /validhomepagegemhttps 1<\/b>[\n\s]+(<span title="rdoc not installed">\[rdoc\]<\/span>|<a href="\/doc_root\/validhomepagegemhttps-1\/">\[rdoc\]<\/a>)[\n\s]+<a href="https:\/\/rubygems\.org" title="https:\/\/rubygems\.org">\[www\]<\/a>/
+    assert_match regex_match, @res.body
+  end
+
   def test_specs
     data = StringIO.new "GET /specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
     @req.parse data
@@ -378,7 +543,7 @@ class TestGemServer < Gem::TestCase
     specs_dir = File.join dir, 'specifications'
     FileUtils.mkdir_p specs_dir
 
-    open File.join(specs_dir, spec.spec_name), 'w' do |io|
+    File.open File.join(specs_dir, spec.spec_name), 'w' do |io|
       io.write spec.to_ruby
     end
 
index 4a93e222f8ebbdde85d72219a045c8f8de102bdd..8805a9b40455e279d5e3b01e3ea749520ac27c13 100644 (file)
@@ -110,7 +110,7 @@ class TestGemSource < Gem::TestCase
 
     cache_file = File.join cache_dir, a1.spec_name
 
-    open cache_file, 'wb' do |io|
+    File.open cache_file, 'wb' do |io|
       Marshal.dump a1, io
     end
 
@@ -163,7 +163,7 @@ class TestGemSource < Gem::TestCase
 
     cache_file = File.join cache_dir, "latest_specs.#{Gem.marshal_version}"
 
-    open cache_file, 'wb' do |io|
+    File.open cache_file, 'wb' do |io|
       Marshal.dump latest_specs, io
     end
 
@@ -187,7 +187,7 @@ class TestGemSource < Gem::TestCase
 
     cache_file = File.join cache_dir, "latest_specs.#{Gem.marshal_version}"
 
-    open cache_file, 'wb' do |io|
+    File.open cache_file, 'wb' do |io|
       # Setup invalid data in the cache:
       io.write Marshal.dump(latest_specs)[0, 10]
     end
index 0e13a11e7eaf1880ef7a66de4020c35b259c738c..8f5d3ee745747fad55d6f9166d9341e79fb6d064 100644 (file)
@@ -229,7 +229,7 @@ class TestGemSourceGit < Gem::TestCase
       Dir.chdir 'b' do
         b = Gem::Specification.new 'b', 1
 
-        open 'b.gemspec', 'w' do |io|
+        File.open 'b.gemspec', 'w' do |io|
           io.write b.to_ruby
         end
 
index bb6acbc7dead5a3b29df39217fd4b3803945c9b3..badb297eee46a97d5e6a5a5b397dcf5f7859885f 100644 (file)
@@ -922,7 +922,7 @@ dependencies: []
   end
 
   def test_self_load_relative
-    open 'a-2.gemspec', 'w' do |io|
+    File.open 'a-2.gemspec', 'w' do |io|
       io.write @a2.to_ruby_for_cache
     end
 
@@ -948,6 +948,9 @@ dependencies: []
     @a2.files.clear
 
     assert_equal @a2, spec
+
+  ensure
+    $SAFE = 0
   end
 
   def test_self_load_escape_curly
@@ -1111,7 +1114,7 @@ dependencies: []
   end
 
   def test_self_remove_spec_removed
-    open @a1.spec_file, 'w' do |io|
+    File.open @a1.spec_file, 'w' do |io|
       io.write @a1.to_ruby
     end
 
@@ -1363,13 +1366,13 @@ dependencies: []
 
     assert_empty @ext.build_args
 
-    open @ext.build_info_file, 'w' do |io|
+    File.open @ext.build_info_file, 'w' do |io|
       io.puts
     end
 
     assert_empty @ext.build_args
 
-    open @ext.build_info_file, 'w' do |io|
+    File.open @ext.build_info_file, 'w' do |io|
       io.puts '--with-foo-dir=wherever'
     end
 
@@ -1385,9 +1388,9 @@ dependencies: []
     extconf_rb = File.join @ext.gem_dir, @ext.extensions.first
     FileUtils.mkdir_p File.dirname extconf_rb
 
-    open extconf_rb, 'w' do |f|
+    File.open extconf_rb, 'w' do |f|
       f.write <<-'RUBY'
-        open 'Makefile', 'w' do |f|
+        File.open 'Makefile', 'w' do |f|
           f.puts "clean:\n\techo clean"
           f.puts "default:\n\techo built"
           f.puts "install:\n\techo installed"
@@ -1435,9 +1438,9 @@ dependencies: []
     extconf_rb = File.join spec.gem_dir, spec.extensions.first
     FileUtils.mkdir_p File.dirname extconf_rb
 
-    open extconf_rb, 'w' do |f|
+    File.open extconf_rb, 'w' do |f|
       f.write <<-'RUBY'
-        open 'Makefile', 'w' do |f|
+        File.open 'Makefile', 'w' do |f|
           f.puts "default:\n\techo built"
           f.puts "install:\n\techo installed"
         end
@@ -1461,6 +1464,7 @@ dependencies: []
 
   def test_build_extensions_extensions_dir_unwritable
     skip 'chmod not supported' if Gem.win_platform?
+    skip 'skipped in root privilege' if Process.uid.zero?
 
     ext_spec
 
@@ -1469,9 +1473,9 @@ dependencies: []
     extconf_rb = File.join @ext.gem_dir, @ext.extensions.first
     FileUtils.mkdir_p File.dirname extconf_rb
 
-    open extconf_rb, 'w' do |f|
+    File.open extconf_rb, 'w' do |f|
       f.write <<-'RUBY'
-        open 'Makefile', 'w' do |f|
+        File.open 'Makefile', 'w' do |f|
           f.puts "clean:\n\techo clean"
           f.puts "default:\n\techo built"
           f.puts "install:\n\techo installed"
@@ -1486,7 +1490,7 @@ dependencies: []
     @ext.build_extensions
     refute_path_exists @ext.extension_dir
   ensure
-    unless ($DEBUG or win_platform?) then
+    unless ($DEBUG or win_platform? or Process.uid.zero?) then
       FileUtils.chmod 0755, File.join(@ext.base_dir, 'extensions')
       FileUtils.chmod 0755, @ext.base_dir
     end
@@ -1502,9 +1506,9 @@ dependencies: []
     extconf_rb = File.join @ext.gem_dir, @ext.extensions.first
     FileUtils.mkdir_p File.dirname extconf_rb
 
-    open extconf_rb, 'w' do |f|
+    File.open extconf_rb, 'w' do |f|
       f.write <<-'RUBY'
-        open 'Makefile', 'w' do |f|
+        File.open 'Makefile', 'w' do |f|
           f.puts "clean:\n\techo clean"
           f.puts "default:\n\techo built"
           f.puts "install:\n\techo installed"
@@ -1551,9 +1555,9 @@ dependencies: []
     extconf_rb = File.join @ext.gem_dir, @ext.extensions.first
     FileUtils.mkdir_p File.dirname extconf_rb
 
-    open extconf_rb, 'w' do |f|
+    File.open extconf_rb, 'w' do |f|
       f.write <<-'RUBY'
-        open 'Makefile', 'w' do |f|
+        File.open 'Makefile', 'w' do |f|
           f.puts "clean:\n\techo clean"
           f.puts "default:\n\techo built"
           f.puts "install:\n\techo installed"
@@ -2882,7 +2886,22 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use:
         @a1.validate
       end
 
-      assert_equal '"over at my cool site" is not a URI', e.message
+      assert_equal '"over at my cool site" is not a valid HTTP URI', e.message
+
+      @a1.homepage = 'ftp://rubygems.org'
+
+      e = assert_raises Gem::InvalidSpecificationException do
+        @a1.validate
+      end
+
+      assert_equal '"ftp://rubygems.org" is not a valid HTTP URI', e.message
+
+      @a1.homepage = 'http://rubygems.org'
+      assert_equal true, @a1.validate
+
+      @a1.homepage = 'https://rubygems.org'
+      assert_equal true, @a1.validate
+
     end
   end
 
@@ -3418,9 +3437,9 @@ end
     extconf_rb = File.join @ext.gem_dir, @ext.extensions.first
     FileUtils.mkdir_p File.dirname extconf_rb
 
-    open extconf_rb, 'w' do |f|
+    File.open extconf_rb, 'w' do |f|
       f.write <<-'RUBY'
-        open 'Makefile', 'w' do |f|
+        File.open 'Makefile', 'w' do |f|
           f.puts "clean:\n\techo clean"
           f.puts "default:\n\techo built"
           f.puts "install:\n\techo installed"
index 43680265c7343d73eac90ac0c42647316ac4bbdc..f9a3a236c0878e86575c3fd8a2fafea3df8fff8f 100644 (file)
@@ -127,9 +127,9 @@ class TestStubSpecification < Gem::TestCase
       extconf_rb = File.join s.gem_dir, s.extensions.first
       FileUtils.mkdir_p File.dirname extconf_rb
 
-      open extconf_rb, 'w' do |f|
+      File.open extconf_rb, 'w' do |f|
         f.write <<-'RUBY'
-        open 'Makefile', 'w' do |f|
+        File.open 'Makefile', 'w' do |f|
           f.puts "clean:\n\techo clean"
           f.puts "default:\n\techo built"
           f.puts "install:\n\techo installed"
@@ -149,7 +149,7 @@ class TestStubSpecification < Gem::TestCase
     spec = new_default_spec 'default', 1
     spec.extensions << 'extconf.rb'
 
-    open spec.loaded_from, 'w' do |io|
+    File.open spec.loaded_from, 'w' do |io|
       io.write spec.to_ruby_for_cache
     end
 
@@ -198,7 +198,7 @@ class TestStubSpecification < Gem::TestCase
 
   def stub_with_version
     spec = File.join @gemhome, 'specifications', 'stub_e-2.gemspec'
-    open spec, 'w' do |io|
+    File.open spec, 'w' do |io|
       io.write <<-STUB
 # -*- encoding: utf-8 -*-
 # stub: stub_v 2 ruby lib
@@ -221,7 +221,7 @@ end
 
   def stub_without_version
     spec = File.join @gemhome, 'specifications', 'stub-2.gemspec'
-    open spec, 'w' do |io|
+    File.open spec, 'w' do |io|
       io.write <<-STUB
 # -*- encoding: utf-8 -*-
 # stub: stub_v ruby lib
@@ -245,7 +245,7 @@ end
 
   def stub_with_extension
     spec = File.join @gemhome, 'specifications', 'stub_e-2.gemspec'
-    open spec, 'w' do |io|
+    File.open spec, 'w' do |io|
       io.write <<-STUB
 # -*- encoding: utf-8 -*-
 # stub: stub_e 2 ruby lib
@@ -271,7 +271,7 @@ end
 
   def stub_without_extension
     spec = File.join @gemhome, 'specifications', 'stub-2.gemspec'
-    open spec, 'w' do |io|
+    File.open spec, 'w' do |io|
       io.write <<-STUB
 # -*- encoding: utf-8 -*-
 # stub: stub 2 ruby lib
index b85db44d514a1e4f0f1cffbf09084b9746e4dfa3..3b7887d93190335c7bccd5141a318079df7eab46 100644 (file)
@@ -5,6 +5,7 @@ require 'rubygems/util'
 class TestGemUtil < Gem::TestCase
 
   def test_class_popen
+    skip "MJIT executes process and it's caught by Process.wait(-1)" if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?
     assert_equal "0\n", Gem::Util.popen(Gem.ruby, '-e', 'p 0')
 
     assert_raises Errno::ECHILD do
@@ -29,6 +30,30 @@ class TestGemUtil < Gem::TestCase
     loop { break if enum.next.nil? } # exhaust the enumerator
   end
 
+  def test_traverse_parents_does_not_crash_on_permissions_error
+    skip 'skipped on MS Windows (chmod has no effect)' if win_platform?
+
+    FileUtils.mkdir_p 'd/e/f'
+    # remove 'execute' permission from "e" directory and make it
+    # impossible to cd into it and its children
+    FileUtils.chmod(0666, 'd/e')
+
+    paths = Gem::Util.traverse_parents('d/e/f').to_a
+
+    assert_equal File.join(@tempdir, 'd'), paths[0]
+    assert_equal @tempdir, paths[1]
+    if File.respond_to?(:realpath)
+      assert_equal File.realpath(Dir.tmpdir), paths[2]
+      assert_equal File.realpath("..", Dir.tmpdir), paths[3]
+    elsif RUBY_PLATFORM !~ /darwin/
+      assert_equal Dir.tmpdir, paths[2]
+      assert_equal '/', paths[3]
+    end
+  ensure
+    # restore default permissions, allow the directory to be removed
+    FileUtils.chmod(0775, 'd/e') unless win_platform?
+  end
+
   def test_linked_list_find
     list = [1,2,3,4,5].inject(Gem::List.new(0)) { |m,o|
       Gem::List.new o, m
index 56c818663e520419989b203190f44bd466dc2334..792ad5f0841f63f72c1307507f0d6b9cd4f04da8 100644 (file)
@@ -2,6 +2,8 @@
 require 'rubygems/test_case'
 require "rubygems/version"
 
+require "minitest/benchmark"
+
 class TestGemVersion < Gem::TestCase
 
   class V < ::Gem::Version
@@ -102,6 +104,15 @@ class TestGemVersion < Gem::TestCase
     end
   end
 
+  def bench_anchored_version_pattern
+    assert_performance_linear 0.5 do |count|
+      version_string = count.times.map {|i| "0" * i.succ }.join(".") << "."
+      version_string =~ Gem::Version::ANCHORED_VERSION_PATTERN
+    end
+  rescue RegexpError
+    skip "It fails to allocate the memory for regex pattern of Gem::Version::ANCHORED_VERSION_PATTERN"
+  end
+
   def test_empty_version
     ["", "   ", " "].each do |empty|
       assert_equal "0", Gem::Version.new(empty).version
index a846f46833c281c8d9779c0d07f2863273185fa5..e292ce226d125b079e27e5c19e0d1ffb266c32c4 100644 (file)
@@ -38,18 +38,6 @@ class TestGemRequire < Gem::TestCase
     assert require(path), "'#{path}' was already required"
   end
 
-  def append_latch spec
-    dir = spec.gem_dir
-    Dir.chdir dir do
-      spec.files.each do |file|
-        File.open file, 'a' do |fp|
-          fp.puts "FILE_ENTERED_LATCH.release"
-          fp.puts "FILE_EXIT_LATCH.await"
-        end
-      end
-    end
-  end
-
   # Providing -I on the commandline should always beat gems
   def test_dash_i_beats_gems
     a1 = new_spec "a", "1", {"b" => "= 1"}, "lib/test_gem_require_a.rb"
@@ -80,6 +68,17 @@ class TestGemRequire < Gem::TestCase
     Object.send :remove_const, :HELLO if Object.const_defined? :HELLO
   end
 
+  def create_sync_thread
+    Thread.new do
+      begin
+        yield
+      ensure
+        FILE_ENTERED_LATCH.release
+        FILE_EXIT_LATCH.await
+      end
+    end
+  end
+
   def test_concurrent_require
     skip 'deadlock' if /^1\.8\./ =~ RUBY_VERSION
 
@@ -91,11 +90,8 @@ class TestGemRequire < Gem::TestCase
 
     install_specs a1, b1
 
-    append_latch a1
-    append_latch b1
-
-    t1 = Thread.new { assert_require 'a' }
-    t2 = Thread.new { assert_require 'b' }
+    t1 = create_sync_thread{ assert_require 'a' }
+    t2 = create_sync_thread{ assert_require 'b' }
 
     # wait until both files are waiting on the exit latch
     FILE_ENTERED_LATCH.await
@@ -106,10 +102,8 @@ class TestGemRequire < Gem::TestCase
     assert t1.join, "thread 1 should exit"
     assert t2.join, "thread 2 should exit"
   ensure
-    return if $! # skipping
-
-    Object.send :remove_const, :FILE_ENTERED_LATCH
-    Object.send :remove_const, :FILE_EXIT_LATCH
+    Object.send :remove_const, :FILE_ENTERED_LATCH if Object.const_defined? :FILE_ENTERED_LATCH
+    Object.send :remove_const, :FILE_EXIT_LATCH if Object.const_defined? :FILE_EXIT_LATCH
   end
 
   def test_require_is_not_lazy_with_exact_req