dependabot-docker 0.212.0 → 0.214.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dependabot/docker/file_fetcher.rb +16 -18
- data/lib/dependabot/docker/file_parser.rb +58 -43
- data/lib/dependabot/docker/file_updater.rb +36 -7
- data/lib/dependabot/docker/requirement.rb +5 -1
- data/lib/dependabot/docker/update_checker.rb +91 -53
- data/lib/dependabot/docker/utils/credentials_finder.rb +14 -1
- data/lib/dependabot/docker/utils/helpers.rb +13 -0
- data/lib/dependabot/docker/version.rb +22 -0
- metadata +14 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7aabb905dbb5a64638f936079c477b091dd8b2a05aad7cc070c10e11977cc97
|
4
|
+
data.tar.gz: 4cc6bbe0291ded5c2e975f2256561044700a6a5903f1d110815de0ff5a0da281
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2a1629644bf4dcc1a523aaef694b2601f0008361468dbde35008396bb9dfe6c225857946bdad4f6dad384f11b7c763357a50a8f27ab02fb8cde23f9ce6f7271
|
7
|
+
data.tar.gz: b5a6df5e91b49e9faa2d972ee74b4aba244f83051e076cf33dda73dc9f55deee7895f8ffc4e5e13ef4d309ae33e1d9a9ef0e710bf6b12dd35545d524ec7dca7b
|
@@ -1,13 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "dependabot/docker/utils/helpers"
|
4
|
+
require "dependabot/experiments"
|
3
5
|
require "dependabot/file_fetchers"
|
4
6
|
require "dependabot/file_fetchers/base"
|
5
7
|
|
6
8
|
module Dependabot
|
7
9
|
module Docker
|
8
10
|
class FileFetcher < Dependabot::FileFetchers::Base
|
9
|
-
YAML_REGEXP = /^[^\.]+\.ya?ml$/i
|
10
|
-
DOCKER_REGEXP = /dockerfile/i
|
11
|
+
YAML_REGEXP = /^[^\.]+\.ya?ml$/i
|
12
|
+
DOCKER_REGEXP = /dockerfile/i
|
11
13
|
|
12
14
|
def self.required_files_in?(filenames)
|
13
15
|
filenames.any? { |f| f.match?(DOCKER_REGEXP) } or
|
@@ -20,26 +22,18 @@ module Dependabot
|
|
20
22
|
|
21
23
|
private
|
22
24
|
|
23
|
-
def kubernetes_enabled?
|
24
|
-
options.key?(:kubernetes_updates) && options[:kubernetes_updates]
|
25
|
-
end
|
26
|
-
|
27
25
|
def fetch_files
|
28
26
|
fetched_files = []
|
29
27
|
fetched_files += correctly_encoded_dockerfiles
|
30
|
-
fetched_files += correctly_encoded_yamlfiles
|
28
|
+
fetched_files += correctly_encoded_yamlfiles
|
31
29
|
|
32
30
|
return fetched_files if fetched_files.any?
|
33
31
|
|
34
|
-
if
|
32
|
+
if incorrectly_encoded_dockerfiles.none? && incorrectly_encoded_yamlfiles.none?
|
35
33
|
raise(
|
36
34
|
Dependabot::DependencyFileNotFound,
|
37
|
-
File.join(directory, "Dockerfile")
|
38
|
-
|
39
|
-
elsif incorrectly_encoded_dockerfiles.none? && incorrectly_encoded_yamlfiles.none?
|
40
|
-
raise(
|
41
|
-
Dependabot::DependabotError,
|
42
|
-
"Found neither Kubernetes YAML nor Dockerfiles in #{directory}"
|
35
|
+
File.join(directory, "Dockerfile"),
|
36
|
+
"No Dockerfiles nor Kubernetes YAML found in #{directory}"
|
43
37
|
)
|
44
38
|
elsif incorrectly_encoded_dockerfiles.none?
|
45
39
|
raise(
|
@@ -84,10 +78,14 @@ module Dependabot
|
|
84
78
|
def correctly_encoded_yamlfiles
|
85
79
|
candidate_files = yamlfiles.select { |f| f.content.valid_encoding? }
|
86
80
|
candidate_files.select do |f|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
81
|
+
if f.type == "file" && Utils.likely_helm_chart?(f)
|
82
|
+
true
|
83
|
+
else
|
84
|
+
# This doesn't handle multi-resource files, but it shouldn't matter, since the first resource
|
85
|
+
# in a multi-resource file had better be a valid k8s resource
|
86
|
+
content = ::YAML.safe_load(f.content, aliases: true)
|
87
|
+
likely_kubernetes_resource?(content)
|
88
|
+
end
|
91
89
|
rescue ::Psych::Exception
|
92
90
|
false
|
93
91
|
end
|
@@ -15,27 +15,25 @@ module Dependabot
|
|
15
15
|
|
16
16
|
# Details of Docker regular expressions is at
|
17
17
|
# https://github.com/docker/distribution/blob/master/reference/regexp.go
|
18
|
-
DOMAIN_COMPONENT =
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
NAME = /\s+AS\s+(?<name>[\w-]+)/.freeze
|
18
|
+
DOMAIN_COMPONENT = /(?:[[:alnum:]]|[[:alnum:]][[[:alnum:]]-]*[[:alnum:]])/
|
19
|
+
DOMAIN = /(?:#{DOMAIN_COMPONENT}(?:\.#{DOMAIN_COMPONENT})+)/
|
20
|
+
REGISTRY = /(?<registry>#{DOMAIN}(?::\d+)?)/
|
21
|
+
|
22
|
+
NAME_COMPONENT = /(?:[a-z\d]+(?:(?:[._]|__|[-]*)[a-z\d]+)*)/
|
23
|
+
IMAGE = %r{(?<image>#{NAME_COMPONENT}(?:/#{NAME_COMPONENT})*)}
|
24
|
+
|
25
|
+
FROM = /FROM/i
|
26
|
+
PLATFORM = /--platform\=(?<platform>\S+)/
|
27
|
+
TAG = /:(?<tag>[\w][\w.-]{0,127})/
|
28
|
+
DIGEST = /@(?<digest>[^\s]+)/
|
29
|
+
NAME = /\s+AS\s+(?<name>[\w-]+)/
|
31
30
|
FROM_LINE =
|
32
31
|
%r{^#{FROM}\s+(#{PLATFORM}\s+)?(#{REGISTRY}/)?
|
33
|
-
#{IMAGE}#{TAG}?#{DIGEST}?#{NAME}?}x
|
32
|
+
#{IMAGE}#{TAG}?#{DIGEST}?#{NAME}?}x
|
34
33
|
|
35
|
-
AWS_ECR_URL = /dkr\.ecr\.(?<region>[^.]+)\.amazonaws\.com
|
34
|
+
AWS_ECR_URL = /dkr\.ecr\.(?<region>[^.]+)\.amazonaws\.com/
|
36
35
|
|
37
|
-
IMAGE_SPEC =
|
38
|
-
%r{^(#{REGISTRY}/)?#{IMAGE}#{TAG}?#{DIGEST}?#{NAME}?}x.freeze
|
36
|
+
IMAGE_SPEC = %r{^(#{REGISTRY}/)?#{IMAGE}#{TAG}?#{DIGEST}?#{NAME}?}x
|
39
37
|
|
40
38
|
def parse
|
41
39
|
dependency_set = DependencySet.new
|
@@ -103,8 +101,9 @@ module Dependabot
|
|
103
101
|
def version_from_digest(registry:, image:, digest:)
|
104
102
|
return unless digest
|
105
103
|
|
106
|
-
|
107
|
-
|
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"])
|
108
107
|
client.tags(repo, auto_paginate: true).fetch("tags").find do |tag|
|
109
108
|
digest == client.digest(repo, tag)
|
110
109
|
rescue DockerRegistry2::NotFound
|
@@ -114,46 +113,44 @@ module Dependabot
|
|
114
113
|
end
|
115
114
|
rescue DockerRegistry2::RegistryAuthenticationException,
|
116
115
|
RestClient::Forbidden
|
117
|
-
raise
|
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"])
|
118
120
|
|
119
|
-
raise
|
121
|
+
raise PrivateSourceTimedOut, registry_details["registry"]
|
120
122
|
end
|
121
123
|
|
122
124
|
def docker_repo_name(image, registry)
|
123
|
-
return image
|
124
|
-
return image
|
125
|
+
return image if image.include? "/"
|
126
|
+
return "library/#{image}" if credentials_finder.using_dockerhub?(registry)
|
125
127
|
|
126
|
-
|
128
|
+
image
|
127
129
|
end
|
128
130
|
|
129
|
-
def docker_registry_client(
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
DockerRegistry2::Registry.new(
|
134
|
-
"https://#{registry}",
|
135
|
-
user: credentials&.fetch("username", nil),
|
136
|
-
password: credentials&.fetch("password", nil)
|
137
|
-
)
|
138
|
-
else
|
139
|
-
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}")
|
140
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
|
+
)
|
141
142
|
end
|
142
143
|
|
143
|
-
def
|
144
|
-
credentials_finder.
|
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 }
|
145
148
|
end
|
146
149
|
|
147
150
|
def credentials_finder
|
148
151
|
@credentials_finder ||= Utils::CredentialsFinder.new(credentials)
|
149
152
|
end
|
150
153
|
|
151
|
-
def standard_registry?(registry)
|
152
|
-
return true if registry.nil?
|
153
|
-
|
154
|
-
registry == "registry.hub.docker.com"
|
155
|
-
end
|
156
|
-
|
157
154
|
def check_required_files
|
158
155
|
# Just check if there are any files at all.
|
159
156
|
return if dependency_files.any?
|
@@ -214,6 +211,8 @@ module Dependabot
|
|
214
211
|
images =
|
215
212
|
if !img.nil? && img.is_a?(String) && !img.empty?
|
216
213
|
[img]
|
214
|
+
elsif !img.nil? && img.is_a?(Hash) && !img.empty?
|
215
|
+
parse_helm(img)
|
217
216
|
else
|
218
217
|
[]
|
219
218
|
end
|
@@ -225,6 +224,22 @@ module Dependabot
|
|
225
224
|
# Dependencies include both Dockerfiles and yaml, select yaml.
|
226
225
|
dependency_files.select { |f| f.type == "file" && f.name.match?(/^[^\.]+\.ya?ml/i) }
|
227
226
|
end
|
227
|
+
|
228
|
+
def parse_helm(img_hash)
|
229
|
+
repo = img_hash.fetch("repository", nil)
|
230
|
+
tag = img_hash.key?("tag") ? img_hash.fetch("tag", nil) : img_hash.fetch("version", nil)
|
231
|
+
registry = img_hash.fetch("registry", nil)
|
232
|
+
|
233
|
+
if !repo.nil? && !registry.nil? && !tag.nil?
|
234
|
+
["#{registry}/#{repo}:#{tag}"]
|
235
|
+
elsif !repo.nil? && !tag.nil?
|
236
|
+
["#{repo}:#{tag}"]
|
237
|
+
elsif !repo.nil?
|
238
|
+
[repo]
|
239
|
+
else
|
240
|
+
[]
|
241
|
+
end
|
242
|
+
end
|
228
243
|
end
|
229
244
|
end
|
230
245
|
end
|
@@ -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"
|
@@ -7,7 +8,7 @@ require "dependabot/errors"
|
|
7
8
|
module Dependabot
|
8
9
|
module Docker
|
9
10
|
class FileUpdater < Dependabot::FileUpdaters::Base
|
10
|
-
FROM_REGEX = /FROM(\s+--platform\=\S+)?/i
|
11
|
+
FROM_REGEX = /FROM(\s+--platform\=\S+)?/i
|
11
12
|
|
12
13
|
def self.updated_files_regex
|
13
14
|
[
|
@@ -18,7 +19,6 @@ module Dependabot
|
|
18
19
|
|
19
20
|
def updated_dependency_files
|
20
21
|
updated_files = []
|
21
|
-
|
22
22
|
dependency_files.each do |file|
|
23
23
|
next unless requirement_changed?(file, dependency)
|
24
24
|
|
@@ -153,13 +153,29 @@ module Dependabot
|
|
153
153
|
end
|
154
154
|
|
155
155
|
def updated_yaml_content(file)
|
156
|
-
updated_content = update_image(file)
|
156
|
+
updated_content = Utils.likely_helm_chart?(file) ? update_helm(file) : update_image(file)
|
157
157
|
|
158
158
|
raise "Expected content to change!" if updated_content == file.content
|
159
159
|
|
160
160
|
updated_content
|
161
161
|
end
|
162
162
|
|
163
|
+
def update_helm(file)
|
164
|
+
# TODO: this won't work if two images have the same tag version
|
165
|
+
old_tags = old_helm_tags(file)
|
166
|
+
return if old_tags.empty?
|
167
|
+
|
168
|
+
modified_content = file.content
|
169
|
+
|
170
|
+
old_tags.each do |old_tag|
|
171
|
+
old_tag_regex = /^\s+(?:-\s)?(?:tag|version):\s+#{old_tag}(?=\s|$)/
|
172
|
+
modified_content = modified_content.gsub(old_tag_regex) do |old_img_tag|
|
173
|
+
old_img_tag.gsub(old_tag.to_s, new_yaml_tag(file).to_s)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
modified_content
|
177
|
+
end
|
178
|
+
|
163
179
|
def update_image(file)
|
164
180
|
old_images = old_yaml_images(file)
|
165
181
|
return if old_images.empty?
|
@@ -176,13 +192,18 @@ module Dependabot
|
|
176
192
|
end
|
177
193
|
|
178
194
|
def new_yaml_image(file)
|
179
|
-
|
180
|
-
prefix =
|
181
|
-
digest =
|
182
|
-
tag =
|
195
|
+
element = dependency.requirements.find { |r| r[:file] == file.name }
|
196
|
+
prefix = element.fetch(:source)[:registry] ? "#{element.fetch(:source)[:registry]}/" : ""
|
197
|
+
digest = element.fetch(:source)[:digest] ? "@#{element.fetch(:source)[:digest]}" : ""
|
198
|
+
tag = element.fetch(:source)[:tag] ? ":#{element.fetch(:source)[:tag]}" : ""
|
183
199
|
"#{prefix}#{dependency.name}#{tag}#{digest}"
|
184
200
|
end
|
185
201
|
|
202
|
+
def new_yaml_tag(file)
|
203
|
+
element = dependency.requirements.find { |r| r[:file] == file.name }
|
204
|
+
element.fetch(:source)[:tag] || ""
|
205
|
+
end
|
206
|
+
|
186
207
|
def old_yaml_images(file)
|
187
208
|
dependency.
|
188
209
|
previous_requirements.
|
@@ -193,6 +214,14 @@ module Dependabot
|
|
193
214
|
"#{prefix}#{dependency.name}#{tag}#{digest}"
|
194
215
|
end
|
195
216
|
end
|
217
|
+
|
218
|
+
def old_helm_tags(file)
|
219
|
+
dependency.
|
220
|
+
previous_requirements.
|
221
|
+
select { |r| r[:file] == file.name }.map do |r|
|
222
|
+
r.fetch(:source)[:tag] || ""
|
223
|
+
end
|
224
|
+
end
|
196
225
|
end
|
197
226
|
end
|
198
227
|
end
|
@@ -6,13 +6,17 @@ module Dependabot
|
|
6
6
|
module Docker
|
7
7
|
# Lifted from the bundler package manager
|
8
8
|
class Requirement < Gem::Requirement
|
9
|
-
# For consistency with other
|
9
|
+
# For consistency with other languages, we define a requirements array.
|
10
10
|
# Ruby doesn't have an `OR` separator for requirements, so it always
|
11
11
|
# contains a single element.
|
12
12
|
def self.requirements_array(requirement_string)
|
13
13
|
[new(requirement_string)]
|
14
14
|
end
|
15
15
|
|
16
|
+
def satisfied_by?(version)
|
17
|
+
super(version.release_part)
|
18
|
+
end
|
19
|
+
|
16
20
|
# Patches Gem::Requirement to make it accept requirement strings like
|
17
21
|
# "~> 4.2.5, >= 4.2.5.1" without first needing to split them.
|
18
22
|
def initialize(*requirements)
|
@@ -42,22 +42,19 @@ end
|
|
42
42
|
module Dependabot
|
43
43
|
module Docker
|
44
44
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
45
|
-
VERSION_REGEX =
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
VERSION_WITH_PFX_AND_SFX =
|
50
|
-
/^(?<prefix>[a-z\-]+-)?#{VERSION_REGEX}(?<suffix>-[a-z\-]+)?$/i.
|
51
|
-
freeze
|
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
|
48
|
+
VERSION_WITH_PFX_AND_SFX = /^(?<prefix>[a-z\-]+-)?#{VERSION_REGEX}(?<suffix>-[a-z\-]+)?$/i
|
52
49
|
NAME_WITH_VERSION =
|
53
50
|
/
|
54
51
|
#{VERSION_WITH_PFX}|
|
55
52
|
#{VERSION_WITH_SFX}|
|
56
53
|
#{VERSION_WITH_PFX_AND_SFX}
|
57
|
-
/x
|
54
|
+
/x
|
58
55
|
|
59
56
|
def latest_version
|
60
|
-
|
57
|
+
latest_version_from(dependency.version)
|
61
58
|
end
|
62
59
|
|
63
60
|
def latest_resolvable_version
|
@@ -74,7 +71,7 @@ module Dependabot
|
|
74
71
|
dependency.requirements.map do |req|
|
75
72
|
updated_source = req.fetch(:source).dup
|
76
73
|
updated_source[:digest] = updated_digest if req[:source][:digest]
|
77
|
-
updated_source[:tag] =
|
74
|
+
updated_source[:tag] = latest_version_from(req[:source][:tag]) if req[:source][:tag]
|
78
75
|
|
79
76
|
req.merge(source: updated_source)
|
80
77
|
end
|
@@ -120,7 +117,7 @@ module Dependabot
|
|
120
117
|
# Check the precision of the potentially higher tag is the same as the
|
121
118
|
# one it would replace. In the event that it's not the same, check the
|
122
119
|
# digests are also unequal. Avoids 'updating' ruby-2 -> ruby-2.5.1
|
123
|
-
return false if old_v
|
120
|
+
return false if precision_of(old_v) == precision_of(latest_v)
|
124
121
|
|
125
122
|
digest_of(version) == digest_of(latest_version)
|
126
123
|
end
|
@@ -134,33 +131,38 @@ module Dependabot
|
|
134
131
|
end
|
135
132
|
end
|
136
133
|
|
137
|
-
|
138
|
-
# it's the existing one) as it is what we later check the digest of.
|
139
|
-
def fetch_latest_version(version)
|
134
|
+
def latest_version_from(version)
|
140
135
|
@versions ||= {}
|
141
136
|
return @versions[version] if @versions.key?(version)
|
142
137
|
|
143
|
-
@versions[version] =
|
144
|
-
|
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)
|
138
|
+
@versions[version] = fetch_latest_version(version)
|
139
|
+
end
|
150
140
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
155
165
|
end
|
156
|
-
|
157
|
-
latest_tag =
|
158
|
-
filter_ignored(candidate_tags).
|
159
|
-
max_by do |tag|
|
160
|
-
[version_class.new(numeric_version_from(tag)), tag.length]
|
161
|
-
end
|
162
|
-
|
163
|
-
latest_tag || version
|
164
166
|
end
|
165
167
|
end
|
166
168
|
|
@@ -169,28 +171,37 @@ module Dependabot
|
|
169
171
|
original_suffix = suffix_of(version)
|
170
172
|
original_format = format_of(version)
|
171
173
|
|
172
|
-
|
174
|
+
candidate_tags =
|
175
|
+
tags_from_registry.
|
173
176
|
select { |tag| tag.match?(NAME_WITH_VERSION) }.
|
174
177
|
select { |tag| prefix_of(tag) == original_prefix }.
|
175
|
-
select { |tag| suffix_of(tag) == original_suffix || commit_sha_suffix?(tag) }.
|
176
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 }
|
177
182
|
end
|
178
183
|
|
179
184
|
def remove_version_downgrades(candidate_tags, version)
|
180
185
|
candidate_tags.select do |tag|
|
181
|
-
|
182
|
-
|
186
|
+
comparable_version_from(tag) >=
|
187
|
+
comparable_version_from(version)
|
183
188
|
end
|
184
189
|
end
|
185
190
|
|
186
|
-
def
|
187
|
-
|
188
|
-
# can't order on those but will try to, so instead we should exclude
|
189
|
-
# them (unless there's a `latest` version pushed to the registry, in
|
190
|
-
# which case we'll use that to find the latest version)
|
191
|
-
return false unless tag.match?(/(^|\-g?)[0-9a-f]{7,}$/)
|
191
|
+
def remove_prereleases(candidate_tags, version)
|
192
|
+
return candidate_tags if prerelease?(version)
|
192
193
|
|
193
|
-
|
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))
|
194
205
|
end
|
195
206
|
|
196
207
|
def version_of_latest_tag
|
@@ -199,13 +210,13 @@ module Dependabot
|
|
199
210
|
candidate_tag =
|
200
211
|
tags_from_registry.
|
201
212
|
select { |tag| canonical_version?(tag) }.
|
202
|
-
sort_by { |t|
|
213
|
+
sort_by { |t| comparable_version_from(t) }.
|
203
214
|
reverse.
|
204
215
|
find { |t| digest_of(t) == latest_digest }
|
205
216
|
|
206
217
|
return unless candidate_tag
|
207
218
|
|
208
|
-
|
219
|
+
comparable_version_from(candidate_tag)
|
209
220
|
end
|
210
221
|
|
211
222
|
def canonical_version?(tag)
|
@@ -295,6 +306,7 @@ module Dependabot
|
|
295
306
|
|
296
307
|
return :year_month if version.match?(/^[12]\d{3}(?:[.\-]|$)/)
|
297
308
|
return :year_month_day if version.match?(/^[12]\d{5}(?:[.\-]|$)/)
|
309
|
+
return :sha_suffixed if tag.match?(/(^|\-g?)[0-9a-f]{7,}$/)
|
298
310
|
return :build_num if version.match?(/^\d+$/)
|
299
311
|
|
300
312
|
:normal
|
@@ -309,7 +321,11 @@ module Dependabot
|
|
309
321
|
return false unless latest_digest
|
310
322
|
return false unless version_of_latest_tag
|
311
323
|
|
312
|
-
|
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))
|
313
329
|
end
|
314
330
|
|
315
331
|
def numeric_version_from(tag)
|
@@ -319,8 +335,9 @@ module Dependabot
|
|
319
335
|
end
|
320
336
|
|
321
337
|
def registry_hostname
|
322
|
-
dependency.requirements.first[:source][:registry]
|
323
|
-
|
338
|
+
return dependency.requirements.first[:source][:registry] if dependency.requirements.first[:source][:registry]
|
339
|
+
|
340
|
+
credentials_finder.base_registry
|
324
341
|
end
|
325
342
|
|
326
343
|
def using_dockerhub?
|
@@ -347,15 +364,36 @@ module Dependabot
|
|
347
364
|
DockerRegistry2::Registry.new(
|
348
365
|
"https://#{registry_hostname}",
|
349
366
|
user: registry_credentials&.fetch("username", nil),
|
350
|
-
password: registry_credentials&.fetch("password", nil)
|
367
|
+
password: registry_credentials&.fetch("password", nil),
|
368
|
+
read_timeout: 10
|
351
369
|
)
|
352
370
|
end
|
353
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
|
+
|
354
392
|
def filter_ignored(candidate_tags)
|
355
393
|
filtered =
|
356
394
|
candidate_tags.
|
357
395
|
reject do |tag|
|
358
|
-
version =
|
396
|
+
version = comparable_version_from(tag)
|
359
397
|
ignore_requirements.any? { |r| r.satisfied_by?(version) }
|
360
398
|
end
|
361
399
|
if @raise_on_ignored && filter_lower_versions(filtered).empty? && filter_lower_versions(candidate_tags).any?
|
@@ -366,9 +404,9 @@ module Dependabot
|
|
366
404
|
end
|
367
405
|
|
368
406
|
def filter_lower_versions(tags)
|
369
|
-
versions_array = tags.map { |tag|
|
407
|
+
versions_array = tags.map { |tag| comparable_version_from(tag) }
|
370
408
|
versions_array.
|
371
|
-
select { |version| version >
|
409
|
+
select { |version| version > comparable_version_from(dependency.version) }
|
372
410
|
end
|
373
411
|
end
|
374
412
|
end
|
@@ -9,7 +9,8 @@ module Dependabot
|
|
9
9
|
module Docker
|
10
10
|
module Utils
|
11
11
|
class CredentialsFinder
|
12
|
-
AWS_ECR_URL = /dkr\.ecr\.(?<region>[^.]+)\.amazonaws\.com
|
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
|
@@ -4,7 +4,29 @@ require "dependabot/utils"
|
|
4
4
|
|
5
5
|
module Dependabot
|
6
6
|
module Docker
|
7
|
+
# In the special case of Java, the version string may also contain
|
8
|
+
# optional "update number" and "identifier" components.
|
9
|
+
# See https://www.oracle.com/java/technologies/javase/versioning-naming.html
|
10
|
+
# for a description of Java versions.
|
11
|
+
#
|
7
12
|
class Version < Gem::Version
|
13
|
+
def initialize(version)
|
14
|
+
release_part, update_part = version.split("_", 2)
|
15
|
+
|
16
|
+
@release_part = Gem::Version.new(release_part.tr("-", "."))
|
17
|
+
|
18
|
+
@update_part = Gem::Version.new(update_part&.start_with?(/[0-9]/) ? update_part : 0)
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :release_part
|
22
|
+
|
23
|
+
def <=>(other)
|
24
|
+
sort_criteria <=> other.sort_criteria
|
25
|
+
end
|
26
|
+
|
27
|
+
def sort_criteria
|
28
|
+
[@release_part, @update_part]
|
29
|
+
end
|
8
30
|
end
|
9
31
|
end
|
10
32
|
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.
|
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-
|
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,42 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 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.
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: debase
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.2.3
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 0.2.3
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: debase-ruby_core_source
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - '='
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 0.10.16
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - '='
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 0.10.16
|
26
|
+
version: 0.214.0
|
55
27
|
- !ruby/object:Gem::Dependency
|
56
28
|
name: debug
|
57
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,14 +58,14 @@ dependencies:
|
|
86
58
|
requirements:
|
87
59
|
- - "~>"
|
88
60
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
61
|
+
version: 4.0.0
|
90
62
|
type: :development
|
91
63
|
prerelease: false
|
92
64
|
version_requirements: !ruby/object:Gem::Requirement
|
93
65
|
requirements:
|
94
66
|
- - "~>"
|
95
67
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
68
|
+
version: 4.0.0
|
97
69
|
- !ruby/object:Gem::Dependency
|
98
70
|
name: rake
|
99
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,42 +114,28 @@ dependencies:
|
|
142
114
|
requirements:
|
143
115
|
- - "~>"
|
144
116
|
- !ruby/object:Gem::Version
|
145
|
-
version: 1.
|
117
|
+
version: 1.39.0
|
146
118
|
type: :development
|
147
119
|
prerelease: false
|
148
120
|
version_requirements: !ruby/object:Gem::Requirement
|
149
121
|
requirements:
|
150
122
|
- - "~>"
|
151
123
|
- !ruby/object:Gem::Version
|
152
|
-
version: 1.
|
124
|
+
version: 1.39.0
|
153
125
|
- !ruby/object:Gem::Dependency
|
154
126
|
name: rubocop-performance
|
155
127
|
requirement: !ruby/object:Gem::Requirement
|
156
128
|
requirements:
|
157
129
|
- - "~>"
|
158
130
|
- !ruby/object:Gem::Version
|
159
|
-
version: 1.
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - "~>"
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: 1.14.2
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: ruby-debug-ide
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - "~>"
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: 0.7.3
|
131
|
+
version: 1.15.0
|
174
132
|
type: :development
|
175
133
|
prerelease: false
|
176
134
|
version_requirements: !ruby/object:Gem::Requirement
|
177
135
|
requirements:
|
178
136
|
- - "~>"
|
179
137
|
- !ruby/object:Gem::Version
|
180
|
-
version:
|
138
|
+
version: 1.15.0
|
181
139
|
- !ruby/object:Gem::Dependency
|
182
140
|
name: simplecov
|
183
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -263,6 +221,7 @@ files:
|
|
263
221
|
- lib/dependabot/docker/requirement.rb
|
264
222
|
- lib/dependabot/docker/update_checker.rb
|
265
223
|
- lib/dependabot/docker/utils/credentials_finder.rb
|
224
|
+
- lib/dependabot/docker/utils/helpers.rb
|
266
225
|
- lib/dependabot/docker/version.rb
|
267
226
|
homepage: https://github.com/dependabot/dependabot-core
|
268
227
|
licenses:
|
@@ -276,14 +235,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
276
235
|
requirements:
|
277
236
|
- - ">="
|
278
237
|
- !ruby/object:Gem::Version
|
279
|
-
version:
|
238
|
+
version: 3.1.0
|
280
239
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
281
240
|
requirements:
|
282
241
|
- - ">="
|
283
242
|
- !ruby/object:Gem::Version
|
284
|
-
version:
|
243
|
+
version: 3.1.0
|
285
244
|
requirements: []
|
286
|
-
rubygems_version: 3.
|
245
|
+
rubygems_version: 3.3.7
|
287
246
|
signing_key:
|
288
247
|
specification_version: 4
|
289
248
|
summary: Docker support for dependabot-common
|