dependabot-docker 0.213.0 → 0.214.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: ebc54cfc835861f5ff7c37dabe72928e92786cda8925b7744029121b17fdc097
4
- data.tar.gz: 4e99d4753649e65f7d34295f596c9de8e1060487e066c8c3cc6a2054e9e6c30a
3
+ metadata.gz: b7aabb905dbb5a64638f936079c477b091dd8b2a05aad7cc070c10e11977cc97
4
+ data.tar.gz: 4cc6bbe0291ded5c2e975f2256561044700a6a5903f1d110815de0ff5a0da281
5
5
  SHA512:
6
- metadata.gz: 2312611afec9a4b58b82b0327a95f9257ae1cfacabc7f294c9eba48e52cf5d268dcf9004260a8fcb5aa9b6d9f647c2df5199b8bc9ad6e4131a4ad7ec85fa693e
7
- data.tar.gz: 74760bd8b337feb6a2b7ca3a083079c2f6c187bdd2495c9467bc7a5b5f96bb825ac8cfda8defce871295d6e10ec4e8dbed01a6776816f83cc87eabc75517537d
6
+ metadata.gz: d2a1629644bf4dcc1a523aaef694b2601f0008361468dbde35008396bb9dfe6c225857946bdad4f6dad384f11b7c763357a50a8f27ab02fb8cde23f9ce6f7271
7
+ data.tar.gz: b5a6df5e91b49e9faa2d972ee74b4aba244f83051e076cf33dda73dc9f55deee7895f8ffc4e5e13ef4d309ae33e1d9a9ef0e710bf6b12dd35545d524ec7dca7b
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dependabot/docker/utils/helpers"
3
4
  require "dependabot/experiments"
4
5
  require "dependabot/file_fetchers"
5
6
  require "dependabot/file_fetchers/base"
@@ -9,7 +10,6 @@ module Dependabot
9
10
  class FileFetcher < Dependabot::FileFetchers::Base
10
11
  YAML_REGEXP = /^[^\.]+\.ya?ml$/i
11
12
  DOCKER_REGEXP = /dockerfile/i
12
- HELM_REGEXP = /values[\-a-zA-Z_0-9]*\.yaml/i
13
13
 
14
14
  def self.required_files_in?(filenames)
15
15
  filenames.any? { |f| f.match?(DOCKER_REGEXP) } or
@@ -22,26 +22,18 @@ module Dependabot
22
22
 
23
23
  private
24
24
 
25
- def kubernetes_enabled?
26
- Experiments.enabled?(:kubernetes_updates)
27
- end
28
-
29
25
  def fetch_files
30
26
  fetched_files = []
31
27
  fetched_files += correctly_encoded_dockerfiles
32
- fetched_files += correctly_encoded_yamlfiles if kubernetes_enabled?
28
+ fetched_files += correctly_encoded_yamlfiles
33
29
 
34
30
  return fetched_files if fetched_files.any?
35
31
 
36
- if !kubernetes_enabled? && incorrectly_encoded_dockerfiles.none?
32
+ if incorrectly_encoded_dockerfiles.none? && incorrectly_encoded_yamlfiles.none?
37
33
  raise(
38
34
  Dependabot::DependencyFileNotFound,
39
- File.join(directory, "Dockerfile")
40
- )
41
- elsif incorrectly_encoded_dockerfiles.none? && incorrectly_encoded_yamlfiles.none?
42
- raise(
43
- Dependabot::DependabotError,
44
- "Found neither Kubernetes YAML nor Dockerfiles in #{directory}"
35
+ File.join(directory, "Dockerfile"),
36
+ "No Dockerfiles nor Kubernetes YAML found in #{directory}"
45
37
  )
46
38
  elsif incorrectly_encoded_dockerfiles.none?
