dependabot-docker 0.306.0 → 0.309.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: 1542dcfc93d68ebe05d07e758a04988ba3cc07fa9a61ad17555da5c2f18c3291
4
- data.tar.gz: a5e56d32f9d7692035ff693a5d72197bb7b9939758daa0abe74dd1224fcce80d
3
+ metadata.gz: b5ace65f27d0e36a51171e52901faae1a9789e32c13b0c3706811919dc386d25
4
+ data.tar.gz: d5f5343ff0cef86c53ee7b36f4c5b1335f30022d2d8148cfcf64c8d17fee6010
5
5
  SHA512:
6
- metadata.gz: 99dd835ac8187035f36b6f5d348b8bc095a221638b31a4dccb80e864c3c5584a4a1703812876be827bd5979a9db9fc4580ae341ac142cd5701139634655e8c2d
7
- data.tar.gz: 8675326c09190974033b61f0abc0c7bfebf36618f128b26e21eb9057d898ed04aac9e2f4af9a1f23adec27508e10f85dc82030378152656b11b5d706f62d0db0
6
+ metadata.gz: fc21838afc4fc26997d7aa6ee3d4d74e17632512d81c3adbb784bb847cbefbff6ef0e6db47607fc9e24fa19fcf87b09cad218a384e70e81bb48e38ba112a4d87
7
+ data.tar.gz: f4b23db54586036756d46e25fadd8c34aa7826173f3b10882c6177c625977a2788f5aa0d53a91cff89a3b349f58c5c2be5fbd96a7b25e72500a86d2c99a81067
@@ -155,7 +155,7 @@ module Dependabot
155
155
 
156
156
  image = "#{repo}:#{tag}"
157
157
  image.prepend("#{registry}/") if registry
158
- image << "@sha256:#{digest}/" if digest
158
+ image << "@#{digest}/" if digest
159
159
  [image]
160
160
  end
161
161
 
@@ -12,6 +12,8 @@ require "dependabot/docker/file_parser"
12
12
  require "dependabot/docker/version"
13
13
  require "dependabot/docker/requirement"
14
14
  require "dependabot/shared/utils/credentials_finder"
15
+ require "dependabot/package/release_cooldown_options"
16
+ require "dependabot/package/package_release"
15
17
 
16
18
  module Dependabot
17
19
  module Docker
@@ -135,6 +137,7 @@ module Dependabot
135
137
  candidate_tags = remove_prereleases(candidate_tags, version_tag)
136
138
  candidate_tags = filter_ignored(candidate_tags)
137
139
  candidate_tags = sort_tags(candidate_tags, version_tag)
140
+ candidate_tags = apply_cooldown(candidate_tags)
138
141
 
139
142
  latest_tag = candidate_tags.last
140
143
  return version_tag unless latest_tag
@@ -179,6 +182,90 @@ module Dependabot
179
182
  end
180
183
  end
181
184
 
185
+ sig do
186
+ params(candidate_tags: T::Array[Dependabot::Docker::Tag])
187
+ .returns(T::Array[Dependabot::Docker::Tag])
188
+ end
189
+ def apply_cooldown(candidate_tags)
190
+ return candidate_tags if should_skip_cooldown?
191
+
192
+ candidate_tags.reverse_each do |tag|
193
+ details = publication_detail(tag)
194
+
195
+ next if !details || !details.released_at
196
+
197
+ return [tag] unless cooldown_period?(details.released_at)
198
+
199
+ Dependabot.logger.info("Skipping tag #{tag.name} due to cooldown period")
200
+ end
201
+
202
+ []
203
+ end
204
+
205
+ sig { params(candidate_tag: Dependabot::Docker::Tag).returns(T.nilable(Dependabot::Package::PackageRelease)) }
206
+ def publication_detail(candidate_tag)
207
+ return publication_details[candidate_tag.name] if publication_details.key?(candidate_tag.name)
208
+
209
+ details = get_tag_publication_details(candidate_tag)
210
+ publication_details[candidate_tag.name] = T.cast(details, Dependabot::Package::PackageRelease)
211
+
212
+ details
213
+ end
214
+
215
+ sig { params(tag: Dependabot::Docker::Tag).returns(T.nilable(Dependabot::Package::PackageRelease)) }
216
+ def get_tag_publication_details(tag)
217
+ digest_info = with_retries(max_attempts: 3, errors: transient_docker_errors) do
218
+ client = docker_registry_client
219
+ client.digest(docker_repo_name, tag.name)
220
+ end
221
+
222
+ first_digest = digest_info.first&.fetch("digest")
223
+ return nil unless first_digest
224
+
225
+ blob_info = with_retries(max_attempts: 3, errors: transient_docker_errors) do
226
+ client = docker_registry_client
227
+ client.blob(docker_repo_name, first_digest)
228
+ end
229
+
230
+ last_modified = blob_info.headers[:last_modified]
231
+ published_date = last_modified ? Time.parse(last_modified) : nil
232
+
233
+ Dependabot::Package::PackageRelease.new(
234
+ version: Dependabot::Version.new(tag.name),
235
+ released_at: published_date,
236
+ latest: false,
237
+ yanked: false,
238
+ url: nil,
239
+ package_type: "docker"
240
+ )
241
+ end
242
+
243
+ sig do
244
+ params(
245
+ max_attempts: Integer,
246
+ errors: T::Array[T.class_of(StandardError)],
247
+ _blk: T.proc.returns(T.untyped)
248
+ ).returns(T.untyped)
249
+ end
250
+ def with_retries(max_attempts: 3, errors: [], &_blk)
251
+ attempt = 0
252
+ begin
253
+ attempt += 1
254
+ yield
255
+ rescue *errors
256
+ raise if attempt >= max_attempts
257
+
258
+ retry
259
+ end
260
+ end
261
+
262
+ sig { returns(T::Hash[String, T.nilable(Dependabot::Package::PackageRelease)]) }
263
+ def publication_details
264
+ @publication_details ||= T.let({}, T.nilable(
265
+ T::Hash[String, T.nilable(Dependabot::Package::PackageRelease)]
266
+ ))
267
+ end
268
+
182
269
  sig { params(tags: T::Array[Dependabot::Docker::Tag]).returns(T::Array[String]) }
