dependabot-maven 0.403.0 → 0.404.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/maven/file_parser/maven_dependency_parser.rb +4 -1
- data/lib/dependabot/maven/file_parser/transitive_override_finder.rb +208 -0
- data/lib/dependabot/maven/file_parser.rb +84 -2
- data/lib/dependabot/maven/file_updater/declaration_finder.rb +16 -5
- data/lib/dependabot/maven/file_updater.rb +10 -6
- data/lib/dependabot/maven/shared/shared_package_details_fetcher.rb +41 -3
- data/lib/dependabot/maven/update_checker/property_updater.rb +33 -6
- data/lib/dependabot/maven/update_checker/transitive_overrides.rb +87 -0
- data/lib/dependabot/maven/update_checker.rb +52 -4
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 882f62fae9fb3288a00474757b26ab2d3d69c4564b5c57fb1934f95e4064a901
|
|
4
|
+
data.tar.gz: cf2b50d9b0fcf12cb1215a37fbf51244a497c2225f57a0508e772004d8e3648b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0ecba86abf4fa974cdc7a096fac2b0df7385f90456502d283f92616f4ecd82f883a93896220f0da2b3df42033ef95b7a0014c972f834485e2444b1d79993f307
|
|
7
|
+
data.tar.gz: 84fd19d904f5785f35a9f676fb9aa9d46cabe7d1480828d510153be50786669db50af500ddfc5c8895996735d6008394839f803d590e6c22331d7d702c780fb5
|
|
@@ -199,6 +199,8 @@ module Dependabot
|
|
|
199
199
|
end
|
|
200
200
|
private_class_method :node_string
|
|
201
201
|
|
|
202
|
+
# The classifier names which XML entry this is (unclassified means the plain artifact), so
|
|
203
|
+
# it's never taken from the scan, which matches artifacts by name only.
|
|
202
204
|
sig do
|
|
203
205
|
params(
|
|
204
206
|
declared: Dependabot::DependencyRequirement,
|
|
@@ -207,7 +209,8 @@ module Dependabot
|
|
|
207
209
|
end
|
|
208
210
|
def self.merge_requirement_pair(declared, scanned)
|
|
209
211
|
declared_metadata = declared.metadata || {}
|
|
210
|
-
|
|
212
|
+
scanned_metadata = (scanned.metadata || {}).except(:classifier, "classifier")
|
|
213
|
+
metadata = scanned_metadata.merge(declared_metadata) { |_key, scan, xml| xml.nil? ? scan : xml }
|
|
211
214
|
|
|
212
215
|
Dependabot::DependencyRequirement.create(
|
|
213
216
|
requirement: declared.requirement,
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "nokogiri"
|
|
5
|
+
require "sorbet-runtime"
|
|
6
|
+
|
|
7
|
+
require "dependabot/dependency_file"
|
|
8
|
+
require "dependabot/maven/file_parser"
|
|
9
|
+
|
|
10
|
+
module Dependabot
|
|
11
|
+
module Maven
|
|
12
|
+
class FileParser
|
|
13
|
+
# Decides whether a `<dependencyManagement>` entry overrides a transitive version.
|
|
14
|
+
#
|
|
15
|
+
# An entry is an override when no POM in its local lineage (itself, its local
|
|
16
|
+
# parents and its local children) declares the artifact in a `<dependencies>`
|
|
17
|
+
# section. Parents count because their dependencies are inherited; sibling
|
|
18
|
+
# modules don't, as the entry doesn't manage their declarations. A local BOM,
|
|
19
|
+
# and every local POM inheriting from it, also manages the lineage of each
|
|
20
|
+
# local POM that imports it.
|
|
21
|
+
class TransitiveOverrideFinder
|
|
22
|
+
extend T::Sig
|
|
23
|
+
|
|
24
|
+
sig do
|
|
25
|
+
params(
|
|
26
|
+
pomfiles: T::Array[Dependabot::DependencyFile],
|
|
27
|
+
declared_keys_by_pom: T::Hash[String, T::Set[String]],
|
|
28
|
+
property_value_finder: PropertyValueFinder
|
|
29
|
+
).void
|
|
30
|
+
end
|
|
31
|
+
def initialize(pomfiles:, declared_keys_by_pom:, property_value_finder:)
|
|
32
|
+
@pomfiles = pomfiles
|
|
33
|
+
@declared_keys_by_pom = declared_keys_by_pom
|
|
34
|
+
@property_value_finder = property_value_finder
|
|
35
|
+
@lineages = T.let({}, T::Hash[String, T::Array[String]])
|
|
36
|
+
@documents = T.let({}, T::Hash[String, Nokogiri::XML::Document])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# `key` is the entry's groupId:artifactId:type:classifier management key.
|
|
40
|
+
sig { params(pom: Dependabot::DependencyFile, key: String).returns(T::Boolean) }
|
|
41
|
+
def override?(pom:, key:)
|
|
42
|
+
lineage(pom.name).none? { |pom_name| @declared_keys_by_pom.fetch(pom_name, Set.new).include?(key) }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
sig { params(pom_name: String).returns(T::Array[String]) }
|
|
48
|
+
def lineage(pom_name)
|
|
49
|
+
@lineages[pom_name] ||= begin
|
|
50
|
+
found = T.let([], T::Array[String])
|
|
51
|
+
visited = T.let([], T::Array[String])
|
|
52
|
+
queue = [pom_name]
|
|
53
|
+
while (current = queue.shift)
|
|
54
|
+
next if visited.include?(current)
|
|
55
|
+
|
|
56
|
+
visited << current
|
|
57
|
+
found.concat(inheritance_line(current)).uniq!
|
|
58
|
+
# Importing a BOM also imports what it inherits, so importers of its children count too.
|
|
59
|
+
([current] + descendants(current)).each do |bom|
|
|
60
|
+
queue.concat(local_importer_names.fetch(bom, []))
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
found
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
sig { params(pom_name: String).returns(T::Array[String]) }
|
|
68
|
+
def inheritance_line(pom_name)
|
|
69
|
+
ancestors(pom_name) + [pom_name] + descendants(pom_name)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Maps each local BOM file name to the file names of the local POMs that import it.
|
|
73
|
+
sig { returns(T::Hash[String, T::Array[String]]) }
|
|
74
|
+
def local_importer_names
|
|
75
|
+
@local_importer_names ||= T.let(
|
|
76
|
+
@pomfiles.each_with_object({}) do |pom, importers|
|
|
77
|
+
imported_coordinates(pom).each do |coordinates|
|
|
78
|
+
bom = coordinates_to_pom_name[coordinates]
|
|
79
|
+
next if bom.nil? || bom == pom.name
|
|
80
|
+
|
|
81
|
+
(importers[bom] ||= []) << pom.name
|
|
82
|
+
end
|
|
83
|
+
end,
|
|
84
|
+
T.nilable(T::Hash[String, T::Array[String]])
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
sig { params(pom: Dependabot::DependencyFile).returns(T::Array[String]) }
|
|
89
|
+
def imported_coordinates(pom)
|
|
90
|
+
document(pom).xpath("//dependencyManagement/dependencies/dependency").filter_map do |node|
|
|
91
|
+
import_coordinates(node, pom)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
sig { params(node: Nokogiri::XML::Element, pom: Dependabot::DependencyFile).returns(T.nilable(String)) }
|
|
96
|
+
def import_coordinates(node, pom)
|
|
97
|
+
return unless child_value(node, "scope", pom) == "import"
|
|
98
|
+
|
|
99
|
+
group_id = child_value(node, "groupId", pom)
|
|
100
|
+
artifact_id = child_value(node, "artifactId", pom)
|
|
101
|
+
return unless group_id && artifact_id
|
|
102
|
+
|
|
103
|
+
"#{group_id}:#{artifact_id}"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
sig do
|
|
107
|
+
params(node: Nokogiri::XML::Element, name: String, pom: Dependabot::DependencyFile).returns(T.nilable(String))
|
|
108
|
+
end
|
|
109
|
+
def child_value(node, name, pom)
|
|
110
|
+
resolved_text(node.at_xpath("./#{name}"), pom)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
sig { params(node: T.nilable(Nokogiri::XML::Node), pom: Dependabot::DependencyFile).returns(T.nilable(String)) }
|
|
114
|
+
def resolved_text(node, pom)
|
|
115
|
+
value = T.let(node&.content&.strip, T.nilable(String))
|
|
116
|
+
return value unless value&.match?(PROPERTY_REGEX)
|
|
117
|
+
|
|
118
|
+
value.gsub(PROPERTY_REGEX) do |placeholder|
|
|
119
|
+
resolved_property(T.must(Regexp.last_match)[:property].to_s, pom) || placeholder
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
sig { params(property_name: String, pom: Dependabot::DependencyFile).returns(T.nilable(String)) }
|
|
124
|
+
def resolved_property(property_name, pom)
|
|
125
|
+
details = @property_value_finder.property_details(property_name: property_name, callsite_pom: pom)
|
|
126
|
+
value = details&.fetch(:value)
|
|
127
|
+
value.is_a?(String) ? value : nil
|
|
128
|
+
rescue Dependabot::DependabotError
|
|
129
|
+
nil
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
sig { params(pom_name: String).returns(T::Array[String]) }
|
|
133
|
+
def ancestors(pom_name)
|
|
134
|
+
found = T.let([], T::Array[String])
|
|
135
|
+
current = T.let(local_parent_names[pom_name], T.nilable(String))
|
|
136
|
+
while current && !found.include?(current) && current != pom_name
|
|
137
|
+
found << current
|
|
138
|
+
current = local_parent_names[current]
|
|
139
|
+
end
|
|
140
|
+
found
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
sig { params(pom_name: String).returns(T::Array[String]) }
|
|
144
|
+
def descendants(pom_name)
|
|
145
|
+
found = T.let([], T::Array[String])
|
|
146
|
+
queue = [pom_name]
|
|
147
|
+
while (current = queue.shift)
|
|
148
|
+
local_parent_names.each do |child, parent|
|
|
149
|
+
next unless parent == current
|
|
150
|
+
next if child == pom_name || found.include?(child)
|
|
151
|
+
|
|
152
|
+
found << child
|
|
153
|
+
queue << child
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
found
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Maps each POM file name to the file name of its parent, when the parent is in the job.
|
|
160
|
+
sig { returns(T::Hash[String, String]) }
|
|
161
|
+
def local_parent_names
|
|
162
|
+
@local_parent_names ||= T.let(
|
|
163
|
+
@pomfiles.each_with_object({}) do |pom, parents|
|
|
164
|
+
coordinates = parent_coordinates(pom)
|
|
165
|
+
parent = coordinates && coordinates_to_pom_name[coordinates]
|
|
166
|
+
parents[pom.name] = parent if parent && parent != pom.name
|
|
167
|
+
end,
|
|
168
|
+
T.nilable(T::Hash[String, String])
|
|
169
|
+
)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
sig { returns(T::Hash[String, String]) }
|
|
173
|
+
def coordinates_to_pom_name
|
|
174
|
+
@coordinates_to_pom_name ||= T.let(
|
|
175
|
+
@pomfiles.each_with_object({}) do |pom, map|
|
|
176
|
+
doc = document(pom)
|
|
177
|
+
group_id = resolved_text(doc.at_xpath("/project/groupId") || doc.at_xpath("/project/parent/groupId"), pom)
|
|
178
|
+
artifact_id = resolved_text(doc.at_xpath("/project/artifactId"), pom)
|
|
179
|
+
next unless group_id && artifact_id
|
|
180
|
+
|
|
181
|
+
map["#{group_id}:#{artifact_id}"] ||= pom.name
|
|
182
|
+
end,
|
|
183
|
+
T.nilable(T::Hash[String, String])
|
|
184
|
+
)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
sig { params(pom: Dependabot::DependencyFile).returns(T.nilable(String)) }
|
|
188
|
+
def parent_coordinates(pom)
|
|
189
|
+
doc = document(pom)
|
|
190
|
+
group_id = doc.at_xpath("/project/parent/groupId")
|
|
191
|
+
artifact_id = doc.at_xpath("/project/parent/artifactId")
|
|
192
|
+
return unless group_id && artifact_id
|
|
193
|
+
|
|
194
|
+
"#{group_id.content.strip}:#{artifact_id.content.strip}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
sig { params(pom: Dependabot::DependencyFile).returns(Nokogiri::XML::Document) }
|
|
198
|
+
def document(pom)
|
|
199
|
+
@documents[pom.name] ||= begin
|
|
200
|
+
doc = Nokogiri::XML(pom.content)
|
|
201
|
+
doc.remove_namespaces!
|
|
202
|
+
doc
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
@@ -24,6 +24,7 @@ module Dependabot
|
|
|
24
24
|
require "dependabot/file_parsers/base/dependency_set"
|
|
25
25
|
require_relative "file_parser/maven_dependency_parser"
|
|
26
26
|
require_relative "file_parser/property_value_finder"
|
|
27
|
+
require_relative "file_parser/transitive_override_finder"
|
|
27
28
|
require_relative "file_parser/wrapper_mojo"
|
|
28
29
|
|
|
29
30
|
# The following "dependencies" are candidates for updating:
|
|
@@ -36,10 +37,18 @@ module Dependabot
|
|
|
36
37
|
"extensions > extension, " \
|
|
37
38
|
"annotationProcessorPaths > path"
|
|
38
39
|
PLUGIN_SELECTOR = "plugins > plugin"
|
|
39
|
-
|
|
40
|
+
# `<dependencies>` under these elements don't declare a project dependency.
|
|
41
|
+
NON_DECLARING_SECTIONS = %w(dependencyManagement plugin).freeze
|
|
42
|
+
EXTENSION_SELECTOR = "extensions > extension"
|
|
40
43
|
TARGET_SELECTOR = "target > locations > location[type='Maven'] > dependencies > dependency"
|
|
41
44
|
PLUGIN_ARTIFACT_ITEMS_SELECTOR = "plugins > plugin > executions > execution > " \
|
|
42
45
|
"configuration > artifactItems > artifactItem"
|
|
46
|
+
# Annotation processor paths and plugin artifact items can take their version
|
|
47
|
+
# from `<dependencyManagement>`, so they count as declarations too.
|
|
48
|
+
DECLARATION_SELECTOR = T.let(
|
|
49
|
+
"dependencies > dependency, annotationProcessorPaths > path, #{PLUGIN_ARTIFACT_ITEMS_SELECTOR}".freeze,
|
|
50
|
+
String
|
|
51
|
+
)
|
|
43
52
|
|
|
44
53
|
# Regex to get the property name from a declaration that uses a property
|
|
45
54
|
PROPERTY_REGEX = /\$\{(?<property>.*?)\}/
|
|
@@ -285,12 +294,85 @@ module Dependabot
|
|
|
285
294
|
source: nil,
|
|
286
295
|
metadata: {
|
|
287
296
|
packaging_type: packaging_type(pom, dependency_node),
|
|
288
|
-
classifier: dependency_classifier(dependency_node, pom)
|
|
297
|
+
classifier: dependency_classifier(dependency_node, pom),
|
|
298
|
+
transitive_override: transitive_override?(pom, dependency_node, is_plugin: is_plugin) || nil
|
|
289
299
|
}.merge(property_details).compact
|
|
290
300
|
}]
|
|
291
301
|
)
|
|
292
302
|
end
|
|
293
303
|
|
|
304
|
+
# A `<dependencyManagement>` entry (not a BOM import) for an artifact that nothing in its
|
|
305
|
+
# POM lineage declares only sets a transitive version. Tagged with the experiment on, so
|
|
306
|
+
# the update checker can leave it alone outside security updates.
|
|
307
|
+
sig do
|
|
308
|
+
params(
|
|
309
|
+
pom: Dependabot::DependencyFile,
|
|
310
|
+
dependency_node: Nokogiri::XML::Element,
|
|
311
|
+
is_plugin: T::Boolean
|
|
312
|
+
).returns(T::Boolean)
|
|
313
|
+
end
|
|
314
|
+
def transitive_override?(pom, dependency_node, is_plugin:)
|
|
315
|
+
return false if is_plugin
|
|
316
|
+
return false unless Dependabot::Experiments.enabled?(:maven_transitive_dependencies)
|
|
317
|
+
return false unless dependency_management_node?(dependency_node)
|
|
318
|
+
return false if dependency_scope(pom, dependency_node) == "import"
|
|
319
|
+
|
|
320
|
+
key = management_key(dependency_node, pom)
|
|
321
|
+
!key.nil? && transitive_override_finder.override?(pom: pom, key: key)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
sig { params(node: Nokogiri::XML::Node).returns(T::Boolean) }
|
|
325
|
+
def dependency_management_node?(node)
|
|
326
|
+
node.name == "dependency" && node.ancestors.any? { |a| a.name == "dependencyManagement" }
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
sig { returns(TransitiveOverrideFinder) }
|
|
330
|
+
def transitive_override_finder
|
|
331
|
+
@transitive_override_finder ||= T.let(
|
|
332
|
+
TransitiveOverrideFinder.new(
|
|
333
|
+
pomfiles: pomfiles,
|
|
334
|
+
declared_keys_by_pom: declared_keys_by_pom,
|
|
335
|
+
property_value_finder: property_value_finder
|
|
336
|
+
),
|
|
337
|
+
T.nilable(TransitiveOverrideFinder)
|
|
338
|
+
)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Management keys of the artifacts each POM declares in a `<dependencies>`
|
|
342
|
+
# section, as an annotation processor path or as a plugin artifact item,
|
|
343
|
+
# excluding `<dependencyManagement>` entries and plugin dependencies.
|
|
344
|
+
sig { returns(T::Hash[String, T::Set[String]]) }
|
|
345
|
+
def declared_keys_by_pom
|
|
346
|
+
pomfiles.to_h do |pom|
|
|
347
|
+
doc = Nokogiri::XML(pom.content)
|
|
348
|
+
doc.remove_namespaces!
|
|
349
|
+
keys = doc.css(DECLARATION_SELECTOR).each_with_object(Set.new) do |node, set|
|
|
350
|
+
next if node.name == "dependency" && node.ancestors.any? { |a| NON_DECLARING_SECTIONS.include?(a.name) }
|
|
351
|
+
|
|
352
|
+
key = declared_key(node, pom)
|
|
353
|
+
set << key if key
|
|
354
|
+
end
|
|
355
|
+
[pom.name, keys]
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
sig { params(node: Nokogiri::XML::Element, pom: Dependabot::DependencyFile).returns(T.nilable(String)) }
|
|
360
|
+
def declared_key(node, pom)
|
|
361
|
+
management_key(node, pom)
|
|
362
|
+
rescue DependencyFileNotEvaluatable
|
|
363
|
+
nil
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
# Maven matches a declaration to a `<dependencyManagement>` entry by groupId, artifactId,
|
|
367
|
+
# type and classifier, so a `test-jar` or classified declaration doesn't use the plain jar entry.
|
|
368
|
+
sig { params(node: Nokogiri::XML::Element, pom: Dependabot::DependencyFile).returns(T.nilable(String)) }
|
|
369
|
+
def management_key(node, pom)
|
|
370
|
+
name = dependency_name(node, pom)
|
|
371
|
+
return unless name
|
|
372
|
+
|
|
373
|
+
[name, packaging_type(pom, node), dependency_classifier(node, pom).to_s].join(":")
|
|
374
|
+
end
|
|
375
|
+
|
|
294
376
|
sig do
|
|
295
377
|
params(
|
|
296
378
|
dependency_node: Nokogiri::XML::Element,
|
|
@@ -20,6 +20,17 @@ module Dependabot
|
|
|
20
20
|
<path>.*?</path>|
|
|
21
21
|
<artifactItem>.*?</artifactItem>
|
|
22
22
|
}mx
|
|
23
|
+
|
|
24
|
+
# The parts of a requirement the XML match depends on. Scanned-only requirements have no XML
|
|
25
|
+
# entry and are pinned per `pom_file`, so they're kept whole.
|
|
26
|
+
sig { params(requirement: Dependabot::DependencyRequirement).returns(Object) }
|
|
27
|
+
def self.match_key(requirement)
|
|
28
|
+
return requirement unless requirement.file
|
|
29
|
+
|
|
30
|
+
[requirement.file, requirement.requirement_string, requirement.groups] +
|
|
31
|
+
%w(packaging_type classifier property_name property_source).map { |key| requirement.metadata_string(key) }
|
|
32
|
+
end
|
|
33
|
+
|
|
23
34
|
sig { returns(Dependabot::Dependency) }
|
|
24
35
|
attr_reader :dependency
|
|
25
36
|
|
|
@@ -137,13 +148,13 @@ module Dependabot
|
|
|
137
148
|
type == packaging_type(node)
|
|
138
149
|
end
|
|
139
150
|
|
|
151
|
+
# A classifier names a distinct artifact, so an entry only matches the requirement parsed from
|
|
152
|
+
# an entry with the same classifier (none for the plain artifact).
|
|
140
153
|
sig { params(node: Nokogiri::XML::Document).returns(T::Boolean) }
|
|
141
154
|
def classifier_matches?(node)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
classifier
|
|
145
|
-
dep_classifier = dependency.requirements.first&.metadata_string("classifier")
|
|
146
|
-
classifier == dep_classifier
|
|
155
|
+
classifier_node = node.at_xpath("./*/classifier")
|
|
156
|
+
classifier = classifier_node && evaluated_value(classifier_node.content.strip)
|
|
157
|
+
classifier == declaring_requirement.metadata_string("classifier")
|
|
147
158
|
end
|
|
148
159
|
|
|
149
160
|
sig { params(node: Nokogiri::XML::Document).returns(T::Boolean) }
|
|
@@ -134,13 +134,8 @@ module Dependabot
|
|
|
134
134
|
def update_files_for_dependency(original_files:, dependency:)
|
|
135
135
|
files = original_files.dup
|
|
136
136
|
|
|
137
|
-
# The UpdateChecker ensures the order of requirements is preserved
|
|
138
|
-
# when updating, so we can zip them together in new/old pairs.
|
|
139
|
-
reqs = dependency.requirements.zip(dependency.previous_requirements.to_a)
|
|
140
|
-
.reject { |new_req, old_req| new_req == old_req }
|
|
141
|
-
|
|
142
137
|
# Loop through each changed requirement and update the files
|
|
143
|
-
|
|
138
|
+
changed_requirement_pairs(dependency).each do |new_req, old_req|
|
|
144
139
|
raise "Bad req match" unless new_req.file == T.must(old_req).file
|
|
145
140
|
next if new_req.requirement == T.must(old_req).requirement
|
|
146
141
|
|
|
@@ -161,6 +156,15 @@ module Dependabot
|
|
|
161
156
|
end
|
|
162
157
|
# rubocop:enable Metrics/AbcSize
|
|
163
158
|
|
|
159
|
+
# Requirement order is preserved, so new/old pairs zip together. One rewrite changes every XML
|
|
160
|
+
# entry that matches it, so pairs that differ only in other metadata (the override tag, or what
|
|
161
|
+
# the dependency tree scan merged into one of them) collapse into one.
|
|
162
|
+
sig { params(dependency: Dependency).returns(T::Array[[DependencyRequirement, T.nilable(DependencyRequirement)]]) }
|
|
163
|
+
def changed_requirement_pairs(dependency)
|
|
164
|
+
dependency.requirements.zip(dependency.previous_requirements.to_a).reject { |new, old| new == old }
|
|
165
|
+
.uniq { |pair| pair.map { |req| req && DeclarationFinder.match_key(req) } }
|
|
166
|
+
end
|
|
167
|
+
|
|
164
168
|
sig do
|
|
165
169
|
params(
|
|
166
170
|
pomfiles: T::Array[Dependabot::DependencyFile],
|
|
@@ -112,6 +112,7 @@ module Dependabot
|
|
|
112
112
|
headers: headers
|
|
113
113
|
)
|
|
114
114
|
check_response(response, url)
|
|
115
|
+
check_unavailable_response(response, url)
|
|
115
116
|
return unless response.status < 400
|
|
116
117
|
|
|
117
118
|
Nokogiri::XML(response.body)
|
|
@@ -223,6 +224,23 @@ module Dependabot
|
|
|
223
224
|
forbidden_urls << repository_url
|
|
224
225
|
end
|
|
225
226
|
|
|
227
|
+
# A rate limit or server error means the repository could not be read, not
|
|
228
|
+
# that it has no versions. Raises for the central repo; for other repos the
|
|
229
|
+
# URL is recorded so we can raise if no repository returned any versions.
|
|
230
|
+
sig { params(response: Excon::Response, repository_url: String).void }
|
|
231
|
+
def check_unavailable_response(response, repository_url)
|
|
232
|
+
return unless response.status == 429 || response.status >= 500
|
|
233
|
+
|
|
234
|
+
if base_repository_urls.include?(strip_trailing_slashes(repository_url))
|
|
235
|
+
raise RegistryError.new(
|
|
236
|
+
response.status,
|
|
237
|
+
"RegistryError: #{response.status} response status from #{repository_url}"
|
|
238
|
+
)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
unavailable_urls << repository_url unless unavailable_urls.include?(repository_url)
|
|
242
|
+
end
|
|
243
|
+
|
|
226
244
|
# Raises RegistryError for failures hitting the central repo.
|
|
227
245
|
sig do
|
|
228
246
|
params(
|
|
@@ -289,6 +307,7 @@ module Dependabot
|
|
|
289
307
|
sig { returns(T::Array[VersionDetails]) }
|
|
290
308
|
def versions_details_from_xml
|
|
291
309
|
forbidden_urls.clear
|
|
310
|
+
unavailable_urls.clear
|
|
292
311
|
version_details = repositories.flat_map do |repository_details|
|
|
293
312
|
url = repository_url(repository_details)
|
|
294
313
|
xml = dependency_metadata(repository_details)
|
|
@@ -298,6 +317,7 @@ module Dependabot
|
|
|
298
317
|
end
|
|
299
318
|
|
|
300
319
|
raise PrivateSourceAuthenticationFailure, forbidden_urls.first if version_details.none? && forbidden_urls.any?
|
|
320
|
+
raise PrivateSourceBadResponse, unavailable_urls.first if version_details.none? && unavailable_urls.any?
|
|
301
321
|
|
|
302
322
|
version_details
|
|
303
323
|
end
|
|
@@ -390,9 +410,9 @@ module Dependabot
|
|
|
390
410
|
end
|
|
391
411
|
|
|
392
412
|
# Both HTTP and HTTPS variants of the central repo URL, for comparison.
|
|
393
|
-
sig { returns(T::Array[String]) }
|
|
394
|
-
def central_repo_urls
|
|
395
|
-
central_url_without_protocol =
|
|
413
|
+
sig { params(url: String).returns(T::Array[String]) }
|
|
414
|
+
def central_repo_urls(url = central_repo_url)
|
|
415
|
+
central_url_without_protocol = url.gsub(%r{^.*://}, "")
|
|
396
416
|
%w(http:// https://).map { |p| p + central_url_without_protocol }
|
|
397
417
|
end
|
|
398
418
|
|
|
@@ -401,6 +421,24 @@ module Dependabot
|
|
|
401
421
|
@forbidden_urls ||= T.let([], T.nilable(T::Array[String]))
|
|
402
422
|
end
|
|
403
423
|
|
|
424
|
+
# Maven Central and any registry that replaces it. Central is kept even when
|
|
425
|
+
# replaced, since a POM may still list it explicitly.
|
|
426
|
+
sig { returns(T::Array[String]) }
|
|
427
|
+
def base_repository_urls
|
|
428
|
+
replaces_base = credentials.filter_map { |c| c[URL_KEY] if c["type"] == REPOSITORY_TYPE && c.replaces_base? }
|
|
429
|
+
(central_repo_urls(DEFAULT_CENTRAL_REPO_URL) + replaces_base).map { |url| strip_trailing_slashes(url) }
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
sig { params(url: String).returns(String) }
|
|
433
|
+
def strip_trailing_slashes(url)
|
|
434
|
+
url.dup.tap { |u| u.delete_suffix!("/") while u.end_with?("/") }
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
sig { returns(T::Array[String]) }
|
|
438
|
+
def unavailable_urls
|
|
439
|
+
@unavailable_urls ||= T.let([], T.nilable(T::Array[String]))
|
|
440
|
+
end
|
|
441
|
+
|
|
404
442
|
# -- Auth --
|
|
405
443
|
|
|
406
444
|
sig { params(maven_repo_url: String).returns(T::Hash[String, String]) }
|
|
@@ -14,6 +14,7 @@ module Dependabot
|
|
|
14
14
|
extend T::Sig
|
|
15
15
|
|
|
16
16
|
require_relative "requirements_updater"
|
|
17
|
+
require_relative "transitive_overrides"
|
|
17
18
|
require_relative "version_finder"
|
|
18
19
|
|
|
19
20
|
sig do
|
|
@@ -23,7 +24,8 @@ module Dependabot
|
|
|
23
24
|
credentials: T::Array[Dependabot::Credential],
|
|
24
25
|
ignored_versions: T::Array[String],
|
|
25
26
|
target_version_details: T.nilable(UpdateChecker::VersionDetails),
|
|
26
|
-
update_cooldown: T.nilable(Dependabot::Package::ReleaseCooldownOptions)
|
|
27
|
+
update_cooldown: T.nilable(Dependabot::Package::ReleaseCooldownOptions),
|
|
28
|
+
security_update: T::Boolean
|
|
27
29
|
).void
|
|
28
30
|
end
|
|
29
31
|
def initialize(
|
|
@@ -32,7 +34,8 @@ module Dependabot
|
|
|
32
34
|
credentials:,
|
|
33
35
|
ignored_versions:,
|
|
34
36
|
target_version_details:,
|
|
35
|
-
update_cooldown: nil
|
|
37
|
+
update_cooldown: nil,
|
|
38
|
+
security_update: false
|
|
36
39
|
)
|
|
37
40
|
@dependency = dependency
|
|
38
41
|
@dependency_files = dependency_files
|
|
@@ -43,6 +46,7 @@ module Dependabot
|
|
|
43
46
|
@target_version = T.let(target_version, T.nilable(Dependabot::Maven::Version))
|
|
44
47
|
@source_url = T.let(target_version_details&.fetch(:source_url), T.nilable(String))
|
|
45
48
|
@update_cooldown = update_cooldown
|
|
49
|
+
@security_update = security_update
|
|
46
50
|
@property_value_finder = T.let(nil, T.nilable(Dependabot::Maven::FileParser::PropertyValueFinder))
|
|
47
51
|
end
|
|
48
52
|
|
|
@@ -123,13 +127,21 @@ module Dependabot
|
|
|
123
127
|
sig { returns(T::Array[Dependabot::Dependency]) }
|
|
124
128
|
def dependencies_using_property
|
|
125
129
|
@dependencies_using_property ||= T.let(
|
|
130
|
+
parsed_dependencies.select do |dep|
|
|
131
|
+
dep.requirements.any? { |requirement| uses_property?(requirement) }
|
|
132
|
+
end,
|
|
133
|
+
T.nilable(T::Array[Dependabot::Dependency])
|
|
134
|
+
)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
|
138
|
+
def parsed_dependencies
|
|
139
|
+
@parsed_dependencies ||= T.let(
|
|
126
140
|
Maven::FileParser.new(
|
|
127
141
|
dependency_files: dependency_files,
|
|
128
142
|
source: nil,
|
|
129
143
|
options: { skip_dependency_tree: true }
|
|
130
|
-
).parse
|
|
131
|
-
dep.requirements.any? { |requirement| uses_property?(requirement) }
|
|
132
|
-
end,
|
|
144
|
+
).parse,
|
|
133
145
|
T.nilable(T::Array[Dependabot::Dependency])
|
|
134
146
|
)
|
|
135
147
|
end
|
|
@@ -156,7 +168,9 @@ module Dependabot
|
|
|
156
168
|
|
|
157
169
|
sig { returns(Dependabot::DependencyRequirement) }
|
|
158
170
|
def property_requirement
|
|
159
|
-
property_requirements =
|
|
171
|
+
property_requirements = TransitiveOverrides.raisable_property_requirements(
|
|
172
|
+
dependency.requirements, security_update: @security_update
|
|
173
|
+
) { parsed_dependencies }
|
|
160
174
|
matching_requirement = property_requirements.find do |requirement|
|
|
161
175
|
normalized_requirement_version(requirement) == dependency.version
|
|
162
176
|
end
|
|
@@ -255,12 +269,25 @@ module Dependabot
|
|
|
255
269
|
source_url: source_url,
|
|
256
270
|
properties_to_update: [property_name]
|
|
257
271
|
).updated_requirements.map.with_index do |requirement, index|
|
|
272
|
+
next dep.requirements.fetch(index) if keep_unchanged?(dep, dep.requirements.fetch(index))
|
|
258
273
|
next requirement unless requirement.metadata_string("property_name")
|
|
259
274
|
|
|
260
275
|
uses_property?(requirement) ? requirement : dep.requirements.fetch(index)
|
|
261
276
|
end
|
|
262
277
|
end
|
|
263
278
|
|
|
279
|
+
# A literal transitive override isn't tied to the shared property, so the property update leaves
|
|
280
|
+
# it, and any declaration whose rewrite would also hit it, alone. Only a security update raises
|
|
281
|
+
# it, and only for the vulnerable dependency.
|
|
282
|
+
sig { params(dep: Dependabot::Dependency, requirement: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
283
|
+
def keep_unchanged?(dep, requirement)
|
|
284
|
+
return false if @security_update && dep.name == dependency.name
|
|
285
|
+
return false if requirement.metadata_string("property_name")
|
|
286
|
+
|
|
287
|
+
TransitiveOverrides.override?(requirement) ||
|
|
288
|
+
TransitiveOverrides.rewrites_an_override?(requirement, dep.requirements)
|
|
289
|
+
end
|
|
290
|
+
|
|
264
291
|
sig { params(dep: Dependabot::Dependency).returns(T::Boolean) }
|
|
265
292
|
def writable_requirements?(dep)
|
|
266
293
|
updated = updated_requirements(dep)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# typed: strong
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "sorbet-runtime"
|
|
5
|
+
require "dependabot/dependency_requirement"
|
|
6
|
+
require "dependabot/maven/update_checker"
|
|
7
|
+
|
|
8
|
+
module Dependabot
|
|
9
|
+
module Maven
|
|
10
|
+
class UpdateChecker
|
|
11
|
+
# Rules for keeping transitive overrides (tagged by the file parser) out of version updates.
|
|
12
|
+
module TransitiveOverrides
|
|
13
|
+
extend T::Sig
|
|
14
|
+
|
|
15
|
+
sig { params(requirement: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
16
|
+
def self.override?(requirement)
|
|
17
|
+
requirement.metadata_boolean("transitive_override") == true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The file updater rewrites every XML entry that matches a declaration's file, literal version,
|
|
21
|
+
# packaging type, scope (ignored for plugins) and classifier. A declaration that matches a kept
|
|
22
|
+
# override that way can't change on its own, so it's held too.
|
|
23
|
+
sig do
|
|
24
|
+
params(
|
|
25
|
+
requirement: Dependabot::DependencyRequirement,
|
|
26
|
+
requirements: T::Array[Dependabot::DependencyRequirement]
|
|
27
|
+
).returns(T::Boolean)
|
|
28
|
+
end
|
|
29
|
+
def self.rewrites_an_override?(requirement, requirements)
|
|
30
|
+
return false if override?(requirement) || property?(requirement)
|
|
31
|
+
|
|
32
|
+
requirements.any? { |other| override?(other) && rewrites?(requirement, other) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Outside a security update an override follows a version property only when a declaration
|
|
36
|
+
# also uses it. A property only overrides use is never raised, so it can't drive an update.
|
|
37
|
+
sig do
|
|
38
|
+
params(
|
|
39
|
+
requirements: T::Array[Dependabot::DependencyRequirement],
|
|
40
|
+
security_update: T::Boolean,
|
|
41
|
+
dependencies: T.proc.returns(T::Array[Dependabot::Dependency])
|
|
42
|
+
).returns(T::Array[Dependabot::DependencyRequirement])
|
|
43
|
+
end
|
|
44
|
+
def self.raisable_property_requirements(requirements, security_update:, &dependencies)
|
|
45
|
+
with_property = requirements.select { |req| property?(req) }
|
|
46
|
+
return with_property if security_update || with_property.none? { |req| override?(req) }
|
|
47
|
+
|
|
48
|
+
declared = (requirements + yield.flat_map(&:requirements)).reject { |req| override?(req) }
|
|
49
|
+
with_property.select do |req|
|
|
50
|
+
!override?(req) || declared.any? { |other| same_property?(other, req) }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
sig do
|
|
55
|
+
params(
|
|
56
|
+
declaration: Dependabot::DependencyRequirement,
|
|
57
|
+
override: Dependabot::DependencyRequirement
|
|
58
|
+
).returns(T::Boolean)
|
|
59
|
+
end
|
|
60
|
+
def self.rewrites?(declaration, override)
|
|
61
|
+
return false if property?(override)
|
|
62
|
+
return false unless declaration.file == override.file
|
|
63
|
+
return false unless declaration.requirement_string == override.requirement_string
|
|
64
|
+
return false unless %w(packaging_type classifier).all? do |key|
|
|
65
|
+
declaration.metadata_string(key) == override.metadata_string(key)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
declaration.groups == ["plugin"] || declaration.groups == override.groups
|
|
69
|
+
end
|
|
70
|
+
private_class_method :rewrites?
|
|
71
|
+
|
|
72
|
+
sig { params(one: Dependabot::DependencyRequirement, other: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
73
|
+
def self.same_property?(one, other)
|
|
74
|
+
one.metadata_string("property_name") == other.metadata_string("property_name") &&
|
|
75
|
+
one.metadata_string("property_source") == other.metadata_string("property_source")
|
|
76
|
+
end
|
|
77
|
+
private_class_method :same_property?
|
|
78
|
+
|
|
79
|
+
sig { params(requirement: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
80
|
+
def self.property?(requirement)
|
|
81
|
+
!requirement.metadata_string("property_name").nil?
|
|
82
|
+
end
|
|
83
|
+
private_class_method :property?
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -11,6 +11,7 @@ module Dependabot
|
|
|
11
11
|
require_relative "update_checker/requirements_updater"
|
|
12
12
|
require_relative "update_checker/version_finder"
|
|
13
13
|
require_relative "update_checker/property_updater"
|
|
14
|
+
require_relative "update_checker/transitive_overrides"
|
|
14
15
|
|
|
15
16
|
VersionDetails = T.type_alias do
|
|
16
17
|
{
|
|
@@ -57,6 +58,16 @@ module Dependabot
|
|
|
57
58
|
@all_property_based_dependencies = T.let(nil, T.nilable(T::Array[Dependabot::Dependency]))
|
|
58
59
|
end
|
|
59
60
|
|
|
61
|
+
# Transitive overrides hold a version on purpose (often a security fix), so only a
|
|
62
|
+
# vulnerable one is updated. A dependency set only by overrides is "up to date" otherwise,
|
|
63
|
+
# which keeps version, grouped and refresh jobs away from it.
|
|
64
|
+
sig { override.returns(T::Boolean) }
|
|
65
|
+
def up_to_date?
|
|
66
|
+
return true if no_updatable_declarations? && !vulnerable?
|
|
67
|
+
|
|
68
|
+
super
|
|
69
|
+
end
|
|
70
|
+
|
|
60
71
|
sig { override.returns(T.nilable(Dependabot::Version)) }
|
|
61
72
|
def latest_version
|
|
62
73
|
version = latest_version_details&.fetch(:version)
|
|
@@ -155,12 +166,47 @@ module Dependabot
|
|
|
155
166
|
declarations_using_a_property
|
|
156
167
|
.filter_map { |req| req.metadata_string("property_name") }
|
|
157
168
|
|
|
158
|
-
RequirementsUpdater.new(
|
|
169
|
+
updated = RequirementsUpdater.new(
|
|
159
170
|
requirements: dependency.requirements,
|
|
160
171
|
latest_version: version&.to_s,
|
|
161
172
|
source_url: preferred_version_details&.fetch(:source_url),
|
|
162
173
|
properties_to_update: property_names
|
|
163
174
|
).updated_requirements
|
|
175
|
+
return updated if vulnerable? || dependency.requirements.none? { |req| transitive_override?(req) }
|
|
176
|
+
|
|
177
|
+
# Outside a security update only declarations change, plus overrides sharing a property being
|
|
178
|
+
# raised (they move with it anyway, and must change so their version suffix is normalized).
|
|
179
|
+
# Other overrides keep their version, and scanned requirements aren't pinned underneath them.
|
|
180
|
+
dependency.requirements.zip(updated).map do |original, updated_req|
|
|
181
|
+
updatable_declaration?(original) || follows_raised_property?(original) ? T.must(updated_req) : original
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
sig { params(requirement: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
186
|
+
def follows_raised_property?(requirement)
|
|
187
|
+
transitive_override?(requirement) && declarations_using_a_property.include?(requirement)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
sig { returns(T::Boolean) }
|
|
191
|
+
def no_updatable_declarations?
|
|
192
|
+
declared = dependency.requirements.select(&:file)
|
|
193
|
+
declared.any? && declared.none? { |req| updatable_declaration?(req) }
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
sig { params(requirement: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
197
|
+
def updatable_declaration?(requirement)
|
|
198
|
+
declared_requirement?(requirement) &&
|
|
199
|
+
!TransitiveOverrides.rewrites_an_override?(requirement, dependency.requirements)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
sig { params(requirement: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
203
|
+
def transitive_override?(requirement)
|
|
204
|
+
TransitiveOverrides.override?(requirement)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
sig { params(requirement: Dependabot::DependencyRequirement).returns(T::Boolean) }
|
|
208
|
+
def declared_requirement?(requirement)
|
|
209
|
+
!requirement.file.nil? && !transitive_override?(requirement)
|
|
164
210
|
end
|
|
165
211
|
|
|
166
212
|
sig { override.returns(T::Boolean) }
|
|
@@ -230,7 +276,8 @@ module Dependabot
|
|
|
230
276
|
target_version_details: latest_version_details,
|
|
231
277
|
credentials: credentials,
|
|
232
278
|
ignored_versions: ignored_versions,
|
|
233
|
-
update_cooldown: update_cooldown
|
|
279
|
+
update_cooldown: update_cooldown,
|
|
280
|
+
security_update: vulnerable?
|
|
234
281
|
)
|
|
235
282
|
end
|
|
236
283
|
|
|
@@ -262,8 +309,9 @@ module Dependabot
|
|
|
262
309
|
sig { returns(T::Array[Dependabot::DependencyRequirement]) }
|
|
263
310
|
def declarations_using_a_property
|
|
264
311
|
@declarations_using_a_property ||=
|
|
265
|
-
dependency.requirements
|
|
266
|
-
|
|
312
|
+
TransitiveOverrides.raisable_property_requirements(dependency.requirements, security_update: vulnerable?) do
|
|
313
|
+
all_property_based_dependencies
|
|
314
|
+
end
|
|
267
315
|
end
|
|
268
316
|
|
|
269
317
|
sig { returns(T::Array[Dependabot::Dependency]) }
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-maven
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.404.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.404.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.404.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: rexml
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -263,6 +263,7 @@ files:
|
|
|
263
263
|
- lib/dependabot/maven/file_parser/pom_fetcher.rb
|
|
264
264
|
- lib/dependabot/maven/file_parser/property_value_finder.rb
|
|
265
265
|
- lib/dependabot/maven/file_parser/repositories_finder.rb
|
|
266
|
+
- lib/dependabot/maven/file_parser/transitive_override_finder.rb
|
|
266
267
|
- lib/dependabot/maven/file_parser/wrapper_mojo.rb
|
|
267
268
|
- lib/dependabot/maven/file_updater.rb
|
|
268
269
|
- lib/dependabot/maven/file_updater/declaration_finder.rb
|
|
@@ -289,6 +290,7 @@ files:
|
|
|
289
290
|
- lib/dependabot/maven/update_checker.rb
|
|
290
291
|
- lib/dependabot/maven/update_checker/property_updater.rb
|
|
291
292
|
- lib/dependabot/maven/update_checker/requirements_updater.rb
|
|
293
|
+
- lib/dependabot/maven/update_checker/transitive_overrides.rb
|
|
292
294
|
- lib/dependabot/maven/update_checker/version_finder.rb
|
|
293
295
|
- lib/dependabot/maven/utils/auth_headers_finder.rb
|
|
294
296
|
- lib/dependabot/maven/version.rb
|
|
@@ -298,7 +300,7 @@ licenses:
|
|
|
298
300
|
- MIT
|
|
299
301
|
metadata:
|
|
300
302
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
301
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
303
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.404.0
|
|
302
304
|
rdoc_options: []
|
|
303
305
|
require_paths:
|
|
304
306
|
- lib
|