47
39
  raise(
@@ -86,7 +78,7 @@ module Dependabot
86
78
  def correctly_encoded_yamlfiles
87
79
  candidate_files = yamlfiles.select { |f| f.content.valid_encoding? }
88
80
  candidate_files.select do |f|
89
- if f.type == "file" && f.name.match?(HELM_REGEXP)
81
+ if f.type == "file" && Utils.likely_helm_chart?(f)
90
82
  true
91
83
  else
92
84
  # This doesn't handle multi-resource files, but it shouldn't matter, since the first resource
@@ -101,8 +101,9 @@ module Dependabot
101
101
  def version_from_digest(registry:, image:, digest:)
102
102
  return unless digest
103
103
 
104
- repo = docker_repo_name(image, registry)
105
- client = docker_registry_client(registry)
104
+ registry_details = fetch_registry_details(registry)
105
+ repo = docker_repo_name(image, registry_details["registry"])
106
+ client = docker_registry_client(registry_details["registry"], registry_details["credentials"])
106
107
  client.tags(repo, auto_paginate: true).fetch("tags").find do |tag|
107
108
  digest == client.digest(repo, tag)
108
109
  rescue DockerRegistry2::NotFound
@@ -112,46 +113,44 @@ module Dependabot
112
113
  end
113
114
  rescue DockerRegistry2::RegistryAuthenticationException,
114
115
  RestClient::Forbidden
115
- raise if standard_registry?(registry)
116
+ raise PrivateSourceAuthenticationFailure, registry_details["registry"]
117
+ rescue RestClient::Exceptions::OpenTimeout,
118
+ RestClient::Exceptions::ReadTimeout
119
+ raise if credentials_finder.using_dockerhub?(registry_details["registry"])
116
120
 
117
- raise PrivateSourceAuthenticationFailure, registry
121
+ raise PrivateSourceTimedOut, registry_details["registry"]
118
122
  end
119
123
 
120
124
  def docker_repo_name(image, registry)
121
- return image unless standard_registry?(registry)
122
- return image unless image.split("/").count < 2
125
+ return image if image.include? "/"
126
+ return "library/#{image}" if credentials_finder.using_dockerhub?(registry)
123
127
 
124
- "library/#{image}"
128
+ image
125
129
  end
126
130
 
127
- def docker_registry_client(registry)
128
- if registry
129
- credentials = registry_credentials(registry)
130
-
131
- DockerRegistry2::Registry.new(
132
- "https://#{registry}",
133
- user: credentials&.fetch("username", nil),
134
- password: credentials&.fetch("password", nil)
135
- )
136
- else
137
- DockerRegistry2::Registry.new("https://registry.hub.docker.com")
131
+ def docker_registry_client(registry_hostname, registry_credentials)
132
+ unless credentials_finder.using_dockerhub?(registry_hostname)
133
+ return DockerRegistry2::Registry.new("https://#{registry_hostname}")
138
134
  end
135
+
136
+ DockerRegistry2::Registry.new(
137
+ "https://#{registry_hostname}",
138
+ user: registry_credentials&.fetch("username", nil),
139
+ password: registry_credentials&.fetch("password", nil),
140
+ read_timeout: 10
141
+ )
139
142
  end
140
143
 
141
- def registry_credentials(registry_url)
142
- credentials_finder.credentials_for_registry(registry_url)
144
+ def fetch_registry_details(registry)
145
+ registry ||= credentials_finder.base_registry
146
+ credentials = credentials_finder.credentials_for_registry(registry)
147
+ { "registry" => registry, "credentials" => credentials }
143
148
  end
144
149
 
145
150
  def credentials_finder
146
151
  @credentials_finder ||= Utils::CredentialsFinder.new(credentials)
147
152
  end
148
153
 
149
- def standard_registry?(registry)
150
- return true if registry.nil?
151
-
152
- registry == "registry.hub.docker.com"
153
- end
154
-
155
154
  def check_required_files
156
155
  # Just check if there are any files at all.
157
156
  return if dependency_files.any?
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dependabot/docker/utils/helpers"
3
4
  require "dependabot/file_updaters"
4
5
  require "dependabot/file_updaters/base"
5
6
  require "dependabot/errors"
@@ -152,7 +153,7 @@ module Dependabot
152
153
  end
153
154
 
154
155
  def updated_yaml_content(file)
155
- updated_content = file.name == "values.yaml" ? update_helm(file) : update_image(file)
156
+ updated_content = Utils.likely_helm_chart?(file) ? update_helm(file) : update_image(file)
156
157
 
157
158
  raise "Expected content to change!" if updated_content == file.content
158
159
 
@@ -42,10 +42,9 @@ end
42
42
  module Dependabot
43
43
  module Docker
44
44
  class UpdateChecker < Dependabot::UpdateCheckers::Base
45
- VERSION_REGEX =
46
- /v?(?<version>[0-9]+(?:(?:\.[_a-z0-9]+)|(?:-(?:kb)?[0-9]+))*)/i
47
- VERSION_WITH_SFX = /^#{VERSION_REGEX}(?<suffix>-[a-z0-9.\-]+)?$/i
48
- VERSION_WITH_PFX = /^(?<prefix>[a-z0-9.\-]+-)?#{VERSION_REGEX}$/i
45
+ VERSION_REGEX = /v?(?<version>[0-9]+(?:\.[0-9]+)*(?:_[0-9]+|\.[a-z0-9]+|-(?:kb)?[0-9]+)*)/i
46
+ VERSION_WITH_SFX = /^#{VERSION_REGEX}(?<suffix>-[a-z][a-z0-9.\-]*)?$/i
47
+ VERSION_WITH_PFX = /^(?<prefix>[a-z][a-z0-9.\-]*-)?#{VERSION_REGEX}$/i
49
48
  VERSION_WITH_PFX_AND_SFX = /^(?<prefix>[a-z\-]+-)?#{VERSION_REGEX}(?<suffix>-[a-z\-]+)?$/i
50
49
  NAME_WITH_VERSION =
51
50
  /
@@ -55,7 +54,7 @@ module Dependabot
55
54
  /x
56
55
 
57
56
  def latest_version
58
- fetch_latest_version(dependency.version)
57
+ latest_version_from(dependency.version)
59
58
  end
60
59
 
61
60
  def latest_resolvable_version
@@ -72,7 +71,7 @@ module Dependabot
72
71
  dependency.requirements.map do |req|
73
72
  updated_source = req.fetch(:source).dup
74
73
  updated_source[:digest] = updated_digest if req[:source][:digest]
75
- updated_source[:tag] = fetch_latest_version(req[:source][:tag]) if req[:source][:tag]
74
+ updated_source[:tag] = latest_version_from(req[:source][:tag]) if req[:source][:tag]
76
75
 
77
76
  req.merge(source: updated_source)
78
77
  end
@@ -118,7 +117,7 @@ module Dependabot
118
117
  # Check the precision of the potentially higher tag is the same as the
119
118
  # one it would replace. In the event that it's not the same, check the
120
119
  # digests are also unequal. Avoids 'updating' ruby-2 -> ruby-2.5.1
121
- return false if old_v.split(".").count == latest_v.split(".").count
120
+ return false if precision_of(old_v) == precision_of(latest_v)
122
121
 
123
122
  digest_of(version) == digest_of(latest_version)
124
123
  end
@@ -132,33 +131,38 @@ module Dependabot
132
131
  end
133
132
  end
134
133
 
135
- # NOTE: It's important that this *always* returns a version (even if
136
- # it's the existing one) as it is what we later check the digest of.
137
- def fetch_latest_version(version)
134
+ def latest_version_from(version)
138
135
  @versions ||= {}
139
136
  return @versions[version] if @versions.key?(version)
140
137
 
141
- @versions[version] = begin
142
- return version unless version.match?(NAME_WITH_VERSION)
143
-
144
- # Prune out any downgrade tags before checking for pre-releases
145
- # (which requires a call to the registry for each tag, so can be slow)
146
- candidate_tags = comparable_tags_from_registry(version)
147
- candidate_tags = remove_version_downgrades(candidate_tags, version)
138
+ @versions[version] = fetch_latest_version(version)
139
+ end
148
140
 
149
- unless prerelease?(version)
150
- candidate_tags =
151
- candidate_tags.
152
- reject { |tag| prerelease?(tag) }
141
+ # NOTE: It's important that this *always* returns a version (even if
142
+ # it's the existing one) as it is what we later check the digest of.
143
+ def fetch_latest_version(version)
144
+ return version unless version.match?(NAME_WITH_VERSION)
145
+
146
+ # Prune out any downgrade tags before checking for pre-releases
147
+ # (which requires a call to the registry for each tag, so can be slow)
148
+ candidate_tags = comparable_tags_from_registry(version)
149
+ candidate_tags = remove_version_downgrades(candidate_tags, version)
150
+ candidate_tags = remove_prereleases(candidate_tags, version)
151
+ candidate_tags = filter_ignored(candidate_tags)
152
+ candidate_tags = sort_tags(candidate_tags, version)
153
+
154
+ latest_tag = candidate_tags.last
155
+
156
+ if latest_tag && same_precision?(latest_tag, version)
157
+ latest_tag
158
+ else
159
+ latest_same_precision_tag = remove_precision_changes(candidate_tags, version).last
160
+
161
+ if latest_same_precision_tag && digest_of(latest_same_precision_tag) == digest_of(latest_tag)
162
+ latest_same_precision_tag
163
+ else
164
+ latest_tag || version
153
165
  end
154
-
155
- latest_tag =
156
- filter_ignored(candidate_tags).
157
- max_by do |tag|
158
- [version_class.new(numeric_version_from(tag)), tag.length]
159
- end
160
-
161
- latest_tag || version
162
166
  end
163
167
  end
164
168
 
@@ -167,28 +171,37 @@ module Dependabot
167
171
  original_suffix = suffix_of(version)
168
172
  original_format = format_of(version)
169
173
 
170
- tags_from_registry.
174
+ candidate_tags =
175
+ tags_from_registry.
171
176
  select { |tag| tag.match?(NAME_WITH_VERSION) }.
172
177
  select { |tag| prefix_of(tag) == original_prefix }.
173
- select { |tag| suffix_of(tag) == original_suffix || commit_sha_suffix?(tag) }.
174
178
  select { |tag| format_of(tag) == original_format }
179
+ return candidate_tags if original_format == :sha_suffixed
180
+
181
+ candidate_tags.select { |tag| suffix_of(tag) == original_suffix }
175
182
  end
176
183
 
177
184
  def remove_version_downgrades(candidate_tags, version)
178
185
  candidate_tags.select do |tag|
179
- version_class.new(numeric_version_from(tag)) >=
180
- version_class.new(numeric_version_from(version))
186
+ comparable_version_from(tag) >=
187
+ comparable_version_from(version)
181
188
  end
182
189
  end
183
190
 
184
- def commit_sha_suffix?(tag)
185
- # Some people suffix their versions with commit SHAs. Dependabot
186
- # can't order on those but will try to, so instead we should exclude
187
- # them (unless there's a `latest` version pushed to the registry, in
188
- # which case we'll use that to find the latest version)
189
- return false unless tag.match?(/(^|\-g?)[0-9a-f]{7,}$/)
191
+ def remove_prereleases(candidate_tags, version)
192
+ return candidate_tags if prerelease?(version)
190
193
 
191
- !tag.match?(/(^|\-)\d+$/)
194
+ candidate_tags.reject { |tag| prerelease?(tag) }
195
+ end
196
+
197
+ def remove_precision_changes(candidate_tags, version)
198
+ candidate_tags.select do |tag|
199
+ same_precision?(tag, version)
200
+ end
201
+ end
202
+
203
+ def same_precision?(tag, another_tag)
204
+ precision_of(numeric_version_from(tag)) == precision_of(numeric_version_from(another_tag))
192
205
  end
193
206
 
194
207
  def version_of_latest_tag
@@ -197,13 +210,13 @@ module Dependabot
197
210
  candidate_tag =
198
211
  tags_from_registry.
199
212
  select { |tag| canonical_version?(tag) }.
200
- sort_by { |t| version_class.new(numeric_version_from(t)) }.
213
+ sort_by { |t| comparable_version_from(t) }.
201
214
  reverse.
202
215
  find { |t| digest_of(t) == latest_digest }
203
216
 
204
217
  return unless candidate_tag
205
218
 
206
- version_class.new(numeric_version_from(candidate_tag))
219
+ comparable_version_from(candidate_tag)
207
220
  end
208
221
 
209
222
  def canonical_version?(tag)
@@ -293,6 +306,7 @@ module Dependabot
293
306
 
294
307
  return :year_month if version.match?(/^[12]\d{3}(?:[.\-]|$)/)
295
308
  return :year_month_day if version.match?(/^[12]\d{5}(?:[.\-]|$)/)
309
+ return :sha_suffixed if tag.match?(/(^|\-g?)[0-9a-f]{7,}$/)
296
310
  return :build_num if version.match?(/^\d+$/)
297
311
 
298
312
  :normal
@@ -307,7 +321,11 @@ module Dependabot
307
321
  return false unless latest_digest
308
322
  return false unless version_of_latest_tag
309
323
 
310
- version_class.new(numeric_version_from(tag)) > version_of_latest_tag
324
+ comparable_version_from(tag) > version_of_latest_tag
325
+ end
326
+
327
+ def comparable_version_from(tag)
328
+ version_class.new(numeric_version_from(tag))
311
329
  end
312
330
 
313
331
  def numeric_version_from(tag)
@@ -317,8 +335,9 @@ module Dependabot
317
335
  end
318
336
 
319
337
  def registry_hostname
320
- dependency.requirements.first[:source][:registry] ||
321
- "registry.hub.docker.com"
338
+ return dependency.requirements.first[:source][:registry] if dependency.requirements.first[:source][:registry]
339
+
340
+ credentials_finder.base_registry
322
341
  end
323
342
 
324
343
  def using_dockerhub?
@@ -350,11 +369,31 @@ module Dependabot
350
369
  )
