rubygems-update 2.7.5 → 2.7.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubygems-update might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95086df533cd20a4f5f170842e369a7a883a80653b84ff3398adffc7514299c5
4
- data.tar.gz: c21e484af79d93bb72757b37903e990081436482f00cd63bd4b941699ba5eb88
3
+ metadata.gz: 0fa366bda5b1ed46730b8c276ce161ef32966ec9dde14f974663508163df41da
4
+ data.tar.gz: 76d8c2583652ec7266303e5af81014b7b6c440ff207e1d4cbe483959226db55d
5
5
  SHA512:
6
- metadata.gz: 1a5b15531e1362e6f141956de530d446fc9c013b59e67573a6d3ada5630e67f90c8d6b732d1895ec0bc4233a292fc1316028049dee4dc1fe947034fe531ebf9b
7
- data.tar.gz: 82ee7c7338628277e6127faeac9043b19bae6b57dee39dd48c8137f1c954866a6a6e43f6e44fbfa2428f86efe1d0d24ba724fa4f188ae4383117a3388beae171
6
+ metadata.gz: cd712f404f5e736191c312af58dafdfe897e155b9cdec68a634547606846bb31bae7cdefc46ace35eb143db7f8281c20092a534a7ccb94760ad5701d8c0ca06f
7
+ data.tar.gz: 1d80df8990549a07c91d94c5e848141f72045a71046ef0a3be5b871e8af9f0909187b196d117b6c508ec9fd0c9238a0ed96e4f9a8c7f6a9f6b59feac8a7df25b
@@ -1,5 +1,24 @@
1
1
  # coding: UTF-8
2
2
 
3
+ === 2.7.6 / 2018-02-16
4
+
5
+ Security fixes:
6
+
7
+ * Prevent path traversal when writing to a symlinked basedir outside of the root.
8
+ Discovered by nmalkin, fixed by Jonathan Claudius and Samuel Giddins.
9
+ * Fix possible Unsafe Object Deserialization Vulnerability in gem owner.
10
+ Fixed by Jonathan Claudius.
11
+ * Strictly interpret octal fields in tar headers.
12
+ Discoved by plover, fixed by Samuel Giddins.
13
+ * Raise a security error when there are duplicate files in a package.
14
+ Discovered by plover, fixed by Samuel Giddins.
15
+ * Enforce URL validation on spec homepage attribute.
16
+ Discovered by Yasin Soliman, fixed by Jonathan Claudius.
17
+ * Mitigate XSS vulnerability in homepage attribute when displayed via `gem server`.
18
+ Discovered by Yasin Soliman, fixed by Jonathan Claudius.
19
+ * Prevent Path Traversal issue during gem installation.
20
+ Discovered by nmalkin.
21
+
3
22
  === 2.7.4
4
23
 
5
24
  Bug fixes:
@@ -10,7 +10,7 @@ require 'rbconfig'
10
10
  require 'thread'
11
11
 
12
12
  module Gem
13
- VERSION = "2.7.5"
13
+ VERSION = "2.7.6"
14
14
  end
15
15
 
16
16
  # Must be first since it unloads the prelude from 1.9.2
@@ -64,7 +64,7 @@ permission to.
64
64
  end
65
65
 
66
66
  with_response response do |resp|
67
- owners = YAML.load resp.body
67
+ owners = Gem::SafeYAML.load resp.body
68
68
 
69
69
  say "Owners for gem: #{name}"
70
70
  owners.each do |owner|
@@ -378,7 +378,7 @@ EOM
378
378
  File.dirname destination
379
379
  end
380
380
 
381
- FileUtils.mkdir_p mkdir, mkdir_options
381
+ mkdir_p_safe mkdir, mkdir_options, destination_dir, entry.full_name
382
382
 
383
383
  File.open destination, 'wb' do |out|
384
384
  out.write entry.read
@@ -416,20 +416,35 @@ EOM
416
416
  raise Gem::Package::PathError.new(filename, destination_dir) if
417
417
  filename.start_with? '/'
418
418
 
419
- destination_dir = File.realpath destination_dir if
420
- File.respond_to? :realpath
419
+ destination_dir = realpath destination_dir
421
420
  destination_dir = File.expand_path destination_dir