183
270
  def identify_common_components(tags)
184
271
  tag_parts = tags.map do |tag|
@@ -340,7 +427,7 @@ module Dependabot
340
427
 
341
428
  sig { params(tag: String).returns(T.nilable(String)) }
342
429
  def fetch_digest_of(tag)
343
- docker_registry_client.manifest_digest(docker_repo_name, tag)&.delete_prefix("sha256:")
430
+ docker_registry_client.manifest_digest(docker_repo_name, tag)
344
431
  rescue *transient_docker_errors => e
345
432
  attempt ||= 1
346
433
  attempt += 1
@@ -522,6 +609,31 @@ module Dependabot
522
609
  T.nilable(Dependabot::Docker::Tag)
523
610
  )
524
611
  end
612
+
613
+ sig { returns(T::Boolean) }
614
+ def should_skip_cooldown?
615
+ @update_cooldown.nil? || !cooldown_enabled? || !@update_cooldown.included?(dependency.name)
616
+ end
617
+
618
+ sig { returns(T::Boolean) }
619
+ def cooldown_enabled?
620
+ Dependabot::Experiments.enabled?(:enable_cooldown_for_docker)
621
+ end
622
+
623
+ sig do
624
+ returns(Integer)
625
+ end
626
+ def cooldown_days_for
627
+ cooldown = @update_cooldown
628
+
629
+ T.must(cooldown).default_days
630
+ end
631
+
632
+ sig { params(release_date: T.untyped).returns(T::Boolean) }
633
+ def cooldown_period?(release_date)
634
+ days = cooldown_days_for
635
+ (Time.now.to_i - release_date.to_i) < (days * 24 * 60 * 60)
636
+ end
525
637
  end
526
638
  # rubocop:enable Metrics/ClassLength
527
639
  end
@@ -33,7 +33,13 @@ module Dependabot
33
33
 
34
34
  sig { params(parsed_line: T::Hash[String, T.nilable(String)]).returns(T.nilable(String)) }
35
35
  def version_from(parsed_line)
36
- parsed_line.fetch("tag") || parsed_line.fetch("digest")
36
+ return nil unless parsed_line.fetch("tag") || parsed_line.fetch("digest")
37
+
38
+ if parsed_line.fetch("tag") && parsed_line.fetch("digest")
39
+ "#{parsed_line.fetch('tag')}@sha256:#{parsed_line.fetch('digest')}"
40
+ else
41
+ parsed_line.fetch("tag") || "sha256:#{parsed_line.fetch('digest')}"
42
+ end
37
43
  end
38
44
 
39
45
  sig { params(parsed_line: T::Hash[String, T.nilable(String)]).returns(T::Hash[String, T.nilable(String)]) }
@@ -42,7 +48,7 @@ module Dependabot
42
48
 
43
49
  source[:registry] = parsed_line.fetch("registry") if parsed_line.fetch("registry")
44
50
  source[:tag] = parsed_line.fetch("tag") if parsed_line.fetch("tag")
45
- source[:digest] = parsed_line.fetch("digest") if parsed_line.fetch("digest")
51
+ source[:digest] = "sha256:#{parsed_line.fetch('digest')}" if parsed_line.fetch("digest")
46
52
 
47
53
  source
48
54
  end
@@ -70,7 +70,7 @@ module Dependabot
70
70
  params(previous_content: String, old_source: T::Hash[Symbol, T.nilable(String)],
71
71
  new_source: T::Hash[Symbol, T.nilable(String)]).returns(String)
72
72
  end
73
- def update_digest_and_tag(previous_content, old_source, new_source)
73
+ def update_digest_and_tag(previous_content, old_source, new_source) # rubocop:disable Metrics/PerceivedComplexity
74
74
  old_digest = old_source[:digest]
75
75
  new_digest = new_source[:digest]
76
76
 
@@ -92,7 +92,7 @@ module Dependabot
92
92
  end
