dependabot-docker_compose 0.298.0 → 0.299.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 +4 -4
- data/lib/dependabot/docker_compose/file_fetcher.rb +1 -1
- data/lib/dependabot/docker_compose/file_parser.rb +44 -3
- data/lib/dependabot/docker_compose/file_updater.rb +2 -44
- data/lib/dependabot/docker_compose/package_manager.rb +0 -2
- data/lib/dependabot/docker_compose.rb +8 -4
- metadata +19 -15
- data/lib/dependabot/docker_compose/metadata_finder.rb +0 -39
- data/lib/dependabot/docker_compose/requirement.rb +0 -43
- data/lib/dependabot/docker_compose/tag.rb +0 -144
- data/lib/dependabot/docker_compose/update_checker.rb +0 -479
- data/lib/dependabot/docker_compose/version.rb +0 -84
- data/lib/dependabot/shared/shared_file_fetcher.rb +0 -99
- data/lib/dependabot/shared/shared_file_parser.rb +0 -80
- data/lib/dependabot/shared/shared_file_updater.rb +0 -261
- data/lib/dependabot/shared/utils/credentials_finder.rb +0 -101
- data/lib/dependabot/shared/utils/helpers.rb +0 -19
@@ -1,80 +0,0 @@
|
|
1
|
-
# typed: strong
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "dependabot/dependency"
|
5
|
-
require "dependabot/file_parsers"
|
6
|
-
require "dependabot/file_parsers/base"
|
7
|
-
require "sorbet-runtime"
|
8
|
-
|
9
|
-
module Dependabot
|
10
|
-
module Shared
|
11
|
-
class SharedFileParser < Dependabot::FileParsers::Base
|
12
|
-
extend T::Sig
|
13
|
-
extend T::Helpers
|
14
|
-
|
15
|
-
abstract!
|
16
|
-
|
17
|
-
require "dependabot/file_parsers/base/dependency_set"
|
18
|
-
|
19
|
-
# Details of Docker regular expressions is at
|
20
|
-
# https://github.com/docker/distribution/blob/master/reference/regexp.go
|
21
|
-
DOMAIN_COMPONENT = /(?:[[:alnum:]]|[[:alnum:]][[[:alnum:]]-]*[[:alnum:]])/
|
22
|
-
DOMAIN = /(?:#{DOMAIN_COMPONENT}(?:\.#{DOMAIN_COMPONENT})+)/
|
23
|
-
REGISTRY = /(?<registry>#{DOMAIN}(?::\d+)?)/
|
24
|
-
|
25
|
-
NAME_COMPONENT = /(?:[a-z\d]+(?:(?:[._]|__|[-]*)[a-z\d]+)*)/
|
26
|
-
IMAGE = %r{(?<image>#{NAME_COMPONENT}(?:/#{NAME_COMPONENT})*)}
|
27
|
-
|
28
|
-
TAG = /:(?<tag>[\w][\w.-]{0,127})/
|
29
|
-
DIGEST = /@(?<digest>[^\s]+)/
|
30
|
-
NAME = /\s+AS\s+(?<name>[\w-]+)/
|
31
|
-
|
32
|
-
protected
|
33
|
-
|
34
|
-
sig { params(parsed_line: T::Hash[String, T.nilable(String)]).returns(T.nilable(String)) }
|
35
|
-
def version_from(parsed_line)
|
36
|
-
parsed_line.fetch("tag") || parsed_line.fetch("digest")
|
37
|
-
end
|
38
|
-
|
39
|
-
sig { params(parsed_line: T::Hash[String, T.nilable(String)]).returns(T::Hash[String, T.nilable(String)]) }
|
40
|
-
def source_from(parsed_line)
|
41
|
-
source = {}
|
42
|
-
|
43
|
-
source[:registry] = parsed_line.fetch("registry") if parsed_line.fetch("registry")
|
44
|
-
source[:tag] = parsed_line.fetch("tag") if parsed_line.fetch("tag")
|
45
|
-
source[:digest] = parsed_line.fetch("digest") if parsed_line.fetch("digest")
|
46
|
-
|
47
|
-
source
|
48
|
-
end
|
49
|
-
|
50
|
-
sig do
|
51
|
-
params(file: Dependabot::DependencyFile, details: T::Hash[String, T.nilable(String)],
|
52
|
-
version: String).returns(Dependabot::Dependency)
|
53
|
-
end
|
54
|
-
def build_dependency(file, details, version)
|
55
|
-
Dependency.new(
|
56
|
-
name: T.must(details.fetch("image")),
|
57
|
-
version: version,
|
58
|
-
package_manager: package_manager,
|
59
|
-
requirements: [
|
60
|
-
requirement: nil,
|
61
|
-
groups: [],
|
62
|
-
file: file.name,
|
63
|
-
source: source_from(details)
|
64
|
-
]
|
65
|
-
)
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
sig { override.void }
|
71
|
-
def check_required_files; end
|
72
|
-
|
73
|
-
sig { abstract.returns(String) }
|
74
|
-
def package_manager; end
|
75
|
-
|
76
|
-
sig { abstract.returns(String) }
|
77
|
-
def file_type; end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,261 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "dependabot/file_updaters"
|
5
|
-
require "dependabot/file_updaters/base"
|
6
|
-
require "dependabot/errors"
|
7
|
-
require "sorbet-runtime"
|
8
|
-
require "dependabot/shared/utils/helpers"
|
9
|
-
|
10
|
-
module Dependabot
|
11
|
-
module Shared
|
12
|
-
class SharedFileUpdater < Dependabot::FileUpdaters::Base
|
13
|
-
extend T::Sig
|
14
|
-
extend T::Helpers
|
15
|
-
|
16
|
-
abstract!
|
17
|
-
|
18
|
-
FROM_REGEX = /FROM(\s+--platform\=\S+)?/i
|
19
|
-
|
20
|
-
sig { override.returns(T::Array[Dependabot::DependencyFile]) }
|
21
|
-
def updated_dependency_files
|
22
|
-
updated_files = []
|
23
|
-
dependency_files.each do |file|
|
24
|
-
next unless requirement_changed?(file, T.must(dependency))
|
25
|
-
|
26
|
-
updated_files << if file.name.match?(T.must(yaml_file_pattern))
|
27
|
-
updated_file(
|
28
|
-
file: file,
|
29
|
-
content: T.must(updated_yaml_content(file))
|
30
|
-
)
|
31
|
-
else
|
32
|
-
updated_file(
|
33
|
-
file: file,
|
34
|
-
content: T.must(updated_dockerfile_content(file))
|
35
|
-
)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
updated_files.reject! { |f| dependency_files.include?(f) }
|
40
|
-
raise "No files changed!" if updated_files.none?
|
41
|
-
|
42
|
-
updated_files
|
43
|
-
end
|
44
|
-
|
45
|
-
sig { abstract.returns(T.nilable(Regexp)) }
|
46
|
-
def yaml_file_pattern; end
|
47
|
-
|
48
|
-
sig { abstract.returns(T.nilable(Regexp)) }
|
49
|
-
def container_image_regex; end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
sig { params(file: Dependabot::DependencyFile).returns(T.nilable(String)) }
|
54
|
-
def updated_dockerfile_content(file)
|
55
|
-
old_sources = previous_sources(file)
|
56
|
-
new_sources = sources(file)
|
57
|
-
|
58
|
-
updated_content = T.let(file.content, T.untyped)
|
59
|
-
|
60
|
-
T.must(old_sources).zip(new_sources).each do |old_source, new_source|
|
61
|
-
updated_content = update_digest_and_tag(updated_content, old_source, T.must(new_source))
|
62
|
-
end
|
63
|
-
|
64
|
-
raise "Expected content to change!" if updated_content == file.content
|
65
|
-
|
66
|
-
updated_content
|
67
|
-
end
|
68
|
-
|
69
|
-
sig do
|
70
|
-
params(previous_content: String, old_source: T::Hash[Symbol, T.nilable(String)],
|
71
|
-
new_source: T::Hash[Symbol, T.nilable(String)]).returns(String)
|
72
|
-
end
|
73
|
-
def update_digest_and_tag(previous_content, old_source, new_source)
|
74
|
-
old_digest = old_source[:digest]
|
75
|
-
new_digest = new_source[:digest]
|
76
|
-
|
77
|
-
old_tag = old_source[:tag]
|
78
|
-
new_tag = new_source[:tag]
|
79
|
-
|
80
|
-
old_declaration =
|
81
|
-
if private_registry_url(old_source)
|
82
|
-
"#{private_registry_url(old_source)}/"
|
83
|
-
else
|
84
|
-
""
|
85
|
-
end
|
86
|
-
old_declaration += T.must(dependency).name
|
87
|
-
old_declaration +=
|
88
|
-
if specified_with_tag?(old_source)
|
89
|
-
":#{old_tag}"
|
90
|
-
else
|
91
|
-
""
|
92
|
-
end
|
93
|
-
old_declaration +=
|
94
|
-
if specified_with_digest?(old_source)
|
95
|
-
"@sha256:#{old_digest}"
|
96
|
-
else
|
97
|
-
""
|
98
|
-
end
|
99
|
-
|
100
|
-
escaped_declaration = Regexp.escape(old_declaration)
|
101
|
-
|
102
|
-
old_declaration_regex = build_old_declaration_regex(escaped_declaration)
|
103
|
-
|
104
|
-
previous_content.gsub(old_declaration_regex) do |old_dec|
|
105
|
-
old_dec
|
106
|
-
.gsub("@sha256:#{old_digest}", "@sha256:#{new_digest}")
|
107
|
-
.gsub(":#{old_tag}", ":#{new_tag}")
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
sig { params(escaped_declaration: String).returns(Regexp) }
|
112
|
-
def build_old_declaration_regex(escaped_declaration)
|
113
|
-
%r{^#{FROM_REGEX}\s+(docker\.io/)?#{escaped_declaration}(?=\s|$)}
|
114
|
-
end
|
115
|
-
|
116
|
-
sig { params(file: Dependabot::DependencyFile).returns(T.nilable(String)) }
|
117
|
-
def updated_yaml_content(file)
|
118
|
-
updated_content = file.content
|
119
|
-
updated_content = update_helm(file, updated_content) if Shared::Utils.likely_helm_chart?(file)
|
120
|
-
updated_content = update_image(file, updated_content)
|
121
|
-
|
122
|
-
raise "Expected content to change!" if updated_content == file.content
|
123
|
-
|
124
|
-
updated_content
|
125
|
-
end
|
126
|
-
|
127
|
-
sig { params(file: Dependabot::DependencyFile, content: T.nilable(String)).returns(T.nilable(String)) }
|
128
|
-
def update_helm(file, content)
|
129
|
-
old_tags = old_helm_tags(file)
|
130
|
-
return if old_tags.empty?
|
131
|
-
|
132
|
-
modified_content = content
|
133
|
-
|
134
|
-
old_tags.each do |old_tag|
|
135
|
-
old_tag_regex = /^\s*(?:-\s)?(?:tag|version):\s+["']?#{old_tag}["']?(?=\s|$)/
|
136
|
-
modified_content = modified_content&.gsub(old_tag_regex) do |old_img_tag|
|
137
|
-
old_img_tag.gsub(old_tag.to_s, new_helm_tag(file).to_s)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
modified_content
|
141
|
-
end
|
142
|
-
|
143
|
-
sig { params(file: Dependabot::DependencyFile, content: T.nilable(String)).returns(T.nilable(String)) }
|
144
|
-
def update_image(file, content)
|
145
|
-
old_images = old_yaml_images(file)
|
146
|
-
return if old_images.empty?
|
147
|
-
|
148
|
-
modified_content = content
|
149
|
-
|
150
|
-
old_images.each do |old_image|
|
151
|
-
old_image_regex = /^\s*(?:-\s)?image:\s+#{old_image}(?=\s|$)/
|
152
|
-
modified_content = modified_content&.gsub(old_image_regex) do |old_img|
|
153
|
-
old_img.gsub(old_image.to_s, new_yaml_image(file).to_s)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
modified_content
|
157
|
-
end
|
158
|
-
|
159
|
-
sig { params(file: Dependabot::DependencyFile).returns(String) }
|
160
|
-
def new_yaml_image(file)
|
161
|
-
element = T.must(dependency).requirements.find { |r| r[:file] == file.name }
|
162
|
-
prefix = element&.dig(:source, :registry) ? "#{element.fetch(:source)[:registry]}/" : ""
|
163
|
-
digest = element&.dig(:source, :digest) ? "@sha256:#{element.fetch(:source)[:digest]}" : ""
|
164
|
-
tag = element&.dig(:source, :tag) ? ":#{element.fetch(:source)[:tag]}" : ""
|
165
|
-
"#{prefix}#{T.must(dependency).name}#{tag}#{digest}"
|
166
|
-
end
|
167
|
-
|
168
|
-
sig { params(file: Dependabot::DependencyFile).returns(T::Array[String]) }
|
169
|
-
def old_yaml_images(file)
|
170
|
-
T.must(previous_requirements(file)).map do |r|
|
171
|
-
prefix = r.fetch(:source)[:registry] ? "#{r.fetch(:source)[:registry]}/" : ""
|
172
|
-
digest = r.fetch(:source)[:digest] ? "@sha256:#{r.fetch(:source)[:digest]}" : ""
|
173
|
-
tag = r.fetch(:source)[:tag] ? ":#{r.fetch(:source)[:tag]}" : ""
|
174
|
-
"#{prefix}#{T.must(dependency).name}#{tag}#{digest}"
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
sig { params(file: Dependabot::DependencyFile).returns(T::Array[String]) }
|
179
|
-
def old_helm_tags(file)
|
180
|
-
T.must(previous_requirements(file)).map do |r|
|
181
|
-
tag = r.fetch(:source)[:tag] || ""
|
182
|
-
digest = r.fetch(:source)[:digest] ? "@sha256:#{r.fetch(:source)[:digest]}" : ""
|
183
|
-
"#{tag}#{digest}"
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
sig { params(file: Dependabot::DependencyFile).returns(String) }
|
188
|
-
def new_helm_tag(file)
|
189
|
-
element = T.must(dependency).requirements.find { |r| r[:file] == file.name }
|
190
|
-
tag = T.must(element).dig(:source, :tag) || ""
|
191
|
-
digest = T.must(element).dig(:source, :digest) ? "@sha256:#{T.must(element).dig(:source, :digest)}" : ""
|
192
|
-
"#{tag}#{digest}"
|
193
|
-
end
|
194
|
-
|
195
|
-
protected
|
196
|
-
|
197
|
-
sig { params(file: Dependabot::DependencyFile, dependency: Dependabot::Dependency).returns(T::Boolean) }
|
198
|
-
def requirement_changed?(file, dependency)
|
199
|
-
changed_requirements =
|
200
|
-
dependency.requirements - T.must(dependency.previous_requirements)
|
201
|
-
|
202
|
-
changed_requirements.any? { |f| f[:file] == file.name }
|
203
|
-
end
|
204
|
-
|
205
|
-
sig { params(source: T::Hash[Symbol, T.nilable(String)]).returns(T::Boolean) }
|
206
|
-
def specified_with_tag?(source)
|
207
|
-
!source[:tag].nil?
|
208
|
-
end
|
209
|
-
|
210
|
-
sig { params(source: T::Hash[Symbol, T.nilable(String)]).returns(T::Boolean) }
|
211
|
-
def specified_with_digest?(source)
|
212
|
-
!source[:digest].nil?
|
213
|
-
end
|
214
|
-
|
215
|
-
sig { params(file: Dependabot::DependencyFile).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
216
|
-
def requirements(file)
|
217
|
-
T.must(dependency).requirements
|
218
|
-
.select { |r| r[:file] == file.name }
|
219
|
-
end
|
220
|
-
|
221
|
-
sig { params(file: Dependabot::DependencyFile).returns(T.nilable(T::Array[T::Hash[Symbol, T.untyped]])) }
|
222
|
-
def previous_requirements(file)
|
223
|
-
T.must(dependency).previous_requirements
|
224
|
-
&.select { |r| r[:file] == file.name }
|
225
|
-
end
|
226
|
-
|
227
|
-
sig { params(source: T::Hash[Symbol, T.nilable(String)]).returns(T.nilable(String)) }
|
228
|
-
def private_registry_url(source)
|
229
|
-
source[:registry]
|
230
|
-
end
|
231
|
-
|
232
|
-
sig { params(file: Dependabot::DependencyFile).returns(T::Array[T::Hash[Symbol, T.nilable(String)]]) }
|
233
|
-
def sources(file)
|
234
|
-
requirements(file).map { |r| r.fetch(:source) }
|
235
|
-
end
|
236
|
-
|
237
|
-
sig { params(file: Dependabot::DependencyFile).returns(T.nilable(T::Array[T::Hash[Symbol, T.nilable(String)]])) }
|
238
|
-
def previous_sources(file)
|
239
|
-
previous_requirements(file)&.map { |r| r.fetch(:source) }
|
240
|
-
end
|
241
|
-
|
242
|
-
sig { returns(T.nilable(Dependabot::Dependency)) }
|
243
|
-
def dependency
|
244
|
-
# Files will only ever be updating a single dependency
|
245
|
-
dependencies.first
|
246
|
-
end
|
247
|
-
|
248
|
-
sig { override.void }
|
249
|
-
def check_required_files
|
250
|
-
return if dependency_files.any?
|
251
|
-
|
252
|
-
raise "No #{file_type}!"
|
253
|
-
end
|
254
|
-
|
255
|
-
private
|
256
|
-
|
257
|
-
sig { abstract.returns(String) }
|
258
|
-
def file_type; end
|
259
|
-
end
|
260
|
-
end
|
261
|
-
end
|
@@ -1,101 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "aws-sdk-ecr"
|
5
|
-
require "base64"
|
6
|
-
require "sorbet-runtime"
|
7
|
-
|
8
|
-
require "dependabot/credential"
|
9
|
-
require "dependabot/errors"
|
10
|
-
|
11
|
-
module Dependabot
|
12
|
-
module Shared
|
13
|
-
module Utils
|
14
|
-
class CredentialsFinder
|
15
|
-
extend T::Sig
|
16
|
-
|
17
|
-
AWS_ECR_URL = /dkr\.ecr\.(?<region>[^.]+)\.amazonaws\.com/
|
18
|
-
DEFAULT_DOCKER_HUB_REGISTRY = "registry.hub.docker.com"
|
19
|
-
|
20
|
-
sig { params(credentials: T::Array[Dependabot::Credential]).void }
|
21
|
-
def initialize(credentials)
|
22
|
-
@credentials = credentials
|
23
|
-
end
|
24
|
-
|
25
|
-
sig { params(registry_hostname: T.nilable(String)).returns(T.nilable(Dependabot::Credential)) }
|
26
|
-
def credentials_for_registry(registry_hostname)
|
27
|
-
registry_details =
|
28
|
-
credentials
|
29
|
-
.select { |cred| cred["type"] == "docker_registry" }
|
30
|
-
.find { |cred| cred.fetch("registry") == registry_hostname }
|
31
|
-
return unless registry_details
|
32
|
-
return registry_details unless registry_hostname&.match?(AWS_ECR_URL)
|
33
|
-
|
34
|
-
build_aws_credentials(registry_details)
|
35
|
-
end
|
36
|
-
|
37
|
-
sig { returns(T.nilable(String)) }
|
38
|
-
def base_registry
|
39
|
-
@base_registry ||= T.let(
|
40
|
-
credentials.find do |cred|
|
41
|
-
cred["type"] == "docker_registry" && cred.replaces_base?
|
42
|
-
end,
|
43
|
-
T.nilable(Dependabot::Credential)
|
44
|
-
)
|
45
|
-
@base_registry ||= Dependabot::Credential.new({ "registry" => DEFAULT_DOCKER_HUB_REGISTRY,
|
46
|
-
"credentials" => nil })
|
47
|
-
@base_registry["registry"]
|
48
|
-
end
|
49
|
-
|
50
|
-
sig { params(registry: String).returns(T::Boolean) }
|
51
|
-
def using_dockerhub?(registry)
|
52
|
-
registry == DEFAULT_DOCKER_HUB_REGISTRY
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
sig { returns(T::Array[Dependabot::Credential]) }
|
58
|
-
attr_reader :credentials
|
59
|
-
|
60
|
-
sig { params(registry_details: Dependabot::Credential).returns(Dependabot::Credential) }
|
61
|
-
def build_aws_credentials(registry_details)
|
62
|
-
# If credentials have been generated from AWS we can just return them
|
63
|
-
return registry_details if registry_details["username"] == "AWS"
|
64
|
-
|
65
|
-
# Build a client either with explicit creds or default creds
|
66
|
-
registry_hostname = registry_details.fetch("registry")
|
67
|
-
region = registry_hostname.match(AWS_ECR_URL).named_captures.fetch("region")
|
68
|
-
aws_credentials = Aws::Credentials.new(
|
69
|
-
registry_details["username"],
|
70
|
-
registry_details["password"]
|
71
|
-
)
|
72
|
-
|
73
|
-
ecr_client =
|
74
|
-
if aws_credentials.set?
|
75
|
-
Aws::ECR::Client.new(region: region, credentials: aws_credentials)
|
76
|
-
else
|
77
|
-
# Let the client check default locations for credentials
|
78
|
-
Aws::ECR::Client.new(region: region)
|
79
|
-
end
|
80
|
-
|
81
|
-
# If the client still lacks credentials, we might be running within GitHub's
|
82
|
-
# Dependabot Service, in which case we might get them from the proxy
|
83
|
-
return registry_details if ecr_client.config.credentials.nil?
|
84
|
-
|
85
|
-
# Otherwise, we need to use the provided Access Key ID and secret to
|
86
|
-
# generate a temporary username and password
|
87
|
-
@authorization_tokens ||= T.let({}, T.nilable(T::Hash[String, String]))
|
88
|
-
@authorization_tokens[registry_hostname] ||=
|
89
|
-
ecr_client.get_authorization_token.authorization_data.first.authorization_token
|
90
|
-
username, password =
|
91
|
-
Base64.decode64(T.must(@authorization_tokens[registry_hostname])).split(":")
|
92
|
-
registry_details.merge(Dependabot::Credential.new({ "username" => username, "password" => password }))
|
93
|
-
rescue Aws::Errors::MissingCredentialsError,
|
94
|
-
Aws::ECR::Errors::UnrecognizedClientException,
|
95
|
-
Aws::ECR::Errors::InvalidSignatureException
|
96
|
-
raise PrivateSourceAuthenticationFailure, registry_hostname
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# typed: strong
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "sorbet-runtime"
|
5
|
-
|
6
|
-
module Dependabot
|
7
|
-
module Shared
|
8
|
-
module Utils
|
9
|
-
HELM_REGEXP = /values[\-a-zA-Z_0-9]*\.ya?ml$/i
|
10
|
-
|
11
|
-
extend T::Sig
|
12
|
-
|
13
|
-
sig { params(file: Dependabot::DependencyFile).returns(T::Boolean) }
|
14
|
-
def self.likely_helm_chart?(file)
|
15
|
-
file.name.match?(HELM_REGEXP)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|