docker_registry2 1.18.2 → 1.19.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6087558b34bf6fb8953c216c820b1823c53efab8696a9ce36e05d995089f2287
4
- data.tar.gz: 0a88cad1f6e1e47198c626bbf9ee78c5d4201ebf8d50a10dbde2b77fb46a6949
3
+ metadata.gz: c54f805742d7c7382fdd7e1575fc1a32285fef0bcb14b6455c01cb27cd96a0c0
4
+ data.tar.gz: 15c79cc613681c1a298adf5ddad7272c0753964c0571dcd083856086b63a1c84
5
5
  SHA512:
6
- metadata.gz: e80d966c2720e940312674dfd30cf24ec2be1266a3ef86141cefec1be158221ae898ac7e97839ffb6a3e218838c37b9aa95b26b42fe19a5b1d6b46643213a871
7
- data.tar.gz: 1cab4aa7740798df185769d23cd6841aa4aaadbd338e41657b6435cd84173619604883492bb5f6801bbb7651968940252f01b67486c1b9de45787b0736534d1a
6
+ metadata.gz: 87f6872852356171866a5b1a880629dc293998b21d8c238da44cba1fa70459045026a78497200f88e20dc718b0868bbfdb5de48c58c6b38a3e57d6370c96183f
7
+ data.tar.gz: 3b7c8b3cee45d83f0718a83b52959bc99b6bd01675fb17a5f078b3960e591bd4287e7a43b65768f1d3171664eb7af492b9514bf97d8e565e524c2643940330f1
data/README.md CHANGED
@@ -55,7 +55,7 @@ opts = { open_timeout: 2, read_timeout: 5 }
55
55
  reg = DockerRegistry2.connect("https://my.registy.corp.com", opts)
56
56
  ```
57
57
 
58
- Your may pass extra options for RestClient::Request.execute through `http_options` :
58
+ You may pass extra Faraday connection options through `http_options`:
59
59
 
60
60
  ```ruby
61
61
  opts = { http_options: { proxy: 'http://proxy.example.com:8080/' } }
@@ -24,13 +24,17 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ['lib']
26
26
 
27
+ spec.add_development_dependency 'base64'
28
+ spec.add_development_dependency 'benchmark'
27
29
  spec.add_development_dependency 'bundler'
28
- spec.add_development_dependency 'rake', '~> 10.0'
30
+ spec.add_development_dependency 'rake', '~> 13.0'
29
31
  spec.add_development_dependency 'rspec', '~> 3'
30
32
  spec.add_development_dependency 'rubocop', '>= 1.63.0'
31
33
  spec.add_development_dependency 'vcr', '~> 6'
32
34
  spec.add_development_dependency 'webmock'
33
35
 
34
- spec.add_dependency 'rest-client', '>= 1.8.0'
36
+ spec.add_dependency 'faraday', '>= 2.0'
37
+ spec.add_dependency 'faraday-follow_redirects'
38
+ spec.add_dependency 'faraday-net_http'
35
39
  spec.metadata['rubygems_mfa_required'] = 'true'
36
40
  end
@@ -30,4 +30,7 @@ module DockerRegistry2
30
30
 
31
31
  class InvalidMethod < DockerRegistry2::Exception
32
32
  end
33
+
34
+ class RegistryHTTPException < DockerRegistry2::Exception
35
+ end
33
36
  end
@@ -1,10 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fileutils'
4
- require 'rest-client'
4
+ require 'base64'
5
+ require 'faraday'
6
+ require 'faraday/follow_redirects'
7
+ require 'faraday/net_http'
5
8
  require 'json'
9
+ require 'openssl'
6
10
 
7
11
  module DockerRegistry2
12
+ Response = Struct.new(:body, :headers, :code, :request_url, keyword_init: true)
13
+
8
14
  class Registry # rubocop:disable Metrics/ClassLength
9
15
  # @param [#to_s] base_uri Docker registry base URI
10
16
  # @param [Hash] options Client options
@@ -14,21 +20,21 @@ module DockerRegistry2
14
20
  # It is ignored if http_options[:open_timeout] is also specified.
15
21
  # @option options [#to_s] :read_timeout Time to wait for data from a registry.
16
22
  # It is ignored if http_options[:read_timeout] is also specified.
17
- # @option options [Hash] :http_options Extra options for RestClient::Request.execute.
23
+ # @option options [Hash] :http_options Extra options for Faraday connection/request setup.
18
24
  def initialize(uri, options = {})
19
25
  @uri = URI.parse(uri)
20
- @base_uri = +"#{@uri.scheme}://#{@uri.host}:#{@uri.port}#{@uri.path}"
26
+ @base_uri = "#{@uri.scheme}://#{@uri.host}:#{@uri.port}#{@uri.path}"
21
27
  # `URI.join("https://example.com/foo/bar", "v2")` drops `bar` in the base URL. A trailing slash prevents that.
22
28
  @base_uri << '/' unless @base_uri.end_with? '/'
23
29
  @user = options[:user]
24
30
  @password = options[:password]
25
31
  @http_options = options[:http_options] || {}
26
- @http_options[:open_timeout] ||= options[:open_timeout] || 2
27
- @http_options[:read_timeout] ||= options[:read_timeout] || 5
32
+ apply_timeout_defaults(options)
33
+ @connection = nil
28
34
  end
29
35
 
30
- def doget(url)
31
- doreq 'get', url
36
+ def doget(url, accept: nil)
37
+ doreq 'get', url, nil, nil, accept: accept
32
38
  end
33
39
 
34
40
  def doput(url, payload = nil)
@@ -56,14 +62,14 @@ module DockerRegistry2
56
62
 
57
63
  # The next URL in the Link header may be relative to the request URL, or absolute.
58
64
  # URI.join handles both cases nicely.
59
- url = URI.join(response.request.url, next_url)
65
+ url = URI.join(response.request_url, next_url)
60
66
  end
61
67
  end
62
68
 
63
69
  def search(query = '')
64
70
  all_repos = []
65
71
  paginate_doget('v2/_catalog') do |response|
66
- repos = JSON.parse(response)['repositories']
72
+ repos = JSON.parse(response.body)['repositories']
67
73
  repos.select! { |repo| repo.match?(/#{query}/) } unless query.empty?
68
74
  all_repos += repos
69
75
  end
@@ -81,7 +87,7 @@ module DockerRegistry2
81
87
 
82
88
  response = doget "v2/#{repo}/tags/list#{query_vars}"
83
89
  # parse the response
84
- resp = JSON.parse response
90
+ resp = JSON.parse response.body
85
91
  # parse out next page link if necessary
86
92
  resp['last'] = last(response.headers[:link]) if response.headers[:link]
87
93
 
@@ -108,7 +114,7 @@ module DockerRegistry2
108
114
 
109
115
  def manifest(repo, tag)
110
116
  # first get the manifest
111
- response = doget "v2/#{repo}/manifests/#{tag}"
117
+ response = doget_with_legacy_fallback("v2/#{repo}/manifests/#{tag}")
112
118
  parsed = JSON.parse response.body
113
119
  manifest = DockerRegistry2::Manifest[parsed]
114
120
  manifest.body = response.body
@@ -276,105 +282,36 @@ module DockerRegistry2
276
282
 
277
283
  private
278
284
 
279
- def doreq(type, url, stream = nil, payload = nil)
280
- begin
281
- block = if stream.nil?
282
- nil
283
- else
284
- proc { |response|
285
- response.read_body do |chunk|
286
- stream.write chunk
287
- end
288
- }
289
- end
290
- response = RestClient::Request.execute(@http_options.merge(
291
- method: type,
292
- url: URI.join(@base_uri, url).to_s,
293
- headers: headers(payload: payload),
294
- block_response: block,
295
- payload: payload
296
- ))
297
- rescue SocketError
298
- raise DockerRegistry2::RegistryUnknownException
299
- rescue RestClient::NotFound
300
- raise DockerRegistry2::NotFound, "Image not found at #{@uri.host}"
301
- rescue RestClient::Unauthorized => e
302
- header = e.response.headers[:www_authenticate]
303
- method = header.to_s.downcase.split[0]
304
- case method
305
- when 'basic'
306
- response = do_basic_req(type, url, stream, payload)
307
- when 'bearer'
308
- response = do_bearer_req(type, url, header, stream, payload)
309
- else
310
- raise DockerRegistry2::RegistryUnknownException
311
- end
312
- end
313
- response
314
- end
315
-
316
- def do_basic_req(type, url, stream = nil, payload = nil)
317
- begin
318
- block = if stream.nil?
319
- nil
320
- else
321
- proc { |response|
322
- response.read_body do |chunk|
323
- stream.write chunk
324
- end
325
- }
326
- end
327
- response = RestClient::Request.execute(@http_options.merge(
328
- method: type,
329
- url: URI.join(@base_uri, url).to_s,
330
- user: @user,
331
- password: @password,
332
- headers: headers(payload: payload),
333
- block_response: block,
334
- payload: payload
335
- ))
336
- rescue SocketError
285
+ def doreq(type, url, stream = nil, payload = nil, **request_options)
286
+ response = perform_request(type, url, payload: payload, stream: stream, **request_options)
287
+ return handle_error_response(response, unauthorized_exception: DockerRegistry2::RegistryAuthenticationException) unless response.code == 401
288
+
289
+ header = response.headers[:www_authenticate]
290
+ method = header.to_s.downcase.split[0]
291
+ case method
292
+ when 'basic'
293
+ do_basic_req(type, url, stream, payload, **request_options)
294
+ when 'bearer'
295
+ do_bearer_req(type, url, header, stream: stream, payload: payload, **request_options)
296
+ else
337
297
  raise DockerRegistry2::RegistryUnknownException
338
- rescue RestClient::Unauthorized
339
- raise DockerRegistry2::RegistryAuthenticationException
340
- rescue RestClient::MethodNotAllowed
341
- raise DockerRegistry2::InvalidMethod
342
- rescue RestClient::NotFound => e
343
- raise DockerRegistry2::NotFound, e
344
298
  end
345
- response
346
299
  end
347
300
 
348
- def do_bearer_req(type, url, header, stream = false, payload = nil)
349
- token = authenticate_bearer(header)
350
- begin
351
- block = if stream.nil?
352
- nil
353
- else
354
- proc { |response|
355
- response.read_body do |chunk|
356
- stream.write chunk
357
- end
358
- }
359
- end
360
- response = RestClient::Request.execute(@http_options.merge(
361
- method: type,
362
- url: URI.join(@base_uri, url).to_s,
363
- headers: headers(payload: payload, bearer_token: token),
364
- block_response: block,
365
- payload: payload
366
- ))
367
- rescue SocketError
368
- raise DockerRegistry2::RegistryUnknownException
369
- rescue RestClient::Unauthorized
370
- raise DockerRegistry2::RegistryAuthenticationException
371
- rescue RestClient::MethodNotAllowed
372
- raise DockerRegistry2::InvalidMethod
373
- rescue RestClient::NotFound => e
374
- raise DockerRegistry2::NotFound, e
375
- end
301
+ def do_basic_req(type, url, stream = nil, payload = nil, **request_options)
302
+ response = perform_request(type, url, payload: payload, stream: stream, auth: :basic, **request_options)
303
+ handle_error_response(response, unauthorized_exception: DockerRegistry2::RegistryAuthenticationException)
304
+ end
376
305
 
377
- response
306
+ def do_bearer_req(type, url, header, request_options = {})
307
+ token = authenticate_bearer(header)
308
+ response = perform_request(type, url,
309
+ payload: request_options[:payload],
310
+ stream: request_options[:stream],
311
+ auth: :bearer,
312
+ bearer_token: token,
313
+ **request_options.except(:payload, :stream))
314
+ handle_error_response(response, unauthorized_exception: DockerRegistry2::RegistryAuthenticationException)
378
315
  end
379
316
 
380
317
  def authenticate_bearer(header)
@@ -384,26 +321,16 @@ module DockerRegistry2
384
321
  target[:params][:account] = @user if defined? @user && !@user.to_s.strip.empty?
385
322
  # authenticate against the realm
386
323
  uri = URI.parse(target[:realm])
387
- begin
388
- response = RestClient::Request.execute(@http_options.merge(
389
- method: :get,
390
- url: uri.to_s, headers: { params: target[:params] },
391
- user: @user,
392
- password: @password
393
- ))
394
- rescue RestClient::Unauthorized, RestClient::Forbidden
395
- # bad authentication
396
- raise DockerRegistry2::RegistryAuthenticationException
397
- rescue RestClient::NotFound => e
398
- raise DockerRegistry2::NotFound, e
399
- end
324
+ response = perform_absolute_request(:get, uri.to_s, params: target[:params], auth: :basic)
325
+ handle_error_response(response,
326
+ unauthorized_exception: DockerRegistry2::RegistryAuthenticationException,
327
+ forbidden_exception: DockerRegistry2::RegistryAuthenticationException)
400
328
  # now save the web token
401
- result = JSON.parse(response)
329
+ result = JSON.parse(response.body)
402
330
  result['token'] || result['access_token']
403
331
  end
404
332
 
405
333
  def split_auth_header(header = '')
406
- h = {}
407
334
  h = { params: {} }
408
335
  header.scan(/(\w+)="([^"]+)"/) do |entry|
409
336
  case entry[0]
@@ -416,20 +343,213 @@ module DockerRegistry2
416
343
  h
417
344
  end
418
345
 
419
- def headers(payload: nil, bearer_token: nil)
346
+ def headers(payload: nil, bearer_token: nil, accept: nil)
420
347
  headers = {}
421
348
  headers['Authorization'] = "Bearer #{bearer_token}" unless bearer_token.nil?
422
- if payload.nil?
423
- headers['Accept'] =
424
- %w[application/vnd.docker.distribution.manifest.v2+json
425
- application/vnd.docker.distribution.manifest.list.v2+json
426
- application/vnd.oci.image.manifest.v1+json
427
- application/vnd.oci.image.index.v1+json
428
- application/json].join(',')
429
- end
349
+ headers['Accept'] = accept || default_accept_header if payload.nil?
430
350
  headers['Content-Type'] = 'application/vnd.docker.distribution.manifest.v2+json' unless payload.nil?
431
351
 
432
352
  headers
433
353
  end
354
+
355
+ def default_accept_header
356
+ %w[application/vnd.docker.distribution.manifest.v2+json
357
+ application/vnd.docker.distribution.manifest.list.v2+json
358
+ application/vnd.oci.image.manifest.v1+json
359
+ application/vnd.oci.image.index.v1+json
360
+ application/json].join(',')
361
+ end
362
+
363
+ def legacy_manifest_accept_header
364
+ %w[application/vnd.docker.distribution.manifest.v2+json
365
+ application/vnd.docker.distribution.manifest.list.v2+json
366
+ application/vnd.docker.distribution.manifest.v1+prettyjws
367
+ application/json].join(',')
368
+ end
369
+
370
+ def connection
371
+ @connection ||= build_connection(@base_uri)
372
+ end
373
+
374
+ def build_connection(base_url)
375
+ Faraday.new(base_url, **connection_options) do |faraday|
376
+ faraday.response :follow_redirects,
377
+ limit: 5,
378
+ standards_compliant: true
379
+ faraday.adapter :net_http
380
+ end
381
+ end
382
+
383
+ def connection_options
384
+ options = symbolize_keys(@http_options).dup
385
+ options.delete(:open_timeout)
386
+ options.delete(:read_timeout)
387
+
388
+ ssl = normalize_ssl_options(options)
389
+ request = request_options(options.delete(:request))
390
+
391
+ options[:ssl] = ssl unless ssl.empty?
392
+ options[:request] = request unless request.empty?
393
+ options
394
+ end
395
+
396
+ def request_options(request = nil)
397
+ options = symbolize_keys(request || {})
398
+ options[:open_timeout] ||= @http_options[:open_timeout] || @http_options['open_timeout']
399
+ options[:timeout] ||= @http_options[:read_timeout] || @http_options['read_timeout']
400
+ options
401
+ end
402
+
403
+ def normalize_ssl_options(options)
404
+ ssl = symbolize_keys(options.delete(:ssl) || {})
405
+ normalize_legacy_verify_ssl!(ssl, options)
406
+ ssl_aliases.each do |target_key, source_keys|
407
+ source_keys.each do |source_key|
408
+ next if source_key == :verify_ssl
409
+ next unless options.key?(source_key)
410
+
411
+ ssl[target_key] = options.delete(source_key)
412
+ end
413
+ end
414
+ normalize_legacy_client_cert_paths!(ssl)
415
+ ssl
416
+ end
417
+
418
+ def ssl_aliases
419
+ {
420
+ version: %i[ssl_version],
421
+ ca_file: %i[ca_file ssl_ca_file],
422
+ ca_path: %i[ca_path ssl_ca_path],
423
+ cert_store: %i[cert_store ssl_cert_store],
424
+ client_cert: %i[client_cert ssl_client_cert],
425
+ client_key: %i[client_key ssl_client_key],
426
+ verify_mode: %i[verify_mode]
427
+ }
428
+ end
429
+
430
+ def apply_timeout_defaults(options)
431
+ @http_options[:open_timeout] = options[:open_timeout] || 2 unless @http_options.key?(:open_timeout) || @http_options.key?('open_timeout')
432
+ @http_options[:read_timeout] = options[:read_timeout] || 5 unless @http_options.key?(:read_timeout) || @http_options.key?('read_timeout')
433
+ end
434
+
435
+ def normalize_legacy_verify_ssl!(ssl, options)
436
+ return unless options.key?(:verify_ssl)
437
+
438
+ verify_ssl = options.delete(:verify_ssl)
439
+ if verify_ssl.is_a?(Numeric)
440
+ ssl[:verify_mode] = verify_ssl
441
+ else
442
+ ssl[:verify] = verify_ssl
443
+ end
444
+ end
445
+
446
+ def normalize_legacy_client_cert_paths!(ssl)
447
+ ssl[:client_cert] = load_client_certificate(ssl[:client_cert]) if ssl[:client_cert].is_a?(String)
448
+ ssl[:client_key] = load_client_key(ssl[:client_key]) if ssl[:client_key].is_a?(String)
449
+ end
450
+
451
+ def load_client_certificate(path)
452
+ OpenSSL::X509::Certificate.new(File.read(path))
453
+ end
454
+
455
+ def load_client_key(path)
456
+ OpenSSL::PKey.read(File.read(path))
457
+ end
458
+
459
+ def symbolize_keys(hash)
460
+ hash.transform_keys { |key| key.respond_to?(:to_sym) ? key.to_sym : key }
461
+ end
462
+
463
+ def perform_request(type, url, request_options = {})
464
+ perform(connection, type, url, request_options)
465
+ end
466
+
467
+ def perform_absolute_request(type, url, request_options = {})
468
+ uri = URI.parse(url)
469
+ absolute_connection = build_connection("#{uri.scheme}://#{uri.host}:#{uri.port}")
470
+ request_url = uri.request_uri
471
+ perform(absolute_connection, type, request_url, request_options)
472
+ end
473
+
474
+ def perform(conn, type, url, request_options = {})
475
+ request_headers = headers(payload: request_options[:payload],
476
+ bearer_token: request_options[:bearer_token],
477
+ accept: request_options[:accept])
478
+ response = conn.run_request(type.to_sym, url, request_options[:payload], request_headers) do |request|
479
+ request.params.update(request_options[:params]) if request_options[:params]
480
+ request.options.on_data = stream_handler(request_options[:stream]) if request_options[:stream]
481
+ apply_auth!(request, request_options[:auth])
482
+ end
483
+
484
+ normalize_response(response, stream: request_options[:stream])
485
+ rescue Faraday::SSLError
486
+ raise DockerRegistry2::RegistrySSLException
487
+ rescue Faraday::TimeoutError, Faraday::ConnectionFailed, SocketError
488
+ raise DockerRegistry2::RegistryUnknownException
489
+ end
490
+
491
+ def apply_auth!(request, auth)
492
+ case auth
493
+ when :basic
494
+ return if @user.to_s.empty? && @password.to_s.empty?
495
+
496
+ token = Base64.strict_encode64([@user, @password].join(':'))
497
+ request.headers['Authorization'] = "Basic #{token}"
498
+ when nil, :bearer
499
+ nil
500
+ else
501
+ raise ArgumentError, "Unsupported auth strategy: #{auth}"
502
+ end
503
+ end
504
+
505
+ def stream_handler(stream)
506
+ proc do |chunk, _overall_received_bytes, env|
507
+ status = env.status.to_i
508
+ stream.write(chunk) if status >= 200 && status < 300
509
+ end
510
+ end
511
+
512
+ def normalize_response(response, stream: nil)
513
+ DockerRegistry2::Response.new(
514
+ body: stream.nil? ? response.body : nil,
515
+ headers: normalize_headers(response.headers),
516
+ code: response.status,
517
+ request_url: response.env.url.to_s
518
+ )
519
+ end
520
+
521
+ def normalize_headers(raw_headers)
522
+ headers = {}
523
+ raw_headers.each do |key, value|
524
+ normalized_key = key.to_s.tr('-', '_').downcase.to_sym
525
+ headers[normalized_key] = value
526
+ end
527
+ headers
528
+ end
529
+
530
+ def handle_error_response(response, unauthorized_exception:, forbidden_exception: nil)
531
+ case response.code
532
+ when 200..299
533
+ response
534
+ when 401
535
+ raise unauthorized_exception
536
+ when 403
537
+ raise(forbidden_exception || DockerRegistry2::RegistryAuthorizationException)
538
+ when 404
539
+ raise DockerRegistry2::NotFound, "Image not found at #{@uri.host}"
540
+ when 405
541
+ raise DockerRegistry2::InvalidMethod
542
+ else
543
+ raise DockerRegistry2::RegistryHTTPException, "Registry request failed with status #{response.code}"
544
+ end
545
+ end
546
+
547
+ def doget_with_legacy_fallback(url)
548
+ doget(url)
549
+ rescue DockerRegistry2::RegistryHTTPException => e
550
+ raise e unless e.message.include?('status 500')
551
+
552
+ doget(url, accept: legacy_manifest_accept_header)
553
+ end
434
554
  end
435
555
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DockerRegistry2
4
- VERSION = '1.18.2'
4
+ VERSION = '1.19.0'
5
5
  end
metadata CHANGED
@@ -1,18 +1,46 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker_registry2
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.18.2
4
+ version: 1.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Avi Deitcher https://github.com/deitch
8
8
  - Jonathan Hurter https://github.com/johnsudaar
9
9
  - Dmitry Fleytman https://github.com/dmitryfleytman
10
10
  - Grey Baker https://github.com/greysteil
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2024-08-01 00:00:00.000000000 Z
14
+ date: 2026-03-19 00:00:00.000000000 Z
15
15
  dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: base64
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: benchmark
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
16
44
  - !ruby/object:Gem::Dependency
17
45
  name: bundler
18
46
  requirement: !ruby/object:Gem::Requirement
@@ -33,14 +61,14 @@ dependencies:
33
61
  requirements:
34
62
  - - "~>"
35
63
  - !ruby/object:Gem::Version
36
- version: '10.0'
64
+ version: '13.0'
37
65
  type: :development
38
66
  prerelease: false
39
67
  version_requirements: !ruby/object:Gem::Requirement
40
68
  requirements:
41
69
  - - "~>"
42
70
  - !ruby/object:Gem::Version
43
- version: '10.0'
71
+ version: '13.0'
44
72
  - !ruby/object:Gem::Dependency
45
73
  name: rspec
46
74
  requirement: !ruby/object:Gem::Requirement
@@ -98,21 +126,49 @@ dependencies:
98
126
  - !ruby/object:Gem::Version
99
127
  version: '0'
100
128
  - !ruby/object:Gem::Dependency
101
- name: rest-client
129
+ name: faraday
102
130
  requirement: !ruby/object:Gem::Requirement
103
131
  requirements:
104
132
  - - ">="
105
133
  - !ruby/object:Gem::Version
106
- version: 1.8.0
134
+ version: '2.0'
107
135
  type: :runtime
108
136
  prerelease: false
109
137
  version_requirements: !ruby/object:Gem::Requirement
110
138
  requirements:
111
139
  - - ">="
112
140
  - !ruby/object:Gem::Version
113
- version: 1.8.0
141
+ version: '2.0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: faraday-follow_redirects
144
+ requirement: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ type: :runtime
150
+ prerelease: false
151
+ version_requirements: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ - !ruby/object:Gem::Dependency
157
+ name: faraday-net_http
158
+ requirement: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ type: :runtime
164
+ prerelease: false
165
+ version_requirements: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
114
170
  description: Docker v2 registry HTTP API client with support for token authentication
115
- email:
171
+ email:
116
172
  executables: []
117
173
  extensions: []
118
174
  extra_rdoc_files: []
@@ -130,7 +186,7 @@ licenses:
130
186
  - MIT
131
187
  metadata:
132
188
  rubygems_mfa_required: 'true'
133
- post_install_message:
189
+ post_install_message:
134
190
  rdoc_options: []
135
191
  require_paths:
136
192
  - lib
@@ -145,8 +201,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
201
  - !ruby/object:Gem::Version
146
202
  version: '0'
147
203
  requirements: []
148
- rubygems_version: 3.5.11
149
- signing_key:
204
+ rubygems_version: 3.2.3
205
+ signing_key:
150
206
  specification_version: 4
151
207
  summary: Docker v2 registry HTTP API client
152
208
  test_files: []