351
370
  end
352
371
 
372
+ def sort_tags(candidate_tags, version)
373
+ candidate_tags.sort do |tag_a, tag_b|
374
+ if comparable_version_from(tag_a) > comparable_version_from(tag_b)
375
+ 1
376
+ elsif comparable_version_from(tag_a) < comparable_version_from(tag_b)
377
+ -1
378
+ elsif same_precision?(tag_a, version)
379
+ 1
380
+ elsif same_precision?(tag_b, version)
381
+ -1
382
+ else
383
+ 0
384
+ end
385
+ end
386
+ end
387
+
388
+ def precision_of(version)
389
+ version.split(/[.-]/).length
390
+ end
391
+
353
392
  def filter_ignored(candidate_tags)
354
393
  filtered =
355
394
  candidate_tags.
356
395
  reject do |tag|
357
- version = version_class.new(numeric_version_from(tag))
396
+ version = comparable_version_from(tag)
358
397
  ignore_requirements.any? { |r| r.satisfied_by?(version) }
359
398
  end
360
399
  if @raise_on_ignored && filter_lower_versions(filtered).empty? && filter_lower_versions(candidate_tags).any?
@@ -365,9 +404,9 @@ module Dependabot
365
404
  end
366
405
 
367
406
  def filter_lower_versions(tags)