93
93
  old_declaration +=
94
94
  if specified_with_digest?(old_source)
95
- "@sha256:#{old_digest}"
95
+ "@#{old_digest}"
96
96
  else
97
97
  ""
98
98
  end
@@ -102,9 +102,16 @@ module Dependabot
102
102
  old_declaration_regex = build_old_declaration_regex(escaped_declaration)
103
103
 
104
104
  previous_content.gsub(old_declaration_regex) do |old_dec|
105
+ old_digest = old_digest.sub("sha256:", "") if old_digest&.start_with?("sha256:")
106
+ new_digest = new_digest.sub("sha256:", "") if new_digest&.start_with?("sha256:")
107
+
108
+ unless old_digest.to_s.empty?
109
+ old_dec = old_dec.gsub("@sha256:#{old_digest}", "@sha256:#{new_digest}")
110
+ old_dec = old_dec.gsub("@#{old_digest}", "@#{new_digest}")
111
+ end
112
+
113
+ old_dec = old_dec.gsub(":#{old_tag}", ":#{new_tag}") unless old_tag.to_s.empty?
105
114
  old_dec
106
- .gsub("@sha256:#{old_digest}", "@sha256:#{new_digest}")
107
- .gsub(":#{old_tag}", ":#{new_tag}")
108
115
  end
109
116
  end
110
117
 
@@ -160,7 +167,7 @@ module Dependabot
160
167
  def new_yaml_image(file)
161
168
  element = T.must(dependency).requirements.find { |r| r[:file] == file.name }
162
169
  prefix = element&.dig(:source, :registry) ? "#{element.fetch(:source)[:registry]}/" : ""
163
- digest = element&.dig(:source, :digest) ? "@sha256:#{element.fetch(:source)[:digest]}" : ""
170
+ digest = element&.dig(:source, :digest) ? "@#{element.fetch(:source)[:digest]}" : ""
164
171
  tag = element&.dig(:source, :tag) ? ":#{element.fetch(:source)[:tag]}" : ""
165
172
  "#{prefix}#{T.must(dependency).name}#{tag}#{digest}"
166
173
  end
@@ -169,7 +176,7 @@ module Dependabot
169
176
  def old_yaml_images(file)
170
177
  T.must(previous_requirements(file)).map do |r|
171
178
  prefix = r.fetch(:source)[:registry] ? "#{r.fetch(:source)[:registry]}/" : ""
172
- digest = r.fetch(:source)[:digest] ? "@sha256:#{r.fetch(:source)[:digest]}" : ""
179
+ digest = r.fetch(:source)[:digest] ? "@#{r.fetch(:source)[:digest]}" : ""
173
180
  tag = r.fetch(:source)[:tag] ? ":#{r.fetch(:source)[:tag]}" : ""
174
181
  "#{prefix}#{T.must(dependency).name}#{tag}#{digest}"
175
182
  end
@@ -179,7 +186,7 @@ module Dependabot
179
186
  def old_helm_tags(file)
180
187
  T.must(previous_requirements(file)).map do |r|
181
188
  tag = r.fetch(:source)[:tag] || ""
182
- digest = r.fetch(:source)[:digest] ? "@sha256:#{r.fetch(:source)[:digest]}" : ""
189
+ digest = r.fetch(:source)[:digest] ? "@#{r.fetch(:source)[:digest]}" : ""
183
190
  "#{tag}#{digest}"
184
191
  end
185
192
  end
@@ -188,7 +195,7 @@ module Dependabot
188
195
  def new_helm_tag(file)
189
196
  element = T.must(dependency).requirements.find { |r| r[:file] == file.name }
190
197
  tag = T.must(element).dig(:source, :tag) || ""
191
- digest = T.must(element).dig(:source, :digest) ? "@sha256:#{T.must(element).dig(:source, :digest)}" : ""
198
+ digest = T.must(element).dig(:source, :digest) ? "@#{T.must(element).dig(:source, :digest)}" : ""
192
199
  "#{tag}#{digest}"
193
200
  end
194
201
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-docker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.306.0
4
+ version: 0.309.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-04-10 00:00:00.000000000 Z
10
+ date: 2025-04-17 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: dependabot-common
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - '='
18
17
  - !ruby/object:Gem::Version
19
- version: 0.306.0
18
+ version: 0.309.0
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - '='
25
24
  - !ruby/object:Gem::Version
26
- version: 0.306.0
25
+ version: 0.309.0
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: debug
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -262,8 +261,7 @@ licenses:
262
261
  - MIT
263
262
  metadata:
264
263
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
265
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.306.0
266
- post_install_message:
264
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.309.0
267
265
  rdoc_options: []
268
266
  require_paths:
269
267
  - lib
@@ -278,8 +276,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
278
276
  - !ruby/object:Gem::Version
279
277
  version: 3.1.0
280
278
  requirements: []
281
- rubygems_version: 3.5.22
282
- signing_key:
279
+ rubygems_version: 3.6.3
283
280
  specification_version: 4
284
281
  summary: Provides Dependabot support for Docker
285
282
  test_files: []