422
421
 
423
422
  destination = File.join destination_dir, filename
424
423
  destination = File.expand_path destination
425
424
 
426
425
  raise Gem::Package::PathError.new(destination, destination_dir) unless
427
- destination.start_with? destination_dir
426
+ destination.start_with? destination_dir + '/'
428
427
 
429
428
  destination.untaint
430
429
  destination
431
430
  end
432
431
 
432
+ def mkdir_p_safe mkdir, mkdir_options, destination_dir, file_name
433
+ destination_dir = realpath File.expand_path(destination_dir)
434
+ parts = mkdir.split(File::SEPARATOR)
435
+ parts.reduce do |path, basename|
436
+ path = realpath path unless path == ""
437
+ path = File.expand_path(path + File::SEPARATOR + basename)
438
+ lstat = File.lstat path rescue nil
439
+ if !lstat || !lstat.directory?
440
+ unless path.start_with? destination_dir and (FileUtils.mkdir path, mkdir_options rescue false)
441
+ raise Gem::Package::PathError.new(file_name, destination_dir)
442
+ end
443
+ end
444
+ path
445
+ end
446
+ end
447
+
433
448
  ##
434
449
  # Loads a Gem::Specification from the TarEntry +entry+
435
450
 
@@ -603,6 +618,10 @@ EOM
603
618
  raise Gem::Package::FormatError.new \
604
619
  'package content (data.tar.gz) is missing', @gem
605
620
  end
621
+
622
+ if duplicates = @files.group_by {|f| f }.select {|k,v| v.size > 1 }.map(&:first) and duplicates.any?
623
+ raise Gem::Security::Exception, "duplicate files in the package: (#{duplicates.map(&:inspect).join(', ')})"
624
+ end
606
625
  end
607
626
 
608
627
  ##
@@ -616,6 +635,16 @@ EOM
616
635
  raise Gem::Package::FormatError.new(e.message, entry.full_name)
617
636
  end
618
637
 
638
+ if File.respond_to? :realpath
639
+ def realpath file
640
+ File.realpath file
641
+ end
642
+ else
643
+ def realpath file
644
+ file
645
+ end
646
+ end
647
+
619
648
  end
620
649
 
621
650
  require 'rubygems/package/digest_io'
@@ -104,25 +104,30 @@ class Gem::Package::TarHeader
104
104
  fields = header.unpack UNPACK_FORMAT
105
105
 
106
106
  new :name => fields.shift,
107
- :mode => fields.shift.oct,
108
- :uid => fields.shift.oct,
109
- :gid => fields.shift.oct,
110
- :size => fields.shift.oct,
111
- :mtime => fields.shift.oct,
112
- :checksum => fields.shift.oct,
107
+ :mode => strict_oct(fields.shift),
108
+ :uid => strict_oct(fields.shift),
109
+ :gid => strict_oct(fields.shift),
110
+ :size => strict_oct(fields.shift),
111
+ :mtime => strict_oct(fields.shift),
112
+ :checksum => strict_oct(fields.shift),
113
113
  :typeflag => fields.shift,
114
114
  :linkname => fields.shift,
115
115
  :magic => fields.shift,
116
- :version => fields.shift.oct,
116
+ :version => strict_oct(fields.shift),
117
117
  :uname => fields.shift,
118
118
  :gname => fields.shift,
119
- :devmajor => fields.shift.oct,
120
- :devminor => fields.shift.oct,
119
+ :devmajor => strict_oct(fields.shift),
120
+ :devminor => strict_oct(fields.shift),
121
121
  :prefix => fields.shift,
122
122
 
123
123
  :empty => empty
124
124
  end
125
125
 
126
+ def self.strict_oct(str)
127
+ return str.oct if str =~ /\A[0-7]*\z/
128
+ raise ArgumentError, "#{str.inspect} is not an octal string"
129
+ end
130
+
126
131
  ##
127
132
  # Creates a new TarHeader using +vals+
128
133
 
@@ -196,6 +196,8 @@ class Gem::Package::TarWriter
196
196
  digest_name == signer.digest_name
197
197
  end
198
198
 
199
+ raise "no #{signer.digest_name} in #{digests.values.compact}" unless signature_digest
200
+
199
201
  if signer.key then
200
202
  signature = signer.sign signature_digest.digest
201
203
 
@@ -623,6 +623,18 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
623
623
  executables = nil if executables.empty?
624
624
  executables.last["is_last"] = true if executables
625
625
 
626
+ # Pre-process spec homepage for safety reasons
627
+ begin
628
+ homepage_uri = URI.parse(spec.homepage)
629
+ if [URI::HTTP, URI::HTTPS].member? homepage_uri.class
630
+ homepage_uri = spec.homepage
631
+ else
632
+ homepage_uri = "."
633
+ end
634
+ rescue URI::InvalidURIError
635
+ homepage_uri = "."
636
+ end
637
+
626
638
  specs << {
627
639
  "authors" => spec.authors.sort.join(", "),
628
640
  "date" => spec.date.to_s,
@@ -632,7 +644,7 @@ div.method-source-code pre { color: #ffdead; overflow: hidden; }
632
644
  "only_one_executable" => (executables && executables.size == 1),
633
645
  "full_name" => spec.full_name,
634
646
  "has_deps" => !deps.empty?,
635
- "homepage" => spec.homepage,
647
+ "homepage" => homepage_uri,
636
648
  "name" => spec.name,
637
649
  "rdoc_installed" => Gem::RDoc.new(spec).rdoc_installed?,
638
650
  "ri_installed" => Gem::RDoc.new(spec).ri_installed?,
@@ -15,6 +15,7 @@ require 'rubygems/basic_specification'
15
15
  require 'rubygems/stub_specification'
16
16
  require 'rubygems/util/list'
17
17
  require 'stringio'
18
+ require 'uri'
18
19
 
19
20
  ##
20
21
  # The Specification class contains the information for a Gem. Typically
@@ -2822,10 +2823,16 @@ http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard li
2822
2823
  raise Gem::InvalidSpecificationException, "#{lazy} is not a summary"
2823
2824
  end
2824
2825
 
2825
- if homepage and not homepage.empty? and
2826
- homepage !~ /\A[a-z][a-z\d+.-]*:/i then
2827
- raise Gem::InvalidSpecificationException,
2828
- "\"#{homepage}\" is not a URI"
2826
+ # Make sure a homepage is valid HTTP/HTTPS URI
2827
+ if homepage and not homepage.empty?
2828
+ begin
2829
+ homepage_uri = URI.parse(homepage)
2830
+ unless [URI::HTTP, URI::HTTPS].member? homepage_uri.class
2831
+ raise Gem::InvalidSpecificationException, "\"#{homepage}\" is not a valid HTTP URI"
2832
+ end
2833
+ rescue URI::InvalidURIError
2834
+ raise Gem::InvalidSpecificationException, "\"#{homepage}\" is not a valid HTTP URI"
2835
+ end
2829
2836
  end
2830
2837
 
2831
2838
  # Warnings
@@ -43,6 +43,31 @@ EOF
43
43
  assert_match %r{- 4}, @ui.output
44
44
  end
45
45
 
46
+ def test_show_owners_dont_load_objects
47
+ skip "testing a psych-only API" unless defined?(::Psych::DisallowedClass)
48
+
49
+ response = <<EOF
50
+ ---
51
+ - email: !ruby/object:Object {}
52
+ id: 1
53
+ handle: user1
54
+ - email: user2@example.com
55
+ - id: 3
56
+ handle: user3
57
+ - id: 4
58
+ EOF
59
+
60
+ @fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners.yaml"] = [response, 200, 'OK']
61
+
62
+ assert_raises Psych::DisallowedClass do
63
+ use_ui @ui do
64
+ @cmd.show_owners("freewill")
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+
46
71
  def test_show_owners_setting_up_host_through_env_var
47
72
  response = "- email: user1@example.com\n"
48
73
  host = "http://rubygems.example"
@@ -455,6 +455,31 @@ class TestGemPackage < Gem::Package::TarTestCase
455
455
  File.read(extracted)
456
456
  end
457
457
 
458
+ def test_extract_symlink_parent
459
+ skip 'symlink not supported' if Gem.win_platform?
460
+
461
+ package = Gem::Package.new @gem
462
+
463
+ tgz_io = util_tar_gz do |tar|
464
+ tar.mkdir 'lib', 0755
465
+ tar.add_symlink 'lib/link', '../..', 0644
466
+ tar.add_file 'lib/link/outside.txt', 0644 do |io| io.write 'hi' end
467
+ end
468
+
469
+ # Extract into a subdirectory of @destination; if this test fails it writes
470
+ # a file outside destination_subdir, but we want the file to remain inside
471
+ # @destination so it will be cleaned up.
472
+ destination_subdir = File.join @destination, 'subdir'
473
+ FileUtils.mkdir_p destination_subdir
474
+
475
+ e = assert_raises Gem::Package::PathError do
476
+ package.extract_tar_gz tgz_io, destination_subdir
477
+ end
478
+
479
+ assert_equal("installing into parent path lib/link/outside.txt of " +
480
+ "#{destination_subdir} is not allowed", e.message)
481
+ end
482
+
458
483
  def test_extract_tar_gz_directory
459
484
  package = Gem::Package.new @gem
460
485
 
@@ -566,6 +591,21 @@ class TestGemPackage < Gem::Package::TarTestCase
566
591
  "#{@destination} is not allowed", e.message)
567
592
  end
568
593
 
594
+ def test_install_location_suffix
595
+ package = Gem::Package.new @gem
596
+
597
+ filename = "../#{File.basename(@destination)}suffix.rb"
598
+
599
+ e = assert_raises Gem::Package::PathError do
600
+ package.install_location filename, @destination
601
+ end
602
+
603
+ parent = File.expand_path File.join @destination, filename
604
+
605
+ assert_equal("installing into parent path #{parent} of " +
606
+ "#{@destination} is not allowed", e.message)
607
+ end
608
+
569
609
  def test_load_spec
570
610
  entry = StringIO.new Gem.gzip @spec.to_yaml
571
611
  def entry.full_name() 'metadata.gz' end
@@ -723,6 +763,32 @@ class TestGemPackage < Gem::Package::TarTestCase
723
763
  assert_match %r%nonexistent.gem$%, e.message
724
764
  end
725
765
 
766
+ def test_verify_duplicate_file
767
+ FileUtils.mkdir_p 'lib'
768
+ FileUtils.touch 'lib/code.rb'
769
+
770
+ build = Gem::Package.new @gem
771
+ build.spec = @spec
772
+ build.setup_signer
773
+ open @gem, 'wb' do |gem_io|
774
+ Gem::Package::TarWriter.new gem_io do |gem|
775
+ build.add_metadata gem
776
+ build.add_contents gem
777
+
778
+ gem.add_file_simple 'a.sig', 0444, 0
779
+ gem.add_file_simple 'a.sig', 0444, 0
780
+ end
781
+ end
782
+
783
+ package = Gem::Package.new @gem
784
+
785
+ e = assert_raises Gem::Security::Exception do
786
+ package.verify
787
+ end
788
+
789
+ assert_equal 'duplicate files in the package: ("a.sig")', e.message
790
+ end
791
+
726
792
  def test_verify_security_policy
727
793
  skip 'openssl is missing' unless defined?(OpenSSL::SSL)
728
794
 
@@ -780,7 +846,13 @@ class TestGemPackage < Gem::Package::TarTestCase
780
846
 
781
847
  # write bogus data.tar.gz to foil signature
782
848
  bogus_data = Gem.gzip 'hello'
783
- gem.add_file_simple 'data.tar.gz', 0444, bogus_data.length do |io|
849
+ fake_signer = Class.new do
850
+ def digest_name; 'SHA512'; end
851
+ def digest_algorithm; Digest(:SHA512); end
852
+ def key; 'key'; end
853
+ def sign(*); 'fake_sig'; end
854
+ end
855
+ gem.add_file_signed 'data2.tar.gz', 0444, fake_signer.new do |io|
784
856
  io.write bogus_data
785
857
  end
786
858
 
@@ -143,5 +143,25 @@ group\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
143
143
  assert_equal '012467', @tar_header.checksum
144
144
  end
145
145
 
146
+ def test_from_bad_octal
147
+ test_cases = [
148
+ "00000006,44\000", # bogus character
149
+ "00000006789\000", # non-octal digit
150
+ "+0000001234\000", # positive sign
151
+ "-0000001000\000", # negative sign
152
+ "0x000123abc\000", # radix prefix
153
+ ]
154
+
155
+ test_cases.each do |val|
156
+ header_s = @tar_header.to_s
157
+ # overwrite the size field
158
+ header_s[124, 12] = val
159
+ io = TempIO.new header_s
160
+ assert_raises ArgumentError do
161
+ new_header = Gem::Package::TarHeader.from io
162
+ end
163
+ end
164
+ end
165
+
146
166
  end
147
167
 
@@ -353,6 +353,171 @@ class TestGemServer < Gem::TestCase
353
353
  assert_match 'z 9', @res.body
354
354
  end
355
355
 
356
+
357
+ def test_xss_homepage_fix_289313
358
+ data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
359
+ dir = "#{@gemhome}2"
360
+
361
+ spec = util_spec 'xsshomepagegem', 1
362
+ spec.homepage = "javascript:confirm(document.domain)"
363
+
364
+ specs_dir = File.join dir, 'specifications'
365
+ FileUtils.mkdir_p specs_dir
366
+
367
+ open File.join(specs_dir, spec.spec_name), 'w' do |io|
368
+ io.write spec.to_ruby
369
+ end
370
+
371
+ server = Gem::Server.new dir, process_based_port, false
372
+
373
+ @req.parse data
374
+
375
+ server.root @req, @res
376
+
377
+ assert_equal 200, @res.status
378
+ assert_match 'xsshomepagegem 1', @res.body
379
+
380
+ # This verifies that the homepage for this spec is not displayed and is set to ".", because it's not a
381
+ # valid HTTP/HTTPS URL and could be unsafe in an HTML context. We would prefer to throw an exception here,
382
+ # but spec.homepage is currently free form and not currently required to be a URL, this behavior may be
383
+ # validated in future versions of Gem::Specification.
384
+ #
385
+ # There are two variant we're checking here, one where rdoc is not present, and one where rdoc is present in the same regex:
386
+ #
387
+ # Variant #1 - rdoc not installed
388
+ #
389
+ # <b>xsshomepagegem 1</b>
390
+ #
391
+ #
392
+ # <span title="rdoc not installed">[rdoc]</span>
393
+ #
394
+ #
395
+ #
396
+ # <a href="." title=".">[www]</a>
397
+ #
398
+ # Variant #2 - rdoc installed
399
+ #
400
+ # <b>xsshomepagegem 1</b>
401
+ #
402
+ #
403
+ # <a href="\/doc_root\/xsshomepagegem-1\/">\[rdoc\]<\/a>
404
+ #
405
+ #
406
+ #
407
+ # <a href="." title=".">[www]</a>
408
+ 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>/
409
+ assert_match regex_match, @res.body
410
+ end
411
+
412
+ def test_invalid_homepage
413
+ data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
414
+ dir = "#{@gemhome}2"
415
+
416
+ spec = util_spec 'invalidhomepagegem', 1
417
+ spec.homepage = "notavalidhomepageurl"
418
+
419
+ specs_dir = File.join dir, 'specifications'
420
+ FileUtils.mkdir_p specs_dir
421
+
422
+ open File.join(specs_dir, spec.spec_name), 'w' do |io|
423
+ io.write spec.to_ruby
424
+ end
425
+
426
+ server = Gem::Server.new dir, process_based_port, false
427
+
428
+ @req.parse data
429
+
430
+ server.root @req, @res
431
+
432
+ assert_equal 200, @res.status
433
+ assert_match 'invalidhomepagegem 1', @res.body
434
+
435
+ # This verifies that the homepage for this spec is not displayed and is set to ".", because it's not a
436
+ # valid HTTP/HTTPS URL and could be unsafe in an HTML context. We would prefer to throw an exception here,
437
+ # but spec.homepage is currently free form and not currently required to be a URL, this behavior may be
438
+ # validated in future versions of Gem::Specification.
439
+ #
440
+ # There are two variant we're checking here, one where rdoc is not present, and one where rdoc is present in the same regex:
441
+ #
442
+ # Variant #1 - rdoc not installed
443
+ #
444
+ # <b>invalidhomepagegem 1</b>
445
+ #
446
+ #
447
+ # <span title="rdoc not installed">[rdoc]</span>
448
+ #
449
+ #
450
+ #
451
+ # <a href="." title=".">[www]</a>
452
+ #
453
+ # Variant #2 - rdoc installed
454
+ #
455
+ # <b>invalidhomepagegem 1</b>
456
+ #
457
+ #
458
+ # <a href="\/doc_root\/invalidhomepagegem-1\/">\[rdoc\]<\/a>
459
+ #
460
+ #
461
+ #
462
+ # <a href="." title=".">[www]</a>
463
+ 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>/
464
+ assert_match regex_match, @res.body
465
+ end
466
+
467
+ def test_valid_homepage_http
468
+ data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
469
+ dir = "#{@gemhome}2"
470
+
471
+ spec = util_spec 'validhomepagegemhttp', 1
472
+ spec.homepage = "http://rubygems.org"
473
+
474
+ specs_dir = File.join dir, 'specifications'
475
+ FileUtils.mkdir_p specs_dir
476
+
477
+ open File.join(specs_dir, spec.spec_name), 'w' do |io|
478
+ io.write spec.to_ruby
479
+ end
480
+
481
+ server = Gem::Server.new dir, process_based_port, false
482
+
483
+ @req.parse data
484
+
485
+ server.root @req, @res
486
+
487
+ assert_equal 200, @res.status
488
+ assert_match 'validhomepagegemhttp 1', @res.body
489
+
490
+ 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>/
491
+ assert_match regex_match, @res.body
492
+ end
493
+
494
+ def test_valid_homepage_https
495
+ data = StringIO.new "GET / HTTP/1.0\r\n\r\n"
496
+ dir = "#{@gemhome}2"
497
+
498
+ spec = util_spec 'validhomepagegemhttps', 1
499
+ spec.homepage = "https://rubygems.org"
500
+
501
+ specs_dir = File.join dir, 'specifications'
502
+ FileUtils.mkdir_p specs_dir
503
+
504
+ open File.join(specs_dir, spec.spec_name), 'w' do |io|
505
+ io.write spec.to_ruby
506
+ end
507
+
508
+ server = Gem::Server.new dir, process_based_port, false
509
+
510
+ @req.parse data
511
+
512
+ server.root @req, @res
513
+
514
+ assert_equal 200, @res.status
515
+ assert_match 'validhomepagegemhttps 1', @res.body
516
+
517
+ 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>/
518
+ assert_match regex_match, @res.body
519
+ end
520
+
356
521
  def test_specs
357
522
  data = StringIO.new "GET /specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n"
358
523
  @req.parse data
@@ -2886,7 +2886,22 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use:
2886
2886
  @a1.validate
2887
2887
  end
2888
2888
 
2889
- assert_equal '"over at my cool site" is not a URI', e.message
2889
+ assert_equal '"over at my cool site" is not a valid HTTP URI', e.message
2890
+
2891
+ @a1.homepage = 'ftp://rubygems.org'
2892
+
2893
+ e = assert_raises Gem::InvalidSpecificationException do
2894
+ @a1.validate
2895
+ end
2896
+
2897
+ assert_equal '"ftp://rubygems.org" is not a valid HTTP URI', e.message
2898
+
2899
+ @a1.homepage = 'http://rubygems.org'
2900
+ assert_equal true, @a1.validate
2901
+
2902
+ @a1.homepage = 'https://rubygems.org'
2903
+ assert_equal true, @a1.validate
2904
+
2890
2905
  end
2891
2906
  end
2892
2907
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubygems-update
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.5
4
+ version: 2.7.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Weirich
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-02-06 00:00:00.000000000 Z
13
+ date: 2018-02-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: builder
@@ -804,7 +804,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
804
804
  version: '0'
805
805
  requirements: []
806
806
  rubyforge_project:
807
- rubygems_version: 2.7.3
807
+ rubygems_version: 2.7.4
808
808
  signing_key:
809
809
  specification_version: 4
810
810
  summary: ''