368
- versions_array = tags.map { |tag| version_class.new(numeric_version_from(tag)) }
407
+ versions_array = tags.map { |tag| comparable_version_from(tag) }
369
408
  versions_array.
370
- select { |version| version > version_class.new(numeric_version_from(dependency.version)) }
409
+ select { |version| version > comparable_version_from(dependency.version) }
371
410
  end
372
411
  end
373
412
  end
@@ -10,6 +10,7 @@ module Dependabot
10
10
  module Utils
11
11
  class CredentialsFinder
12
12
  AWS_ECR_URL = /dkr\.ecr\.(?<region>[^.]+)\.amazonaws\.com/
13
+ DEFAULT_DOCKER_HUB_REGISTRY = "registry.hub.docker.com"
13
14
 
14
15
  def initialize(credentials)
15
16
  @credentials = credentials
@@ -26,6 +27,18 @@ module Dependabot
26
27
  build_aws_credentials(registry_details)
27
28
  end
28
29
 
30
+ def base_registry
31
+ @base_registry ||= credentials.find do |cred|
32
+ cred["type"] == "docker_registry" && cred["replaces-base"] == true
33
+ end
34
+ @base_registry ||= { "registry" => DEFAULT_DOCKER_HUB_REGISTRY, "credentials" => nil }
35
+ @base_registry["registry"]
36
+ end
37
+
38
+ def using_dockerhub?(registry)
39
+ registry == DEFAULT_DOCKER_HUB_REGISTRY
40
+ end
41
+
29
42
  private
