dependabot-docker 0.297.0 → 0.297.1

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: 6d070a8c350a116ad04884cf6cbbe9b57c391ca1bf7b2ac98de5aaa207d8a530
4
- data.tar.gz: 9648e19e64e9a9b93fbe16aaa013a7211753209cd868a04d59b94636e75e6131
3
+ metadata.gz: cccf6c10f85241bf26410b82522a328174d17dcbb8d1a98bb9d840ab135660b2
4
+ data.tar.gz: 6796c6ab266df1313ee063ddb6c7c0b983b5297e3b5a0f30145604ae6cde9c9c
5
5
  SHA512:
6
- metadata.gz: 36a53dc44f6dce85bd127a67411cdde5307970168c29d923c44c1aa746063140e885b4df66d03136ffdc841883987361b037cf29215ca7b04007a2e4867467a4
7
- data.tar.gz: 93974ab9675312d56b135f9d99731f0d8f4b368718118e467d8025171cdbd8277ac848ad706edcc3193d906031a6c337086d348afcf380636b6d0003fa7817d8
6
+ metadata.gz: 4a501a6453057650b26929251686eda18440fd30aec093cfcd7c84a8fa908ed0a1893fea3a3f6cb7078c1dad93d0ebe096c9fde3c8de06205627299567aadada
7
+ data.tar.gz: 823c1834d1723c2b970424acdd8f1ecd5ef02aa0013230a46fd6457eb74dc115c50e2b10d70117147fe3e425d4d128ecf8a0939d686f4d1124ff0e85f5fbae59
@@ -1,68 +1,63 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "sorbet-runtime"
5
- require "dependabot/docker/utils/helpers"
6
- require "dependabot/file_fetchers"
7
- require "dependabot/file_fetchers/base"
4
+ require "dependabot/shared/utils/helpers"
5
+ require "dependabot/shared/shared_file_fetcher"
8
6
 
9
7
  module Dependabot
10
8
  module Docker
11
- class FileFetcher < Dependabot::FileFetchers::Base
9
+ class FileFetcher < Dependabot::Shared::SharedFileFetcher
12
10
  extend T::Sig
13
- extend T::Helpers
14
11
 
15
- YAML_REGEXP = /^[^\.].*\.ya?ml$/i
16
12
  DOCKER_REGEXP = /dockerfile|containerfile/i
17
13
 
14
+ sig { override.returns(Regexp) }
15
+ def self.filename_regex
16
+ DOCKER_REGEXP
17
+ end
18
+
19
+ sig { override.returns(String) }
20
+ def self.required_files_message
21
+ "Repo must contain a Dockerfile, Containerfile, or Kubernetes YAML files."
22
+ end
23
+
18
24
  sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
19
25
  def self.required_files_in?(filenames)
20
26
  filenames.any? { |f| f.match?(DOCKER_REGEXP) } or
21
27
  filenames.any? { |f| f.match?(YAML_REGEXP) }
22
28
  end
23
29
 
30
+ private
31
+
24
32
  sig { override.returns(String) }
25
- def self.required_files_message
26
- "Repo must contain a Dockerfile, Containerfile, or Kubernetes YAML files."
33
+ def default_file_name
34
+ "Dockerfile"
35
+ end
36
+
37
+ sig { override.returns(String) }
38
+ def file_type
39
+ "Docker"
27
40
  end
28
41
 
29
42
  sig { override.returns(T::Array[DependencyFile]) }
30
43
  def fetch_files
31
- fetched_files = []
32
- fetched_files += correctly_encoded_dockerfiles
33
- fetched_files += correctly_encoded_yamlfiles
44
+ fetched_files = correctly_encoded_dockerfiles
45
+ fetched_files += super
34
46
 
35
47
  return fetched_files if fetched_files.any?
36
48
 
37
- if incorrectly_encoded_dockerfiles.none? && incorrectly_encoded_yamlfiles.none?
38
- raise Dependabot::DependencyFileNotFound.new(
39
- File.join(directory, "Dockerfile"),
40
- "No Dockerfiles nor Kubernetes YAML found in #{directory}"
41
- )
42
- elsif incorrectly_encoded_dockerfiles.none?
43
- raise(
44
- Dependabot::DependencyFileNotParseable,
45
- T.must(incorrectly_encoded_yamlfiles.first).path
46
- )
47
- else
48
- raise(
49
- Dependabot::DependencyFileNotParseable,
50
- T.must(incorrectly_encoded_dockerfiles.first).path
51
- )
52
- end
49
+ raise_appropriate_error(incorrectly_encoded_dockerfiles)
53
50
  end
54
51
 
55
- private
56
-
57
52
  sig { returns(T::Array[DependencyFile]) }
58
53
  def dockerfiles
59
- @dockerfiles ||= T.let(fetch_dockerfiles, T.nilable(T::Array[DependencyFile]))
54
+ @dockerfiles ||= T.let(fetch_candidate_dockerfiles, T.nilable(T::Array[DependencyFile]))
60
55
  end
61
56
 
62
- sig { returns(T::Array[Dependabot::DependencyFile]) }
63
- def fetch_dockerfiles
57
+ sig { returns(T::Array[DependencyFile]) }
58
+ def fetch_candidate_dockerfiles
64
59
  repo_contents(raise_errors: false)
65
- .select { |f| f.type == "file" && f.name.match?(DOCKER_REGEXP) }
60
+ .select { |f| f.type == "file" && f.name.match?(self.class.filename_regex) }
66
61
  .map { |f| fetch_file_from_host(f.name) }
67
62
  end
68
63
 
@@ -75,44 +70,6 @@ module Dependabot
75
70
  def incorrectly_encoded_dockerfiles
76
71
  dockerfiles.reject { |f| f.content&.valid_encoding? }
77
72
  end
78
-
79
- sig { returns(T::Array[DependencyFile]) }
80
- def yamlfiles
81
- @yamlfiles ||= T.let(
82
- repo_contents(raise_errors: false)
83
- .select { |f| f.type == "file" && f.name.match?(YAML_REGEXP) }
84
- .map { |f| fetch_file_from_host(f.name) },
85
- T.nilable(T::Array[DependencyFile])
86
- )
87
- end
88
-
89
- sig { params(resource: Object).returns(T.nilable(T::Boolean)) }
90
- def likely_kubernetes_resource?(resource)
91
- # Heuristic for being a Kubernetes resource. We could make this tighter but this probably works well.
92
- resource.is_a?(::Hash) && resource.key?("apiVersion") && resource.key?("kind")
93
- end
94
-
95
- sig { returns(T::Array[Dependabot::DependencyFile]) }
96
- def correctly_encoded_yamlfiles
97
- candidate_files = yamlfiles.select { |f| f.content&.valid_encoding? }
98
- candidate_files.select do |f|
99
- if f.type == "file" && Utils.likely_helm_chart?(f)
100
- true
101
- else
102
- # This doesn't handle multi-resource files, but it shouldn't matter, since the first resource
103
- # in a multi-resource file had better be a valid k8s resource
104
- content = ::YAML.safe_load(T.must(f.content), aliases: true)
105
- likely_kubernetes_resource?(content)
106
- end
107
- rescue ::Psych::Exception
108
- false
109
- end
110
- end
111
-
112
- sig { returns(T::Array[Dependabot::DependencyFile]) }
113
- def incorrectly_encoded_yamlfiles
114
- yamlfiles.reject { |f| f.content&.valid_encoding? }
115
- end
116
73
  end
117
74
  end
118
75
  end
@@ -1,47 +1,27 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "docker_registry2"
5
-
6
- require "dependabot/dependency"
7
- require "dependabot/file_parsers"
8
- require "dependabot/file_parsers/base"
9
- require "dependabot/errors"
10
- require "sorbet-runtime"
4
+ require "dependabot/shared/shared_file_parser"
11
5
  require "dependabot/docker/package_manager"
12
6
 
13
7
  module Dependabot
14
8
  module Docker
15
- class FileParser < Dependabot::FileParsers::Base
9
+ class FileParser < Dependabot::Shared::SharedFileParser
16
10
  extend T::Sig
17
11
 
18
- require "dependabot/file_parsers/base/dependency_set"
19
-
20
12
  YAML_REGEXP = /^[^\.].*\.ya?ml$/i
21
-
22
- # Details of Docker regular expressions is at
23
- # https://github.com/docker/distribution/blob/master/reference/regexp.go
24
- DOMAIN_COMPONENT = /(?:[[:alnum:]]|[[:alnum:]][[[:alnum:]]-]*[[:alnum:]])/
25
- DOMAIN = /(?:#{DOMAIN_COMPONENT}(?:\.#{DOMAIN_COMPONENT})+)/
26
- REGISTRY = /(?<registry>#{DOMAIN}(?::\d+)?)/
27
-
28
- NAME_COMPONENT = /(?:[a-z\d]+(?:(?:[._]|__|[-]*)[a-z\d]+)*)/
29
- IMAGE = %r{(?<image>#{NAME_COMPONENT}(?:/#{NAME_COMPONENT})*)}
30
-
31
13
  FROM = /FROM/i
32
14
  PLATFORM = /--platform\=(?<platform>\S+)/
33
15
  TAG_NO_PREFIX = /(?<tag>[\w][\w.-]{0,127})/
34
16
  TAG = /:#{TAG_NO_PREFIX}/
35
17
  DIGEST = /(?<digest>[0-9a-f]{64})/
36
- NAME = /\s+AS\s+(?<name>[\w-]+)/
18
+
37
19
  FROM_LINE =
38
20
  %r{^#{FROM}\s+(#{PLATFORM}\s+)?(#{REGISTRY}/)?
39
21
  #{IMAGE}#{TAG}?(?:@sha256:#{DIGEST})?#{NAME}?}x
40
- TAG_WITH_DIGEST = /^#{TAG_NO_PREFIX}(?:@sha256:#{DIGEST})?/x
41
-
42
- AWS_ECR_URL = /dkr\.ecr\.(?<region>[^.]+)\.amazonaws\.com/
43
22
 
44
23
  IMAGE_SPEC = %r{^(#{REGISTRY}/)?#{IMAGE}#{TAG}?(?:@sha256:#{DIGEST})?#{NAME}?}x
24
+ TAG_WITH_DIGEST = /^#{TAG_NO_PREFIX}(?:@sha256:#{DIGEST})?/x
45
25
 
46
26
  sig { returns(Ecosystem) }
47
27
  def ecosystem
@@ -54,7 +34,6 @@ module Dependabot
54
34
  )
55
35
  end
56
36
 
57
- # rubocop:disable Metrics/AbcSize
58
37
  sig { override.returns(T::Array[Dependabot::Dependency]) }
59
38
  def parse
60
39
  dependency_set = DependencySet.new
@@ -69,75 +48,55 @@ module Dependabot
69
48
  version = version_from(parsed_from_line)
70
49
  next unless version
71
50
 
72
- dependency_set << Dependency.new(
73
- name: T.must(parsed_from_line.fetch("image")),
74
- version: version,
75
- package_manager: "docker",
76
- requirements: [
77
- requirement: nil,
78
- groups: [],
79
- file: dockerfile.name,
80
- source: source_from(parsed_from_line)
81
- ]
82
- )
51
+ dependency_set << build_dependency(dockerfile, parsed_from_line, version)
83
52
  end
84
53
  end
85
54
 
86
55
  manifest_files.each do |file|
87
- if file.content && T.must(file.content).start_with?("\uFEFF")
88
- # 0xFEFF is the encoding for the byte order mark (BOM). If a YAML file is loaded with a BOM it will parse
89
- # successfully, but will only load the first line. To prevent this nearly empty object from being returned,
90
- # the BOM is manually detected and reported as a parse error.
91
- file_path = Pathname.new(file.directory).join(file.name).cleanpath.to_path
92
- msg = "The file appears to have been saved with a byte order mark (BOM). This will prevent proper parsing."
93
- raise Dependabot::DependencyFileNotParseable.new(file_path, msg)
94
- end
56
+ check_manifest_file_encoding(file)
95
57
  dependency_set += workfile_file_dependencies(file)
96
58
  end
97
59
 
98
60
  dependency_set.dependencies
99
61
  end
100
- # rubocop:enable Metrics/AbcSize
101
62
 
102
63
  private
103
64
 
65
+ sig { override.returns(String) }
66
+ def package_manager
67
+ "docker"
68
+ end
69
+
70
+ sig { override.returns(String) }
71
+ def file_type
72
+ "Dockerfile"
73
+ end
74
+
104
75
  sig { returns(T::Array[Dependabot::DependencyFile]) }
105
76
  def dockerfiles
106
77
  # The Docker file fetcher fetches Dockerfiles and yaml files. Reject yaml files.
107
78
  dependency_files.reject { |f| f.type == "file" && f.name.match?(YAML_REGEXP) }
108
79
  end
109
80
 
110
- sig { params(parsed_from_line: T::Hash[String, T.nilable(String)]).returns(T.nilable(String)) }
111
- def version_from(parsed_from_line)
112
- parsed_from_line.fetch("tag") || parsed_from_line.fetch("digest")
113
- end
114
-
115
- sig { params(parsed_from_line: T::Hash[String, T.nilable(String)]).returns(T::Hash[String, T.nilable(String)]) }
116
- def source_from(parsed_from_line)
117
- source = {}
118
-
119
- source[:registry] = parsed_from_line.fetch("registry") if parsed_from_line.fetch("registry")
120
-
121
- source[:tag] = parsed_from_line.fetch("tag") if parsed_from_line.fetch("tag")
122
-
123
- source[:digest] = parsed_from_line.fetch("digest") if parsed_from_line.fetch("digest")
124
-
125
- source
81
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
82
+ def manifest_files
83
+ dependency_files.select { |f| f.type == "file" && f.name.match?(YAML_REGEXP) }
126
84
  end
127
85
 
128
- sig { override.void }
129
- def check_required_files
130
- # Just check if there are any files at all.
131
- return if dependency_files.any?
86
+ sig { params(file: Dependabot::DependencyFile).void }
87
+ def check_manifest_file_encoding(file)
88
+ return unless file.content&.start_with?("\uFEFF")
132
89
 
133
- raise "No Dockerfile!"
90
+ file_path = Pathname.new(file.directory).join(file.name).cleanpath.to_path
91
+ msg = "The file appears to have been saved with a byte order mark (BOM). This will prevent proper parsing."
92
+ raise Dependabot::DependencyFileNotParseable.new(file_path, msg)
134
93
  end
135
94
 
136
- sig { params(file: T.untyped).returns(Dependabot::FileParsers::Base::DependencySet) }
95
+ sig { params(file: Dependabot::DependencyFile).returns(DependencySet) }
137
96
  def workfile_file_dependencies(file)
138
97
  dependency_set = DependencySet.new
139
98
 
140
- resources = file.content.split(/^---$/).map(&:strip).reject(&:empty?) # assuming a yaml file
99
+ resources = T.must(file.content).split(/^---$/).map(&:strip).reject(&:empty?)
141
100
  resources.flat_map do |resource|
142
101
  json = YAML.safe_load(resource, aliases: true)
143
102
  images = deep_fetch_images(json).uniq
@@ -152,7 +111,7 @@ module Dependabot
152
111
  version = version_from(details)
153
112
  next unless version
154
113
 
155
- dependency_set << build_image_dependency(file, details, version)
114
+ dependency_set << build_dependency(file, details, version)
156
115
  end
157
116
  end
158
117
 
@@ -161,25 +120,7 @@ module Dependabot
161
120
  raise Dependabot::DependencyFileNotParseable, file.path
162
121
  end
163
122
 
164
- sig do
165
- params(file: T.untyped, details: T.untyped,
166
- version: T.nilable(T.any(String, Dependabot::Version))).returns(Dependabot::Dependency)
167
- end
168
- def build_image_dependency(file, details, version)
169
- Dependency.new(
170
- name: details.fetch("image"),
171
- version: version,
172
- package_manager: "docker",
173
- requirements: [
174
- requirement: nil,
175
- groups: [],
176
- file: file.name,
177
- source: source_from(details)
178
- ]
179
- )
180
- end
181
-
182
- sig { params(json_obj: T.anything).returns(T.untyped) }
123
+ sig { params(json_obj: T.anything).returns(T::Array[String]) }
183
124
  def deep_fetch_images(json_obj)
184
125
  case json_obj
185
126
  when Hash then deep_fetch_images_from_hash(json_obj)
@@ -188,7 +129,7 @@ module Dependabot
188
129
  end
189
130
  end
190
131
 
191
- sig { params(json_object: T.untyped).returns(T::Array[T.untyped]) }
132
+ sig { params(json_object: T::Hash[T.untyped, T.untyped]).returns(T::Array[String]) }
192
133
  def deep_fetch_images_from_hash(json_object)
193
134
  img = json_object.fetch("image", nil)
194
135
 
@@ -204,12 +145,6 @@ module Dependabot
204
145
  images + json_object.values.flat_map { |obj| deep_fetch_images(obj) }
205
146
  end
206
147
 
207
- sig { returns(T::Array[Dependabot::DependencyFile]) }
208
- def manifest_files
209
- # Dependencies include both Dockerfiles and yaml, select yaml.
210
- dependency_files.select { |f| f.type == "file" && f.name.match?(YAML_REGEXP) }
211
- end
212
-
213
148
  sig { params(img_hash: T::Hash[String, T.nilable(String)]).returns(T::Array[String]) }
214
149
  def parse_helm(img_hash)
215
150
  tag_value = img_hash.key?("tag") ? img_hash.fetch("tag", nil) : img_hash.fetch("version", nil)
@@ -230,6 +165,13 @@ module Dependabot
230
165
  image << "@sha256:#{digest}/" if digest
231
166
  [image]
232
167
  end
168
+
169
+ sig { override.void }
170
+ def check_required_files
171
+ return if dependency_files.any?
172
+
173
+ raise "No #{file_type}!"
174
+ end
233
175
  end
234
176
  end
235
177
  end
@@ -1,253 +1,38 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
- require "dependabot/docker/utils/helpers"
5
- require "dependabot/file_updaters"
6
- require "dependabot/file_updaters/base"
7
- require "dependabot/errors"
8
4
  require "sorbet-runtime"
5
+ require "dependabot/file_fetchers"
6
+ require "dependabot/file_fetchers/base"
7
+ require "dependabot/shared/shared_file_updater"
9
8
 
10
9
  module Dependabot
11
10
  module Docker
12
- class FileUpdater < Dependabot::FileUpdaters::Base
11
+ class FileUpdater < Dependabot::Shared::SharedFileUpdater
13
12
  extend T::Sig
14
13
 
15
- FROM_REGEX = /FROM(\s+--platform\=\S+)?/i
16
-
17
14
  YAML_REGEXP = /^[^\.].*\.ya?ml$/i
18
15
  DOCKER_REGEXP = /(docker|container)file/i
16
+ FROM_REGEX = /FROM(\s+--platform\=\S+)?/i
19
17
 
20
18
  sig { override.returns(T::Array[Regexp]) }
21
19
  def self.updated_files_regex
22
- [
23
- DOCKER_REGEXP,
24
- YAML_REGEXP
25
- ]
26
- end
27
-
28
- sig { override.returns(T::Array[Dependabot::DependencyFile]) }
29
- def updated_dependency_files
30
- updated_files = []
31
- dependency_files.each do |file|
32
- next unless requirement_changed?(file, T.must(dependency))
33
-
34
- updated_files << if file.name.match?(YAML_REGEXP)
35
- updated_file(
36
- file: file,
37
- content: T.must(updated_yaml_content(file))
38
- )
39
- else
40
- updated_file(
41
- file: file,
42
- content: updated_dockerfile_content(file)
43
- )
44
- end
45
- end
46
-
47
- updated_files.reject! { |f| dependency_files.include?(f) }
48
- raise "No files changed!" if updated_files.none?
49
-
50
- updated_files
51
- end
52
-
53
- private
54
-
55
- sig { returns T.nilable(Dependabot::Dependency) }
56
- def dependency
57
- # Dockerfiles will only ever be updating a single dependency
58
- dependencies.first
59
- end
60
-
61
- sig { override.void }
62
- def check_required_files
63
- # Just check if there are any files at all.
64
- return if dependency_files.any?
65
-
66
- raise "No Dockerfile or Containerfile!"
67
- end
68
-
69
- sig { params(file: Dependabot::DependencyFile).returns(String) }
70
- def updated_dockerfile_content(file)
71
- old_sources = previous_sources(file)
72
- new_sources = sources(file)
73
-
74
- updated_content = T.let(file.content, T.untyped)
75
-
76
- T.must(old_sources).zip(new_sources).each do |old_source, new_source|
77
- updated_content = update_digest_and_tag(updated_content, old_source, T.must(new_source))
78
- end
79
-
80
- raise "Expected content to change!" if updated_content == file.content
81
-
82
- updated_content
83
- end
84
-
85
- sig do
86
- params(previous_content: String, old_source: T::Hash[Symbol, T.nilable(String)],
87
- new_source: T::Hash[Symbol, T.nilable(String)]).returns(String)
88
- end
89
- def update_digest_and_tag(previous_content, old_source, new_source)
90
- old_digest = old_source[:digest]
91
- new_digest = new_source[:digest]
92
-
93
- old_tag = old_source[:tag]
94
- new_tag = new_source[:tag]
95
-
96
- old_declaration =
97
- if private_registry_url(old_source) then "#{private_registry_url(old_source)}/"
98
- else
99
- ""
100
- end
101
- old_declaration += T.must(dependency).name
102
- old_declaration +=
103
- if specified_with_tag?(old_source) then ":#{old_tag}"
104
- else
105
- ""
106
- end
107
- old_declaration +=
108
- if specified_with_digest?(old_source) then "@sha256:#{old_digest}"
109
- else
110
- ""
111
- end
112
- escaped_declaration = Regexp.escape(old_declaration)
113
-
114
- old_declaration_regex =
115
- %r{^#{FROM_REGEX}\s+(docker\.io/)?#{escaped_declaration}(?=\s|$)}
116
-
117
- previous_content.gsub(old_declaration_regex) do |old_dec|
118
- old_dec
119
- .gsub("@sha256:#{old_digest}", "@sha256:#{new_digest}")
120
- .gsub(":#{old_tag}", ":#{new_tag}")
121
- end
122
- end
123
-
124
- sig { params(source: T::Hash[Symbol, T.nilable(String)]).returns(T.nilable(String)) }
125
- def specified_with_tag?(source)
126
- source[:tag]
127
- end
128
-
129
- sig { params(source: T::Hash[Symbol, T.nilable(String)]).returns(T.nilable(String)) }
130
- def specified_with_digest?(source)
131
- source[:digest]
132
- end
133
-
134
- sig { params(file: Dependabot::DependencyFile).returns(T.nilable(T::Array[String])) }
135
- def new_tags(file)
136
- requirements(file)
137
- .map { |r| r.fetch(:source)[:tag] }
138
- end
139
-
140
- sig { params(file: Dependabot::DependencyFile).returns(T.nilable(T::Array[String])) }
141
- def old_tags(file)
142
- previous_requirements(file)
143
- &.map { |r| r.fetch(:source)[:tag] }
144
- end
145
-
146
- sig { params(source: T::Hash[Symbol, T.nilable(String)]).returns(T.nilable(String)) }
147
- def private_registry_url(source)
148
- source[:registry]
149
- end
150
-
151
- sig { params(file: Dependabot::DependencyFile).returns(T::Array[T::Hash[Symbol, T.nilable(String)]]) }
152
- def sources(file)
153
- requirements(file).map { |r| r.fetch(:source) }
154
- end
155
-
156
- sig { params(file: Dependabot::DependencyFile).returns(T.nilable(T::Array[T::Hash[Symbol, T.nilable(String)]])) }
157
- def previous_sources(file)
158
- previous_requirements(file)&.map { |r| r.fetch(:source) }
159
- end
160
-
161
- sig { params(file: Dependabot::DependencyFile).returns(T.nilable(String)) }
162
- def updated_yaml_content(file)
163
- updated_content = file.content
164
- updated_content = update_helm(file, updated_content) if Utils.likely_helm_chart?(file)
165
- updated_content = update_image(file, updated_content)
166
-
167
- raise "Expected content to change!" if updated_content == file.content
168
-
169
- updated_content
170
- end
171
-
172
- sig { params(file: Dependabot::DependencyFile, content: T.nilable(String)).returns(T.nilable(String)) }
173
- def update_helm(file, content)
174
- # TODO: this won't work if two images have the same tag version
175
- old_tags = old_helm_tags(file)
176
- return if old_tags.empty?
177
-
178
- modified_content = content
179
-
180
- old_tags.each do |old_tag|
181
- old_tag_regex = /^\s+(?:-\s)?(?:tag|version):\s+["']?#{old_tag}["']?(?=\s|$)/
182
- modified_content = modified_content&.gsub(old_tag_regex) do |old_img_tag|
183
- old_img_tag.gsub(old_tag.to_s, new_helm_tag(file).to_s)
184
- end
185
- end
186
- modified_content
187
- end
188
-
189
- sig { params(file: Dependabot::DependencyFile, content: T.nilable(String)).returns(T.nilable(String)) }
190
- def update_image(file, content)
191
- old_images = old_yaml_images(file)
192
- return if old_images.empty?
193
-
194
- modified_content = content
195
-
196
- old_images.each do |old_image|
197
- old_image_regex = /^\s*(?:-\s)?image:\s+#{old_image}(?=\s|$)/
198
- modified_content = modified_content&.gsub(old_image_regex) do |old_img|
199
- old_img.gsub(old_image.to_s, new_yaml_image(file).to_s)
200
- end
201
- end
202
- modified_content
203
- end
204
-
205
- sig { params(file: Dependabot::DependencyFile).returns(String) }
206
- def new_yaml_image(file)
207
- element = T.must(dependency).requirements.find { |r| r[:file] == file.name }
208
- prefix = element&.dig(:source, :registry) ? "#{element.fetch(:source)[:registry]}/" : ""
209
- digest = element&.dig(:source, :digest) ? "@sha256:#{element.fetch(:source)[:digest]}" : ""
210
- tag = element&.dig(:source, :tag) ? ":#{element.fetch(:source)[:tag]}" : ""
211
- "#{prefix}#{T.must(dependency).name}#{tag}#{digest}"
212
- end
213
-
214
- sig { params(file: Dependabot::DependencyFile).returns(T::Array[String]) }
215
- def old_yaml_images(file)
216
- T.must(previous_requirements(file)).map do |r|
217
- prefix = r.fetch(:source)[:registry] ? "#{r.fetch(:source)[:registry]}/" : ""
218
- digest = r.fetch(:source)[:digest] ? "@sha256:#{r.fetch(:source)[:digest]}" : ""
219
- tag = r.fetch(:source)[:tag] ? ":#{r.fetch(:source)[:tag]}" : ""
220
- "#{prefix}#{T.must(dependency).name}#{tag}#{digest}"
221
- end
222
- end
223
-
224
- sig { params(file: Dependabot::DependencyFile).returns(T::Array[String]) }
225
- def old_helm_tags(file)
226
- T.must(previous_requirements(file)).map do |r|
227
- tag = r.fetch(:source)[:tag] || ""
228
- digest = r.fetch(:source)[:digest] ? "@sha256:#{r.fetch(:source)[:digest]}" : ""
229
- "#{tag}#{digest}"
230
- end
20
+ [DOCKER_REGEXP, YAML_REGEXP]
231
21
  end
232
22
 
233
- sig { params(file: Dependabot::DependencyFile).returns(String) }
234
- def new_helm_tag(file)
235
- element = T.must(dependency).requirements.find { |r| r[:file] == file.name }
236
- tag = T.must(element).dig(:source, :tag) || ""
237
- digest = T.must(element).dig(:source, :digest) ? "@sha256:#{T.must(element).dig(:source, :digest)}" : ""
238
- "#{tag}#{digest}"
23
+ sig { override.returns(String) }
24
+ def file_type
25
+ "Dockerfile or Containerfile"
239
26
  end
240
27
 
241
- sig { params(file: Dependabot::DependencyFile).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
242
- def requirements(file)
243
- T.must(dependency).requirements
244
- .select { |r| r[:file] == file.name }
28
+ sig { override.returns(Regexp) }
29
+ def yaml_file_pattern
30
+ YAML_REGEXP
245
31
  end
246
32
 
247
- sig { params(file: Dependabot::DependencyFile).returns T.nilable(T::Array[T::Hash[Symbol, T.untyped]]) }
248
- def previous_requirements(file)
249
- T.must(dependency).previous_requirements
250
- &.select { |r| r[:file] == file.name }
33
+ sig { override.returns(Regexp) }
34
+ def container_image_regex
35
+ %r{^#{FROM_REGEX}\s+(docker\.io/)?}o
251
36
  end
252
37
  end
253
38
  end
@@ -11,7 +11,7 @@ require "dependabot/docker/tag"
11
11
  require "dependabot/docker/file_parser"
12
12
  require "dependabot/docker/version"
13
13
  require "dependabot/docker/requirement"
14
- require "dependabot/docker/utils/credentials_finder"
14
+ require "dependabot/shared/utils/credentials_finder"
15
15
 
16
16
  module Dependabot
17
17
  module Docker
@@ -261,6 +261,12 @@ module Dependabot
261
261
  rescue RestClient::ServerBrokeConnection,
262
262
  RestClient::TooManyRequests
263
263
  raise PrivateSourceBadResponse, registry_hostname
264
+ rescue JSON::ParserError => e
265
+ if e.message.include?("unexpected token")
266
+ raise DependencyFileNotResolvable, "Error while accessing docker image at #{registry_hostname}"
267
+ end
268
+
269
+ raise
264
270
  end
265
271
 
266
272
  sig { returns(T.nilable(String)) }
@@ -355,11 +361,11 @@ module Dependabot
355
361
  credentials_finder.credentials_for_registry(registry_hostname)
356
362
  end
357
363
 
358
- sig { returns(Dependabot::Docker::Utils::CredentialsFinder) }
364
+ sig { returns(Dependabot::Shared::Utils::CredentialsFinder) }
359
365
  def credentials_finder
360
366
  @credentials_finder ||= T.let(
361
- Utils::CredentialsFinder.new(credentials),
362
- T.nilable(Dependabot::Docker::Utils::CredentialsFinder)
367
+ Dependabot::Shared::Utils::CredentialsFinder.new(credentials),
368
+ T.nilable(Dependabot::Shared::Utils::CredentialsFinder)
363
369
  )
364
370
  end
365
371
 
@@ -0,0 +1,99 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/file_fetchers"
6
+ require "dependabot/file_fetchers/base"
7
+ require "dependabot/shared/utils/helpers"
8
+
9
+ module Dependabot
10
+ module Shared
11
+ class SharedFileFetcher < Dependabot::FileFetchers::Base
12
+ extend T::Sig
13
+ extend T::Helpers
14
+
15
+ abstract!
16
+
17
+ YAML_REGEXP = /^[^\.].*\.ya?ml$/i
18
+
19
+ sig { abstract.returns(Regexp) }
20
+ def self.filename_regex; end
21
+
22
+ sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
23
+ def self.required_files_in?(filenames)
24
+ filenames.any? { |f| f.match?(filename_regex) }
25
+ end
26
+
27
+ sig { override.returns(T::Array[DependencyFile]) }
28
+ def fetch_files
29
+ fetched_files = []
30
+ fetched_files + correctly_encoded_yamlfiles
31
+ end
32
+
33
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
34
+ def correctly_encoded_yamlfiles
35
+ candidate_files = yamlfiles.select { |f| f.content&.valid_encoding? }
36
+ candidate_files.select do |f|
37
+ if f.type == "file" && Utils.likely_helm_chart?(f)
38
+ true
39
+ else
40
+ # This doesn't handle multi-resource files, but it shouldn't matter, since the first resource
41
+ # in a multi-resource file had better be a valid k8s resource
42
+ content = YAML.safe_load(T.must(f.content), aliases: true)
43
+ likely_kubernetes_resource?(content)
44
+ end
45
+ rescue ::Psych::Exception
46
+ false
47
+ end
48
+ end
49
+
50
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
51
+ def incorrectly_encoded_yamlfiles
52
+ yamlfiles.reject { |f| f.content&.valid_encoding? }
53
+ end
54
+
55
+ sig do
56
+ params(
57
+ incorrectly_encoded_files: T::Array[Dependabot::DependencyFile]
58
+ ).returns(T.noreturn)
59
+ end
60
+ def raise_appropriate_error(
61
+ incorrectly_encoded_files = []
62
+ )
63
+ if incorrectly_encoded_files.none? && incorrectly_encoded_yamlfiles.none?
64
+ raise Dependabot::DependencyFileNotFound.new(
65
+ File.join(directory, "Dockerfile"),
66
+ "No Dockerfiles nor Kubernetes YAML found in #{directory}"
67
+ )
68
+ end
69
+
70
+ invalid_files = incorrectly_encoded_files.any? ? incorrectly_encoded_files : incorrectly_encoded_yamlfiles
71
+ raise Dependabot::DependencyFileNotParseable, T.must(invalid_files.first).path
72
+ end
73
+
74
+ sig { returns(T::Array[DependencyFile]) }
75
+ def yamlfiles
76
+ @yamlfiles ||= T.let(
77
+ repo_contents(raise_errors: false)
78
+ .select { |f| f.type == "file" && f.name.match?(YAML_REGEXP) }
79
+ .map { |f| fetch_file_from_host(f.name) },
80
+ T.nilable(T::Array[DependencyFile])
81
+ )
82
+ end
83
+
84
+ private
85
+
86
+ sig { params(resource: Object).returns(T.nilable(T::Boolean)) }
87
+ def likely_kubernetes_resource?(resource)
88
+ # Heuristic for being a Kubernetes resource. We could make this tighter but this probably works well.
89
+ resource.is_a?(::Hash) && resource.key?("apiVersion") && resource.key?("kind")
90
+ end
91
+
92
+ sig { abstract.returns(String) }
93
+ def default_file_name; end
94
+
95
+ sig { abstract.returns(String) }
96
+ def file_type; end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,80 @@
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
@@ -0,0 +1,261 @@
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
@@ -9,7 +9,7 @@ require "dependabot/credential"
9
9
  require "dependabot/errors"
10
10
 
11
11
  module Dependabot
12
- module Docker
12
+ module Shared
13
13
  module Utils
14
14
  class CredentialsFinder
15
15
  extend T::Sig
@@ -4,7 +4,7 @@
4
4
  require "sorbet-runtime"
5
5
 
6
6
  module Dependabot
7
- module Docker
7
+ module Shared
8
8
  module Utils
9
9
  HELM_REGEXP = /values[\-a-zA-Z_0-9]*\.ya?ml$/i
10
10
 
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.297.0
4
+ version: 0.297.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-13 00:00:00.000000000 Z
11
+ date: 2025-02-19 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.297.0
19
+ version: 0.297.1
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.297.0
26
+ version: 0.297.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -251,15 +251,18 @@ files:
251
251
  - lib/dependabot/docker/requirement.rb
252
252
  - lib/dependabot/docker/tag.rb
253
253
  - lib/dependabot/docker/update_checker.rb
254
- - lib/dependabot/docker/utils/credentials_finder.rb
255
- - lib/dependabot/docker/utils/helpers.rb
256
254
  - lib/dependabot/docker/version.rb
255
+ - lib/dependabot/shared/shared_file_fetcher.rb
256
+ - lib/dependabot/shared/shared_file_parser.rb
257
+ - lib/dependabot/shared/shared_file_updater.rb
258
+ - lib/dependabot/shared/utils/credentials_finder.rb
259
+ - lib/dependabot/shared/utils/helpers.rb
257
260
  homepage: https://github.com/dependabot/dependabot-core
258
261
  licenses:
259
262
  - MIT
260
263
  metadata:
261
264
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
262
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.297.0
265
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.297.1
263
266
  post_install_message:
264
267
  rdoc_options: []
265
268
  require_paths: