rubygems-update 2.7.5 → 2.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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: ''