30
43
 
31
44
  attr_reader :credentials
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dependabot
4
+ module Docker
5
+ module Utils
6
+ HELM_REGEXP = /values[\-a-zA-Z_0-9]*\.ya?ml$/i
7
+
8
+ def self.likely_helm_chart?(file)
9
+ file.name.match?(HELM_REGEXP)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -13,7 +13,7 @@ module Dependabot
13
13
  def initialize(version)
14
14
  release_part, update_part = version.split("_", 2)
15
15
 
16
- @release_part = Gem::Version.new(release_part)
16
+ @release_part = Gem::Version.new(release_part.tr("-", "."))
17
17
 
18
18
  @update_part = Gem::Version.new(update_part&.start_with?(/[0-9]/) ? update_part : 0)
19
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-docker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.213.0
4
+ version: 0.214.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-31 00:00:00.000000000 Z
11
+ date: 2022-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.213.0
19
+ version: 0.214.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.213.0
26
+ version: 0.214.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 3.13.0
61
+ version: 4.0.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 3.13.0
68
+ version: 4.0.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.37.1
117
+ version: 1.39.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.37.1
124
+ version: 1.39.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop-performance
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -221,6 +221,7 @@ files:
221
221
  - lib/dependabot/docker/requirement.rb
222
222
  - lib/dependabot/docker/update_checker.rb
223
223
  - lib/dependabot/docker/utils/credentials_finder.rb
224
+ - lib/dependabot/docker/utils/helpers.rb
224
225
  - lib/dependabot/docker/version.rb
225
226
  homepage: https://github.com/dependabot/dependabot-core
226
227
  licenses: