rubygems-update 3.4.10 → 3.4.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/Manifest.txt +5 -0
  4. data/bundler/CHANGELOG.md +48 -0
  5. data/bundler/exe/bundle +5 -13
  6. data/bundler/lib/bundler/build_metadata.rb +2 -2
  7. data/bundler/lib/bundler/definition.rb +14 -6
  8. data/bundler/lib/bundler/gem_version_promoter.rb +1 -1
  9. data/bundler/lib/bundler/installer.rb +1 -1
  10. data/bundler/lib/bundler/lazy_specification.rb +1 -1
  11. data/bundler/lib/bundler/lockfile_parser.rb +1 -0
  12. data/bundler/lib/bundler/man/bundle-cache.1 +2 -2
  13. data/bundler/lib/bundler/man/bundle-cache.1.ronn +2 -2
  14. data/bundler/lib/bundler/resolver/base.rb +1 -3
  15. data/bundler/lib/bundler/ruby_version.rb +1 -1
  16. data/bundler/lib/bundler/rubygems_ext.rb +5 -3
  17. data/bundler/lib/bundler/safe_marshal.rb +31 -0
  18. data/bundler/lib/bundler/settings.rb +3 -2
  19. data/bundler/lib/bundler/source/rubygems.rb +12 -12
  20. data/bundler/lib/bundler/spec_set.rb +2 -2
  21. data/bundler/lib/bundler/templates/newgem/bin/console.tt +0 -4
  22. data/bundler/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt +5 -0
  23. data/bundler/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +1 -1
  24. data/bundler/lib/bundler/templates/newgem/newgem.gemspec.tt +2 -1
  25. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb +9 -4
  26. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +2 -2
  27. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  28. data/bundler/lib/bundler/version.rb +1 -1
  29. data/bundler/lib/bundler.rb +8 -16
  30. data/lib/rubygems/command_manager.rb +2 -2
  31. data/lib/rubygems/commands/owner_command.rb +4 -2
  32. data/lib/rubygems/exceptions.rb +10 -0
  33. data/lib/rubygems/gemcutter_utilities.rb +48 -6
  34. data/lib/rubygems/installer.rb +16 -1
  35. data/lib/rubygems/request_set.rb +2 -2
  36. data/lib/rubygems/specification.rb +3 -1
  37. data/lib/rubygems/stub_specification.rb +2 -1
  38. data/lib/rubygems/webauthn_listener/response.rb +161 -0
  39. data/lib/rubygems/webauthn_listener.rb +92 -0
  40. data/lib/rubygems.rb +1 -1
  41. data/rubygems-update.gemspec +4 -3
  42. data/test/rubygems/helper.rb +14 -0
  43. data/test/rubygems/test_bundled_ca.rb +1 -1
  44. data/test/rubygems/test_config.rb +1 -1
  45. data/test/rubygems/test_deprecate.rb +1 -1
  46. data/test/rubygems/test_exit.rb +1 -1
  47. data/test/rubygems/test_gem.rb +7 -0
  48. data/test/rubygems/test_gem_commands_owner_command.rb +67 -0
  49. data/test/rubygems/test_gem_commands_pristine_command.rb +1 -1
  50. data/test/rubygems/test_gem_commands_push_command.rb +73 -0
  51. data/test/rubygems/test_gem_commands_setup_command.rb +1 -1
  52. data/test/rubygems/test_gem_commands_yank_command.rb +84 -0
  53. data/test/rubygems/test_gem_ext_cargo_builder.rb +1 -0
  54. data/test/rubygems/test_gem_gem_runner.rb +5 -5
  55. data/test/rubygems/test_gem_gemcutter_utilities.rb +72 -4
  56. data/test/rubygems/test_gem_installer.rb +50 -2
  57. data/test/rubygems/test_gem_uninstaller.rb +4 -4
  58. data/test/rubygems/test_kernel.rb +1 -1
  59. data/test/rubygems/test_project_sanity.rb +32 -3
  60. data/test/rubygems/test_remote_fetch_error.rb +1 -1
  61. data/test/rubygems/test_webauthn_listener.rb +120 -0
  62. data/test/rubygems/test_webauthn_listener_response.rb +93 -0
  63. data/test/rubygems/utilities.rb +43 -3
  64. metadata +13 -6
@@ -39,16 +39,6 @@ module Bundler
39
39
  environment_preserver.replace_with_backup
40
40
  SUDO_MUTEX = Thread::Mutex.new
41
41
 
42
- SAFE_MARSHAL_CLASSES = [Symbol, TrueClass, String, Array, Hash, Gem::Version, Gem::Specification].freeze
43
- SAFE_MARSHAL_ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed."
44
- SAFE_MARSHAL_PROC = proc do |object|
45
- object.tap do
46
- unless SAFE_MARSHAL_CLASSES.include?(object.class)
47
- raise TypeError, format(SAFE_MARSHAL_ERROR, object.class, SAFE_MARSHAL_CLASSES.join(", "))
48
- end
49
- end
50
- end
51
-
52
42
  autoload :Definition, File.expand_path("bundler/definition", __dir__)
53
43
  autoload :Dependency, File.expand_path("bundler/dependency", __dir__)
54
44
  autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__)
@@ -86,10 +76,11 @@ module Bundler
86
76
  autoload :UI, File.expand_path("bundler/ui", __dir__)
87
77
  autoload :URICredentialsFilter, File.expand_path("bundler/uri_credentials_filter", __dir__)
88
78
  autoload :URINormalizer, File.expand_path("bundler/uri_normalizer", __dir__)
79
+ autoload :SafeMarshal, File.expand_path("bundler/safe_marshal", __dir__)
89
80
 
90
81
  class << self
91
82
  def configure
92
- @configured ||= configure_gem_home_and_path
83
+ @configure ||= configure_gem_home_and_path
93
84
  end
94
85
 
95
86
  def ui
@@ -219,9 +210,10 @@ module Bundler
219
210
  end
220
211
 
221
212
  def frozen_bundle?
222
- frozen = settings[:deployment]
223
- frozen ||= settings[:frozen]
224
- frozen
213
+ frozen = settings[:frozen]
214
+ return frozen unless frozen.nil?
215
+
216
+ settings[:deployment]
225
217
  end
226
218
 
227
219
  def locked_gems
@@ -523,7 +515,7 @@ EOF
523
515
  end
524
516
 
525
517
  def safe_load_marshal(data)
526
- load_marshal(data, :marshal_proc => SAFE_MARSHAL_PROC)
518
+ load_marshal(data, :marshal_proc => SafeMarshal.proc)
527
519
  end
528
520
 
529
521
  def load_gemspec(file, validate = false)
@@ -581,7 +573,7 @@ EOF
581
573
  @bin_path = nil
582
574
  @bundler_major_version = nil
583
575
  @bundle_path = nil
584
- @configured = nil
576
+ @configure = nil
585
577
  @configured_bundle_path = nil
586
578
  @definition = nil
587
579
  @load = nil
@@ -83,7 +83,7 @@ class Gem::CommandManager
83
83
  # Return the authoritative instance of the command manager.
84
84
 
85
85
  def self.instance
86
- @command_manager ||= new
86
+ @instance ||= new
87
87
  end
88
88
 
89
89
  ##
@@ -98,7 +98,7 @@ class Gem::CommandManager
98
98
  # Reset the authoritative instance of the command manager.
99
99
 
100
100
  def self.reset
101
- @command_manager = nil
101
+ @instance = nil
102
102
  end
103
103
 
104
104
  ##
@@ -98,8 +98,10 @@ permission to.
98
98
  action = method == :delete ? "Removing" : "Adding"
99
99
 
100
100
  with_response response, "#{action} #{owner}"
101
- rescue
102
- # ignore
101
+ rescue Gem::WebauthnVerificationError => e
102
+ raise e
103
+ rescue StandardError
104
+ # ignore early exits to allow for completing the iteration of all owners
103
105
  end
104
106
  end
105
107
  end
@@ -213,6 +213,16 @@ class Gem::RubyVersionMismatch < Gem::Exception; end
213
213
 
214
214
  class Gem::VerificationError < Gem::Exception; end
215
215
 
216
+ ##
217
+ # Raised by Gem::WebauthnListener when an error occurs during security
218
+ # device verification.
219
+
220
+ class Gem::WebauthnVerificationError < Gem::Exception
221
+ def initialize(message)
222
+ super "Security device verification failed: #{message}"
223
+ end
224
+ end
225
+
216
226
  ##
217
227
  # Raised to indicate that a system exit should occur with the specified
218
228
  # exit_code
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative "remote_fetcher"
3
3
  require_relative "text"
4
+ require_relative "webauthn_listener"
4
5
 
5
6
  ##
6
7
  # Utility methods for using the RubyGems API.
@@ -82,7 +83,7 @@ module Gem::GemcutterUtilities
82
83
  #
83
84
  # If +allowed_push_host+ metadata is present, then it will only allow that host.
84
85
 
85
- def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, &block)
86
+ def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, credentials: {}, &block)
86
87
  require "net/http"
87
88
 
88
89
  self.host = host if host
@@ -105,7 +106,7 @@ module Gem::GemcutterUtilities
105
106
  response = request_with_otp(method, uri, &block)
106
107
 
107
108
  if mfa_unauthorized?(response)
108
- ask_otp
109
+ fetch_otp(credentials)
109
110
  response = request_with_otp(method, uri, &block)
110
111
  end
111
112
 
@@ -167,11 +168,12 @@ module Gem::GemcutterUtilities
167
168
  mfa_params = get_mfa_params(profile)
168
169
  all_params = scope_params.merge(mfa_params)
169
170
  warning = profile["warning"]
171
+ credentials = { email: email, password: password }
170
172
 
171
173
  say "#{warning}\n" if warning
172
174
 
173
175
  response = rubygems_api_request(:post, "api/v1/api_key",
174
- sign_in_host, scope: scope) do |request|
176
+ sign_in_host, credentials: credentials, scope: scope) do |request|
175
177
  request.basic_auth email, password
176
178
  request["OTP"] = otp if otp
177
179
  request.body = URI.encode_www_form({ name: key_name }.merge(all_params))
@@ -250,9 +252,49 @@ module Gem::GemcutterUtilities
250
252
  end
251
253
  end
252
254
 
253
- def ask_otp
254
- say "You have enabled multi-factor authentication. Please enter OTP code."
255
- options[:otp] = ask "Code: "
255
+ def fetch_otp(credentials)
256
+ options[:otp] = if webauthn_url = webauthn_verification_url(credentials)
257
+ wait_for_otp(webauthn_url)
258
+ else
259
+ say "You have enabled multi-factor authentication. Please enter OTP code."
260
+ ask "Code: "
261
+ end
262
+ end
263
+
264
+ def wait_for_otp(webauthn_url)
265
+ server = TCPServer.new 0
266
+ port = server.addr[1].to_s
267
+
268
+ thread = Thread.new do
269
+ Thread.current[:otp] = Gem::WebauthnListener.wait_for_otp_code(host, server)
270
+ rescue Gem::WebauthnVerificationError => e
271
+ Thread.current[:error] = e
272
+ end
273
+ thread.abort_on_exception = true
274
+ thread.report_on_exception = false
275
+
276
+ url_with_port = "#{webauthn_url}?port=#{port}"
277
+ say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
278
+
279
+ thread.join
280
+ if error = thread[:error]
281
+ alert_error error.message
282
+ terminate_interaction(1)
283
+ end
284
+
285
+ say "You are verified with a security device. You may close the browser window."
286
+ thread[:otp]
287
+ end
288
+
289
+ def webauthn_verification_url(credentials)
290
+ response = rubygems_api_request(:post, "api/v1/webauthn_verification") do |request|
291
+ if credentials.empty?
292
+ request.add_field "Authorization", api_key
293
+ else
294
+ request.basic_auth credentials[:email], credentials[:password]
295
+ end
296
+ end
297
+ response.is_a?(Net::HTTPSuccess) ? response.body : nil
256
298
  end
257
299
 
258
300
  def pretty_host(host)
@@ -342,6 +342,8 @@ class Gem::Installer
342
342
 
343
343
  Gem::Specification.add_spec(spec)
344
344
 
345
+ load_plugin
346
+
345
347
  run_post_install_hooks
346
348
 
347
349
  spec
@@ -388,7 +390,7 @@ class Gem::Installer
388
390
  # we'll be installing into.
389
391
 
390
392
  def installed_specs
391
- @specs ||= begin
393
+ @installed_specs ||= begin
392
394
  specs = []
393
395
 
394
396
  Gem::Util.glob_files_in_dir("*.gemspec", File.join(gem_home, "specifications")).each do |path|
@@ -1002,4 +1004,17 @@ TEXT
1002
1004
  ""
1003
1005
  end
1004
1006
  end
1007
+
1008
+ def load_plugin
1009
+ specs = Gem::Specification.find_all_by_name(spec.name)
1010
+ # If old version already exists, this plugin isn't loaded
1011
+ # immediately. It's for avoiding a case that multiple versions
1012
+ # are loaded at the same time.
1013
+ return unless specs.size == 1
1014
+
1015
+ plugin_files = spec.plugins.map do |plugin|
1016
+ File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}")
1017
+ end
1018
+ Gem.load_plugin_files(plugin_files)
1019
+ end
1005
1020
  end
@@ -107,7 +107,7 @@ class Gem::RequestSet
107
107
  @requests = []
108
108
  @sets = []
109
109
  @soft_missing = false
110
- @sorted = nil
110
+ @sorted_requests = nil
111
111
  @specs = nil
112
112
  @vendor_set = nil
113
113
  @source_set = nil
@@ -424,7 +424,7 @@ class Gem::RequestSet
424
424
  end
425
425
 
426
426
  def sorted_requests
427
- @sorted ||= strongly_connected_components.flatten
427
+ @sorted_requests ||= strongly_connected_components.flatten
428
428
  end
429
429
 
430
430
  def specs
@@ -2233,7 +2233,7 @@ class Gem::Specification < Gem::BasicSpecification
2233
2233
  # The platform this gem runs on. See Gem::Platform for details.
2234
2234
 
2235
2235
  def platform
2236
- @new_platform ||= Gem::Platform::RUBY
2236
+ @new_platform ||= Gem::Platform::RUBY # rubocop:disable Naming/MemoizedInstanceVariableName
2237
2237
  end
2238
2238
 
2239
2239
  def pretty_print(q) # :nodoc:
@@ -2712,6 +2712,8 @@ class Gem::Specification < Gem::BasicSpecification
2712
2712
  end
2713
2713
 
2714
2714
  @installed_by_version ||= nil
2715
+
2716
+ nil
2715
2717
  end
2716
2718
 
2717
2719
  def flatten_require_paths # :nodoc:
@@ -183,7 +183,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
183
183
  ##
184
184
  # The full Gem::Specification for this gem, loaded from evalling its gemspec
185
185
 
186
- def to_spec
186
+ def spec
187
187
  @spec ||= if @data
188
188
  loaded = Gem.loaded_specs[name]
189
189
  loaded if loaded && loaded.version == version
@@ -191,6 +191,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
191
191
 
192
192
  @spec ||= Gem::Specification.load(loaded_from)
193
193
  end
194
+ alias_method :to_spec, :spec
194
195
 
195
196
  ##
196
197
  # Is this StubSpecification valid? i.e. have we found a stub line, OR does
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # The WebauthnListener Response class is used by the WebauthnListener to create
5
+ # responses to be sent to the Gem host. It creates a Net::HTTPResponse instance
6
+ # when initialized and can be converted to the appropriate format to be sent by a socket using `to_s`.
7
+ # Net::HTTPResponse instances cannot be directly sent over a socket.
8
+ #
9
+ # Types of response classes:
10
+ # - OkResponse
11
+ # - NoContentResponse
12
+ # - BadRequestResponse
13
+ # - NotFoundResponse
14
+ # - MethodNotAllowedResponse
15
+ #
16
+ # Example usage:
17
+ #
18
+ # server = TCPServer.new(0)
19
+ # socket = server.accept
20
+ #
21
+ # response = OkResponse.for("https://rubygems.example")
22
+ # socket.print response.to_s
23
+ # socket.close
24
+ #
25
+
26
+ class Gem::WebauthnListener
27
+ class Response
28
+ attr_reader :http_response
29
+
30
+ def self.for(host)
31
+ new(host)
32
+ end
33
+
34
+ def initialize(host)
35
+ @host = host
36
+
37
+ build_http_response
38
+ end
39
+
40
+ def to_s
41
+ status_line = "HTTP/#{@http_response.http_version} #{@http_response.code} #{@http_response.message}\r\n"
42
+ headers = @http_response.to_hash.map {|header, value| "#{header}: #{value.join(", ")}\r\n" }.join + "\r\n"
43
+ body = @http_response.body ? "#{@http_response.body}\n" : ""
44
+
45
+ status_line + headers + body
46
+ end
47
+
48
+ private
49
+
50
+ # Must be implemented in subclasses
51
+ def code
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def reason_phrase
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def body; end
60
+
61
+ def build_http_response
62
+ response_class = Net::HTTPResponse::CODE_TO_OBJ[code.to_s]
63
+ @http_response = response_class.new("1.1", code, reason_phrase)
64
+ @http_response.instance_variable_set(:@read, true)
65
+
66
+ add_connection_header
67
+ add_access_control_headers
68
+ add_body
69
+ end
70
+
71
+ def add_connection_header
72
+ @http_response["connection"] = "close"
73
+ end
74
+
75
+ def add_access_control_headers
76
+ @http_response["access-control-allow-origin"] = @host
77
+ @http_response["access-control-allow-methods"] = "POST"
78
+ @http_response["access-control-allow-headers"] = %w[Content-Type Authorization x-csrf-token]
79
+ end
80
+
81
+ def add_body
82
+ return unless body
83
+ @http_response["content-type"] = "text/plain"
84
+ @http_response["content-length"] = body.bytesize
85
+ @http_response.instance_variable_set(:@body, body)
86
+ end
87
+ end
88
+
89
+ class OkResponse < Response
90
+ private
91
+
92
+ def code
93
+ 200
94
+ end
95
+
96
+ def reason_phrase
97
+ "OK"
98
+ end
99
+
100
+ def body
101
+ "success"
102
+ end
103
+ end
104
+
105
+ class NoContentResponse < Response
106
+ private
107
+
108
+ def code
109
+ 204
110
+ end
111
+
112
+ def reason_phrase
113
+ "No Content"
114
+ end
115
+ end
116
+
117
+ class BadRequestResponse < Response
118
+ private
119
+
120
+ def code
121
+ 400
122
+ end
123
+
124
+ def reason_phrase
125
+ "Bad Request"
126
+ end
127
+
128
+ def body
129
+ "missing code parameter"
130
+ end
131
+ end
132
+
133
+ class NotFoundResponse < Response
134
+ private
135
+
136
+ def code
137
+ 404
138
+ end
139
+
140
+ def reason_phrase
141
+ "Not Found"
142
+ end
143
+ end
144
+
145
+ class MethodNotAllowedResponse < Response
146
+ private
147
+
148
+ def code
149
+ 405
150
+ end
151
+
152
+ def reason_phrase
153
+ "Method Not Allowed"
154
+ end
155
+
156
+ def add_access_control_headers
157
+ super
158
+ @http_response["allow"] = %w[GET OPTIONS]
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "webauthn_listener/response"
4
+
5
+ ##
6
+ # The WebauthnListener class retrieves an OTP after a user successfully WebAuthns with the Gem host.
7
+ # An instance opens a socket using the TCPServer instance given and listens for a request from the Gem host.
8
+ # The request should be a GET request to the root path and contains the OTP code in the form
9
+ # of a query parameter `code`. The listener will return the code which will be used as the OTP for
10
+ # API requests.
11
+ #
12
+ # Types of responses sent by the listener after receiving a request:
13
+ # - 200 OK: OTP code was successfully retrieved
14
+ # - 204 No Content: If the request was an OPTIONS request
15
+ # - 400 Bad Request: If the request did not contain a query parameter `code`
16
+ # - 404 Not Found: The request was not to the root path
17
+ # - 405 Method Not Allowed: OTP code was not retrieved because the request was not a GET/OPTIONS request
18
+ #
19
+ # Example usage:
20
+ #
21
+ # server = TCPServer.new(0)
22
+ # otp = Gem::WebauthnListener.wait_for_otp_code("https://rubygems.example", server)
23
+ #
24
+
25
+ class Gem::WebauthnListener
26
+ attr_reader :host
27
+
28
+ def initialize(host)
29
+ @host = host
30
+ end
31
+
32
+ def self.wait_for_otp_code(host, server)
33
+ new(host).fetch_otp_from_connection(server)
34
+ end
35
+
36
+ def fetch_otp_from_connection(server)
37
+ loop do
38
+ socket = server.accept
39
+ request_line = socket.gets
40
+
41
+ method, req_uri, _protocol = request_line.split(" ")
42
+ req_uri = URI.parse(req_uri)
43
+
44
+ responder = SocketResponder.new(socket)
45
+
46
+ unless root_path?(req_uri)
47
+ responder.send(NotFoundResponse.for(host))
48
+ raise Gem::WebauthnVerificationError, "Page at #{req_uri.path} not found."
49
+ end
50
+
51
+ case method.upcase
52
+ when "OPTIONS"
53
+ responder.send(NoContentResponse.for(host))
54
+ next # will be GET
55
+ when "GET"
56
+ if otp = parse_otp_from_uri(req_uri)
57
+ responder.send(OkResponse.for(host))
58
+ return otp
59
+ end
60
+ responder.send(BadRequestResponse.for(host))
61
+ raise Gem::WebauthnVerificationError, "Did not receive OTP from #{host}."
62
+ else
63
+ responder.send(MethodNotAllowedResponse.for(host))
64
+ raise Gem::WebauthnVerificationError, "Invalid HTTP method #{method.upcase} received."
65
+ end
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def root_path?(uri)
72
+ uri.path == "/"
73
+ end
74
+
75
+ def parse_otp_from_uri(uri)
76
+ require "cgi"
77
+
78
+ return if uri.query.nil?
79
+ CGI.parse(uri.query).dig("code", 0)
80
+ end
81
+
82
+ class SocketResponder
83
+ def initialize(socket)
84
+ @socket = socket
85
+ end
86
+
87
+ def send(response)
88
+ @socket.print response.to_s
89
+ @socket.close
90
+ end
91
+ end
92
+ end
data/lib/rubygems.rb CHANGED
@@ -8,7 +8,7 @@
8
8
  require "rbconfig"
9
9
 
10
10
  module Gem
11
- VERSION = "3.4.10"
11
+ VERSION = "3.4.14"
12
12
  end
13
13
 
14
14
  # Must be first since it unloads the prelude from 1.9.2
@@ -2,18 +2,19 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rubygems-update"
5
- s.version = "3.4.10"
5
+ s.version = "3.4.14"
6
6
  s.authors = ["Jim Weirich", "Chad Fowler", "Eric Hodel", "Luis Lavena", "Aaron Patterson", "Samuel Giddins", "André Arko", "Evan Phoenix", "Hiroshi SHIBATA"]
7
7
  s.email = ["", "", "drbrain@segment7.net", "luislavena@gmail.com", "aaron@tenderlovemaking.com", "segiddins@segiddins.me", "andre@arko.net", "evan@phx.io", "hsbt@ruby-lang.org"]
8
8
 
9
- s.summary = "RubyGems is a package management framework for Ruby."
9
+ s.summary = "RubyGems is a package management framework for Ruby. This gem is downloaded and installed by `gem update --system`, so that the `gem` CLI can update itself."
10
10
  s.description = "A package (also known as a library) contains a set of functionality
11
11
  that can be invoked by a Ruby program, such as reading and parsing an XML file. We call
12
12
  these packages 'gems' and RubyGems is a tool to install, create, manage and load these
13
13
  packages in your Ruby environment. RubyGems is also a client for RubyGems.org, a public
14
14
  repository of Gems that allows you to publish a Gem that can be shared and used by other
15
15
  developers. See our guide on publishing a Gem at guides.rubygems.org"
16
- s.homepage = "https://rubygems.org"
16
+ s.homepage = "https://guides.rubygems.org"
17
+ s.metadata = { "source_code_uri" => "https://github.com/rubygems/rubygems" }
17
18
  s.licenses = ["Ruby", "MIT"]
18
19
 
19
20
  s.files = File.read("Manifest.txt").split
@@ -1179,6 +1179,20 @@ Also, a list:
1179
1179
  RUBY_PLATFORM.match("mswin")
1180
1180
  end
1181
1181
 
1182
+ ##
1183
+ # Is this test being run on a version of Ruby built with mingw?
1184
+
1185
+ def self.mingw_windows?
1186
+ RUBY_PLATFORM.match("mingw")
1187
+ end
1188
+
1189
+ ##
1190
+ # Is this test being run on a version of Ruby built with mingw?
1191
+
1192
+ def mingw_windows?
1193
+ RUBY_PLATFORM.match("mingw")
1194
+ end
1195
+
1182
1196
  ##
1183
1197
  # Is this test being run on a ruby/ruby repository?
1184
1198
  #
@@ -14,7 +14,7 @@ require "rubygems/request"
14
14
  # The tested hosts are explained in detail here: https://github.com/rubygems/rubygems/commit/5e16a5428f973667cabfa07e94ff939e7a83ebd9
15
15
  #
16
16
 
17
- class TestBundledCA < Gem::TestCase
17
+ class TestGemBundledCA < Gem::TestCase
18
18
  def bundled_certificate_store
19
19
  store = OpenSSL::X509::Store.new
20
20
 
@@ -3,7 +3,7 @@ require_relative "helper"
3
3
  require "rubygems"
4
4
  require "shellwords"
5
5
 
6
- class TestConfig < Gem::TestCase
6
+ class TestGemConfig < Gem::TestCase
7
7
  def test_datadir
8
8
  util_make_gems
9
9
  spec = Gem::Specification.find_by_name("a")
@@ -2,7 +2,7 @@
2
2
  require_relative "helper"
3
3
  require "rubygems/deprecate"
4
4
 
5
- class TestDeprecate < Gem::TestCase
5
+ class TestGemDeprecate < Gem::TestCase
6
6
  def setup
7
7
  super
8
8
 
@@ -3,7 +3,7 @@
3
3
  require_relative "helper"
4
4
  require "rubygems"
5
5
 
6
- class TestExit < Gem::TestCase
6
+ class TestGemExit < Gem::TestCase
7
7
  def test_exit
8
8
  system(*ruby_with_rubygems_in_load_path, "-e", "raise Gem::SystemExitException.new(2)")
9
9
  assert_equal 2, $?.exitstatus
@@ -1435,6 +1435,8 @@ class TestGem < Gem::TestCase
1435
1435
  def test_load_plugins
1436
1436
  plugin_path = File.join "lib", "rubygems_plugin.rb"
1437
1437
 
1438
+ foo1_plugin_path = nil
1439
+ foo2_plugin_path = nil
1438
1440
  Dir.chdir @tempdir do
1439
1441
  FileUtils.mkdir_p "lib"
1440
1442
  File.open plugin_path, "w" do |fp|
@@ -1444,17 +1446,22 @@ class TestGem < Gem::TestCase
1444
1446
  foo1 = util_spec "foo", "1" do |s|
1445
1447
  s.files << plugin_path
1446
1448
  end
1449
+ foo1_plugin_path = File.join(foo1.gem_dir, plugin_path)
1447
1450
 
1448
1451
  install_gem foo1
1449
1452
 
1450
1453
  foo2 = util_spec "foo", "2" do |s|
1451
1454
  s.files << plugin_path
1452
1455
  end
1456
+ foo2_plugin_path = File.join(foo2.gem_dir, plugin_path)
1453
1457
 
1454
1458
  install_gem foo2
1455
1459
  end
1456
1460
 
1457
1461
  Gem::Specification.reset
1462
+ PLUGINS_LOADED.clear
1463
+ $LOADED_FEATURES.delete(foo1_plugin_path)
1464
+ $LOADED_FEATURES.delete(foo2_plugin_path)
1458
1465
 
1459
1466
  gem "foo"
1460
1467