dependabot-gradle 0.312.0 → 0.313.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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4226dd4d48a3901cf8ed98892067b901e1a9ab048e72596d939e9b7d4d416226
|
4
|
+
data.tar.gz: 102eabde5d58e0f40278382bfff3197cf31476ff37b53295be697033992fd1fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5de5020a56e21ceb8b6b6bbca4c755abea5ccabf012a82bbe22fd4bfb3586f4246b2262a5bae43869b21b7271f0c26d44130fbc49f69ae5d7039bf616494da0
|
7
|
+
data.tar.gz: ac6abd8571f5457ee58d7474eb4e79cf414a11ff9ee94adb57c8e8e27b610f792e6c4d9f21344d15129b8835b8c1dfb8d02fa056a19a07b531f53b9917463677
|
@@ -0,0 +1,368 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "nokogiri"
|
5
|
+
require "dependabot/shared_helpers"
|
6
|
+
require "dependabot/update_checkers/version_filters"
|
7
|
+
require "dependabot/gradle/file_parser/repositories_finder"
|
8
|
+
require "dependabot/gradle/update_checker"
|
9
|
+
require "dependabot/gradle/version"
|
10
|
+
require "dependabot/gradle/requirement"
|
11
|
+
require "dependabot/maven/utils/auth_headers_finder"
|
12
|
+
require "sorbet-runtime"
|
13
|
+
require "dependabot/gradle/metadata_finder"
|
14
|
+
|
15
|
+
module Dependabot
|
16
|
+
module Gradle
|
17
|
+
module Package
|
18
|
+
class PackageDetailsFetcher
|
19
|
+
extend T::Sig
|
20
|
+
|
21
|
+
CENTRAL_REPO_URL = "https://repo.maven.apache.org/maven2"
|
22
|
+
KOTLIN_PLUGIN_REPO_PREFIX = "org.jetbrains.kotlin"
|
23
|
+
TYPE_SUFFICES = %w(jre android java native_mt agp).freeze
|
24
|
+
|
25
|
+
sig do
|
26
|
+
params(
|
27
|
+
dependency: Dependabot::Dependency,
|
28
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
29
|
+
credentials: T::Array[Dependabot::Credential],
|
30
|
+
forbidden_urls: T.nilable(T::Array[String])
|
31
|
+
).void
|
32
|
+
end
|
33
|
+
def initialize(dependency:, dependency_files:, credentials:, forbidden_urls:)
|
34
|
+
@dependency = dependency
|
35
|
+
@dependency_files = dependency_files
|
36
|
+
@credentials = credentials
|
37
|
+
@forbidden_urls = forbidden_urls
|
38
|
+
|
39
|
+
@repositories = T.let(nil, T.nilable(T::Array[T::Hash[String, T.untyped]]))
|
40
|
+
@google_version_details = T.let(nil, T.nilable(T::Array[T::Hash[String, T.untyped]]))
|
41
|
+
@dependency_repository_details = T.let(nil, T.nilable(T::Array[T::Hash[String, T.untyped]]))
|
42
|
+
end
|
43
|
+
|
44
|
+
sig { returns(Dependabot::Dependency) }
|
45
|
+
attr_reader :dependency
|
46
|
+
|
47
|
+
sig { returns(T::Array[T.untyped]) }
|
48
|
+
attr_reader :dependency_files
|
49
|
+
|
50
|
+
sig { returns(T::Array[T.untyped]) }
|
51
|
+
attr_reader :credentials
|
52
|
+
|
53
|
+
sig { returns(T.nilable(T::Array[String])) }
|
54
|
+
attr_reader :forbidden_urls
|
55
|
+
|
56
|
+
# rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
57
|
+
sig do
|
58
|
+
returns(T::Array[T::Hash[String, T.untyped]])
|
59
|
+
end
|
60
|
+
def fetch_available_versions
|
61
|
+
release_date_info = T.let({}, T::Hash[String, T::Hash[Symbol, T.untyped]])
|
62
|
+
package_releases = T.let([], T::Array[T::Hash[String, T.untyped]])
|
63
|
+
|
64
|
+
version_details =
|
65
|
+
repositories.map do |repository_details|
|
66
|
+
url = repository_details.fetch("url")
|
67
|
+
|
68
|
+
next google_version_details if url == Gradle::FileParser::RepositoriesFinder::GOOGLE_MAVEN_REPO
|
69
|
+
|
70
|
+
dependency_metadata(repository_details).css("versions > version")
|
71
|
+
.select { |node| version_class.correct?(node.content) }
|
72
|
+
.map { |node| version_class.new(node.content) }
|
73
|
+
.map do |version|
|
74
|
+
{ version: version, source_url: url }
|
75
|
+
end
|
76
|
+
end.flatten.compact
|
77
|
+
|
78
|
+
version_details = version_details.sort_by { |details| details.fetch(:version) }
|
79
|
+
release_date_info = release_details
|
80
|
+
|
81
|
+
version_details.map do |info|
|
82
|
+
version = info[:version]&.to_s
|
83
|
+
|
84
|
+
package_releases << {
|
85
|
+
version: Gradle::Version.new(version),
|
86
|
+
released_at: release_date_info.none? ? nil : (release_date_info[version]&.fetch(:release_date) || nil),
|
87
|
+
source_url: info[:source_url]
|
88
|
+
}
|
89
|
+
end
|
90
|
+
if version_details.none? && T.must(forbidden_urls).any?
|
91
|
+
raise PrivateSourceAuthenticationFailure,
|
92
|
+
T.must(forbidden_urls).first
|
93
|
+
end
|
94
|
+
# version_details
|
95
|
+
|
96
|
+
package_releases
|
97
|
+
end
|
98
|
+
# rubocop:enable Metrics/AbcSize,Metrics/PerceivedComplexity
|
99
|
+
|
100
|
+
sig { returns(T::Hash[String, T::Hash[Symbol, T.untyped]]) }
|
101
|
+
def release_details
|
102
|
+
release_date_info = T.let({}, T::Hash[String, T::Hash[Symbol, T.untyped]])
|
103
|
+
|
104
|
+
begin
|
105
|
+
repositories.map do |repository_details|
|
106
|
+
url = repository_details.fetch("url")
|
107
|
+
next unless url == Gradle::FileParser::RepositoriesFinder::CENTRAL_REPO_URL
|
108
|
+
|
109
|
+
release_info_metadata(repository_details).css("a[title]").each do |link|
|
110
|
+
version_string = link["title"]
|
111
|
+
version = version_string.gsub(%r{/$}, "")
|
112
|
+
raw_date_text = link.next.text.strip.split("\n").last.strip
|
113
|
+
|
114
|
+
release_date = begin
|
115
|
+
Time.parse(raw_date_text)
|
116
|
+
rescue StandardError
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
|
120
|
+
next unless version && version_class.correct?(version)
|
121
|
+
|
122
|
+
release_date_info[version] = {
|
123
|
+
release_date: release_date
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
release_date_info
|
129
|
+
rescue StandardError
|
130
|
+
Dependabot.logger.error("Failed to get release date")
|
131
|
+
{}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
sig { returns(T::Array[T::Hash[String, T.untyped]]) }
|
136
|
+
def repositories
|
137
|
+
return @repositories if @repositories
|
138
|
+
|
139
|
+
details = if plugin?
|
140
|
+
T.must(plugin_repository_details) +
|
141
|
+
credentials_repository_details
|
142
|
+
else
|
143
|
+
dependency_repository_details +
|
144
|
+
credentials_repository_details
|
145
|
+
end
|
146
|
+
|
147
|
+
@repositories =
|
148
|
+
details.reject do |repo|
|
149
|
+
next if repo["auth_headers"]
|
150
|
+
|
151
|
+
# Reject this entry if an identical one with non-empty auth_headers exists
|
152
|
+
details.any? { |r| r["url"] == repo["url"] && r["auth_headers"] != {} }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
sig { returns(T.any(T::Array[T::Hash[String, T.untyped]], NilClass)) }
|
157
|
+
def google_version_details
|
158
|
+
url = Gradle::FileParser::RepositoriesFinder::GOOGLE_MAVEN_REPO
|
159
|
+
group_id, artifact_id = group_and_artifact_ids
|
160
|
+
|
161
|
+
dependency_metadata_url = "#{Gradle::FileParser::RepositoriesFinder::GOOGLE_MAVEN_REPO}/" \
|
162
|
+
"#{T.must(group_id).tr('.', '/')}/" \
|
163
|
+
"group-index.xml"
|
164
|
+
|
165
|
+
@google_version_details ||=
|
166
|
+
begin
|
167
|
+
response = Dependabot::RegistryClient.get(url: dependency_metadata_url)
|
168
|
+
Nokogiri::XML(response.body)
|
169
|
+
end
|
170
|
+
|
171
|
+
xpath = "/#{group_id}/#{artifact_id}"
|
172
|
+
return unless @google_version_details.at_xpath(xpath)
|
173
|
+
|
174
|
+
@google_version_details.at_xpath(xpath)
|
175
|
+
.attributes.fetch("versions")
|
176
|
+
.value.split(",")
|
177
|
+
.select { |v| version_class.correct?(v) }
|
178
|
+
.map { |v| version_class.new(v) }
|
179
|
+
.map { |version| { version: version, source_url: url } }
|
180
|
+
rescue Nokogiri::XML::XPath::SyntaxError
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
sig { params(repository_details: T::Hash[T.untyped, T.untyped]).returns(T.untyped) }
|
185
|
+
def dependency_metadata(repository_details)
|
186
|
+
@dependency_metadata ||= T.let({}, T.nilable(T::Hash[T.untyped, T.untyped]))
|
187
|
+
@dependency_metadata[repository_details.hash] ||=
|
188
|
+
begin
|
189
|
+
response = Dependabot::RegistryClient.get(
|
190
|
+
url: dependency_metadata_url(repository_details.fetch("url")),
|
191
|
+
headers: repository_details.fetch("auth_headers")
|
192
|
+
)
|
193
|
+
|
194
|
+
check_response(response, repository_details.fetch("url"))
|
195
|
+
Nokogiri::XML(response.body)
|
196
|
+
rescue URI::InvalidURIError
|
197
|
+
Nokogiri::XML("")
|
198
|
+
rescue Excon::Error::Socket, Excon::Error::Timeout,
|
199
|
+
Excon::Error::TooManyRedirects
|
200
|
+
raise if central_repo_urls.include?(repository_details["url"])
|
201
|
+
|
202
|
+
Nokogiri::XML("")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
sig { params(repository_details: T::Hash[T.untyped, T.untyped]).returns(T.untyped) }
|
207
|
+
def release_info_metadata(repository_details)
|
208
|
+
@release_info_metadata ||= T.let({}, T.nilable(T::Hash[T.untyped, T.untyped]))
|
209
|
+
@release_info_metadata[repository_details.hash] ||=
|
210
|
+
begin
|
211
|
+
response = Dependabot::RegistryClient.get(
|
212
|
+
url: dependency_metadata_url(repository_details.fetch("url")).gsub("maven-metadata.xml", ""),
|
213
|
+
headers: repository_details.fetch("auth_headers")
|
214
|
+
)
|
215
|
+
|
216
|
+
check_response(response, repository_details.fetch("url"))
|
217
|
+
Nokogiri::XML(response.body)
|
218
|
+
rescue URI::InvalidURIError
|
219
|
+
Nokogiri::XML("")
|
220
|
+
rescue Excon::Error::Socket, Excon::Error::Timeout,
|
221
|
+
Excon::Error::TooManyRedirects
|
222
|
+
raise if central_repo_urls.include?(repository_details["url"])
|
223
|
+
|
224
|
+
Nokogiri::XML("")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
sig { returns(T.untyped) }
|
229
|
+
def repository_urls
|
230
|
+
plugin? ? plugin_repository_details : dependency_repository_details
|
231
|
+
end
|
232
|
+
|
233
|
+
sig { params(response: T.untyped, repository_url: T.untyped).returns(T.nilable(T::Array[T.untyped])) }
|
234
|
+
def check_response(response, repository_url)
|
235
|
+
return unless response.status == 401 || response.status == 403
|
236
|
+
return if T.must(@forbidden_urls).include?(repository_url)
|
237
|
+
return if central_repo_urls.include?(repository_url)
|
238
|
+
|
239
|
+
T.must(@forbidden_urls) << repository_url
|
240
|
+
end
|
241
|
+
|
242
|
+
sig { returns(T::Array[T.untyped]) }
|
243
|
+
def credentials_repository_details
|
244
|
+
credentials
|
245
|
+
.select { |cred| cred["type"] == "maven_repository" }
|
246
|
+
.map do |cred|
|
247
|
+
{
|
248
|
+
"url" => cred.fetch("url").gsub(%r{/+$}, ""),
|
249
|
+
"auth_headers" => auth_headers(cred.fetch("url").gsub(%r{/+$}, ""))
|
250
|
+
}
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
sig { returns(T::Array[T.untyped]) }
|
255
|
+
def dependency_repository_details
|
256
|
+
requirement_files =
|
257
|
+
dependency.requirements
|
258
|
+
.map { |r| r.fetch(:file) }
|
259
|
+
.map { |nm| dependency_files.find { |f| f.name == nm } }
|
260
|
+
|
261
|
+
@dependency_repository_details ||=
|
262
|
+
requirement_files.flat_map do |target_file|
|
263
|
+
Gradle::FileParser::RepositoriesFinder.new(
|
264
|
+
dependency_files: dependency_files,
|
265
|
+
target_dependency_file: target_file
|
266
|
+
).repository_urls
|
267
|
+
.map do |url|
|
268
|
+
{ "url" => url, "auth_headers" => {} }
|
269
|
+
end
|
270
|
+
end.uniq
|
271
|
+
end
|
272
|
+
|
273
|
+
sig { returns(T.nilable(T::Array[T::Hash[String, T.untyped]])) }
|
274
|
+
def plugin_repository_details
|
275
|
+
[{
|
276
|
+
"url" => Gradle::FileParser::RepositoriesFinder::GRADLE_PLUGINS_REPO,
|
277
|
+
"auth_headers" => {}
|
278
|
+
}] + dependency_repository_details
|
279
|
+
end
|
280
|
+
|
281
|
+
sig { params(comparison_version: T.untyped).returns(T::Boolean) }
|
282
|
+
def matches_dependency_version_type?(comparison_version)
|
283
|
+
return true unless dependency.version
|
284
|
+
|
285
|
+
current_type = T.must(dependency.version)
|
286
|
+
.gsub("native-mt", "native_mt")
|
287
|
+
.split(/[.\-]/)
|
288
|
+
.find do |type|
|
289
|
+
Dependabot::Gradle::UpdateChecker::VersionFinder::TYPE_SUFFICES.find { |s| type.include?(s) }
|
290
|
+
end
|
291
|
+
|
292
|
+
version_type = comparison_version.to_s
|
293
|
+
.gsub("native-mt", "native_mt")
|
294
|
+
.split(/[.\-]/)
|
295
|
+
.find do |type|
|
296
|
+
Dependabot::Gradle::UpdateChecker::VersionFinder::TYPE_SUFFICES.find { |s| type.include?(s) }
|
297
|
+
end
|
298
|
+
|
299
|
+
current_type == version_type
|
300
|
+
end
|
301
|
+
|
302
|
+
sig { returns(T::Array[T.untyped]) }
|
303
|
+
def pom
|
304
|
+
filename = T.must(dependency.requirements.first).fetch(:file)
|
305
|
+
dependency_files.find { |f| f.name == filename }
|
306
|
+
end
|
307
|
+
|
308
|
+
sig { params(repository_url: T.untyped).returns(String) }
|
309
|
+
def dependency_metadata_url(repository_url)
|
310
|
+
group_id, artifact_id = group_and_artifact_ids
|
311
|
+
group_id = "#{Dependabot::Gradle::MetadataFinder::KOTLIN_PLUGIN_REPO_PREFIX}.#{group_id}" if kotlin_plugin?
|
312
|
+
|
313
|
+
"#{repository_url}/" \
|
314
|
+
"#{T.must(group_id).tr('.', '/')}/" \
|
315
|
+
"#{artifact_id}/" \
|
316
|
+
"maven-metadata.xml"
|
317
|
+
end
|
318
|
+
|
319
|
+
sig { returns(T::Array[String]) }
|
320
|
+
def group_and_artifact_ids
|
321
|
+
if kotlin_plugin?
|
322
|
+
[dependency.name,
|
323
|
+
"#{Dependabot::Gradle::MetadataFinder::KOTLIN_PLUGIN_REPO_PREFIX}.#{dependency.name}.gradle.plugin"]
|
324
|
+
elsif plugin?
|
325
|
+
[dependency.name, "#{dependency.name}.gradle.plugin"]
|
326
|
+
else
|
327
|
+
dependency.name.split(":")
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
sig { returns(T::Boolean) }
|
332
|
+
def plugin?
|
333
|
+
dependency.requirements.any? { |r| r.fetch(:groups).include? "plugins" }
|
334
|
+
end
|
335
|
+
|
336
|
+
sig { returns(T.nilable(T::Boolean)) }
|
337
|
+
def kotlin_plugin?
|
338
|
+
plugin? && dependency.requirements.any? { |r| r.fetch(:groups).include? "kotlin" }
|
339
|
+
end
|
340
|
+
|
341
|
+
sig { returns(T::Array[String]) }
|
342
|
+
def central_repo_urls
|
343
|
+
central_url_without_protocol =
|
344
|
+
Gradle::FileParser::RepositoriesFinder::CENTRAL_REPO_URL
|
345
|
+
.gsub(%r{^.*://}, "")
|
346
|
+
|
347
|
+
%w(http:// https://).map { |p| p + central_url_without_protocol }
|
348
|
+
end
|
349
|
+
|
350
|
+
sig { returns(T.class_of(Dependabot::Version)) }
|
351
|
+
def version_class
|
352
|
+
dependency.version_class
|
353
|
+
end
|
354
|
+
|
355
|
+
sig { returns(Dependabot::Maven::Utils::AuthHeadersFinder) }
|
356
|
+
def auth_headers_finder
|
357
|
+
@auth_headers_finder ||= T.let(Dependabot::Maven::Utils::AuthHeadersFinder.new(credentials),
|
358
|
+
T.nilable(Dependabot::Maven::Utils::AuthHeadersFinder))
|
359
|
+
end
|
360
|
+
|
361
|
+
sig { params(maven_repo_url: String).returns(T::Hash[String, String]) }
|
362
|
+
def auth_headers(maven_repo_url)
|
363
|
+
auth_headers_finder.auth_headers(maven_repo_url)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
@@ -10,43 +10,80 @@ require "dependabot/gradle/version"
|
|
10
10
|
require "dependabot/gradle/requirement"
|
11
11
|
require "dependabot/maven/utils/auth_headers_finder"
|
12
12
|
require "sorbet-runtime"
|
13
|
+
require "dependabot/gradle/package/package_details_fetcher"
|
14
|
+
require "dependabot/package/package_latest_version_finder"
|
13
15
|
|
14
16
|
module Dependabot
|
15
17
|
module Gradle
|
16
18
|
class UpdateChecker
|
17
|
-
class VersionFinder
|
19
|
+
class VersionFinder < Dependabot::Package::PackageLatestVersionFinder
|
18
20
|
extend T::Sig
|
19
21
|
|
20
22
|
KOTLIN_PLUGIN_REPO_PREFIX = "org.jetbrains.kotlin"
|
21
23
|
TYPE_SUFFICES = %w(jre android java native_mt agp).freeze
|
22
24
|
|
25
|
+
sig do
|
26
|
+
params(dependency: Dependabot::Dependency, dependency_files: T::Array[Dependabot::DependencyFile],
|
27
|
+
credentials: T::Array[Dependabot::Credential], ignored_versions: T::Array[String],
|
28
|
+
security_advisories: T::Array[Dependabot::SecurityAdvisory], raise_on_ignored: T::Boolean,
|
29
|
+
cooldown_options: T.nilable(Dependabot::Package::ReleaseCooldownOptions)).void
|
30
|
+
end
|
23
31
|
def initialize(dependency:, dependency_files:, credentials:,
|
24
|
-
ignored_versions:,
|
25
|
-
security_advisories:)
|
32
|
+
ignored_versions:,
|
33
|
+
security_advisories:, raise_on_ignored: false, cooldown_options: nil)
|
34
|
+
@security_advisories = security_advisories
|
26
35
|
@dependency = dependency
|
27
36
|
@dependency_files = dependency_files
|
28
37
|
@credentials = credentials
|
29
|
-
@ignored_versions = ignored_versions
|
30
38
|
@raise_on_ignored = raise_on_ignored
|
31
|
-
@
|
32
|
-
@
|
39
|
+
@forbidden_urls = T.let([], T::Array[T.untyped])
|
40
|
+
@ignored_versions = ignored_versions
|
41
|
+
|
42
|
+
super(
|
43
|
+
dependency: dependency,
|
44
|
+
dependency_files: dependency_files,
|
45
|
+
credentials: credentials,
|
46
|
+
ignored_versions: ignored_versions,
|
47
|
+
security_advisories: security_advisories,
|
48
|
+
cooldown_options: cooldown_options,
|
49
|
+
raise_on_ignored: raise_on_ignored,
|
50
|
+
options: {}
|
51
|
+
)
|
33
52
|
end
|
34
53
|
|
54
|
+
sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) }
|
35
55
|
def latest_version_details
|
36
|
-
possible_versions = versions
|
56
|
+
possible_versions = package_release(versions)
|
37
57
|
|
38
|
-
possible_versions =
|
58
|
+
possible_versions = filter_prerelease_versions(possible_versions)
|
39
59
|
possible_versions = filter_date_based_versions(possible_versions)
|
40
60
|
possible_versions = filter_version_types(possible_versions)
|
41
61
|
possible_versions = filter_ignored_versions(possible_versions)
|
42
62
|
|
43
|
-
possible_versions
|
63
|
+
possible_versions = filter_cooldown_versions(possible_versions)
|
64
|
+
|
65
|
+
return unless possible_versions.any?
|
66
|
+
|
67
|
+
version_max = possible_versions.max_by(&:version)&.version
|
68
|
+
|
69
|
+
url = possible_versions.select do |v| # rubocop:disable Performance/Detect
|
70
|
+
v.version.to_s == version_max.to_s
|
71
|
+
end.last&.url
|
72
|
+
|
73
|
+
{ version: version_max,
|
74
|
+
source_url: url }
|
44
75
|
end
|
45
76
|
|
77
|
+
sig { override.returns(T::Boolean) }
|
78
|
+
def cooldown_enabled?
|
79
|
+
Dependabot::Experiments.enabled?(:enable_cooldown_for_gradle)
|
80
|
+
end
|
81
|
+
|
82
|
+
sig { returns(T.nilable(T::Hash[T.untyped, T.untyped])) }
|
46
83
|
def lowest_security_fix_version_details
|
47
|
-
possible_versions = versions
|
84
|
+
possible_versions = package_release(versions)
|
48
85
|
|
49
|
-
possible_versions =
|
86
|
+
possible_versions = filter_prerelease_versions(possible_versions)
|
50
87
|
possible_versions = filter_date_based_versions(possible_versions)
|
51
88
|
possible_versions = filter_version_types(possible_versions)
|
52
89
|
possible_versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(possible_versions,
|
@@ -54,51 +91,53 @@ module Dependabot
|
|
54
91
|
possible_versions = filter_ignored_versions(possible_versions)
|
55
92
|
possible_versions = filter_lower_versions(possible_versions)
|
56
93
|
|
57
|
-
possible_versions.
|
58
|
-
end
|
94
|
+
return unless possible_versions.any?
|
59
95
|
|
60
|
-
|
61
|
-
version_details =
|
62
|
-
repositories.map do |repository_details|
|
63
|
-
url = repository_details.fetch("url")
|
64
|
-
next google_version_details if url == Gradle::FileParser::RepositoriesFinder::GOOGLE_MAVEN_REPO
|
96
|
+
version_min = possible_versions.min_by(&:version)&.version
|
65
97
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
.map { |version| { version: version, source_url: url } }
|
70
|
-
end.flatten.compact
|
98
|
+
url = possible_versions.select do |v| # rubocop:disable Performance/Detect
|
99
|
+
v.version.to_s == version_min.to_s
|
100
|
+
end.last&.url
|
71
101
|
|
72
|
-
|
102
|
+
{ version: version_min,
|
103
|
+
source_url: url }
|
104
|
+
end
|
73
105
|
|
74
|
-
|
106
|
+
sig { returns(T.any(T::Array[T::Hash[String, T.untyped]], T::Array[T::Hash[Symbol, T.untyped]])) }
|
107
|
+
def versions
|
108
|
+
Package::PackageDetailsFetcher.new(
|
109
|
+
dependency: dependency,
|
110
|
+
dependency_files: dependency_files,
|
111
|
+
credentials: credentials,
|
112
|
+
forbidden_urls: forbidden_urls
|
113
|
+
).fetch_available_versions
|
75
114
|
end
|
76
115
|
|
77
116
|
private
|
78
117
|
|
118
|
+
sig { returns(Dependabot::Dependency) }
|
79
119
|
attr_reader :dependency
|
120
|
+
|
121
|
+
sig { returns(T::Array[T.untyped]) }
|
80
122
|
attr_reader :dependency_files
|
123
|
+
|
124
|
+
sig { returns(T::Array[T.untyped]) }
|
81
125
|
attr_reader :credentials
|
82
|
-
|
126
|
+
|
127
|
+
sig { returns(T.nilable(T::Array[String])) }
|
83
128
|
attr_reader :forbidden_urls
|
84
|
-
attr_reader :security_advisories
|
85
129
|
|
86
|
-
sig {
|
87
|
-
|
88
|
-
return possible_versions if wants_prerelease?
|
130
|
+
sig { returns(T::Array[String]) }
|
131
|
+
attr_reader :ignored_versions
|
89
132
|
|
90
|
-
|
91
|
-
|
92
|
-
Dependabot.logger.info("Filtered out #{possible_versions.count - filtered.count} pre-release versions")
|
93
|
-
end
|
94
|
-
filtered
|
95
|
-
end
|
133
|
+
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
134
|
+
attr_reader :security_advisories
|
96
135
|
|
97
136
|
sig { params(possible_versions: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
|
98
137
|
def filter_date_based_versions(possible_versions)
|
99
138
|
return possible_versions if wants_date_based_version?
|
100
139
|
|
101
|
-
filtered = possible_versions.reject { |
|
140
|
+
filtered = possible_versions.reject { |release| release.version > version_class.new(1900) }
|
102
141
|
if possible_versions.count > filtered.count
|
103
142
|
Dependabot.logger.info("Filtered out #{possible_versions.count - filtered.count} date-based versions")
|
104
143
|
end
|
@@ -107,15 +146,39 @@ module Dependabot
|
|
107
146
|
|
108
147
|
sig { params(possible_versions: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
|
109
148
|
def filter_version_types(possible_versions)
|
110
|
-
filtered = possible_versions.select { |
|
149
|
+
filtered = possible_versions.select { |release| matches_dependency_version_type?(release.version) }
|
111
150
|
if possible_versions.count > filtered.count
|
112
151
|
diff = possible_versions.count - filtered.count
|
113
|
-
classifier = dependency.version.split(/[.\-]/).last
|
152
|
+
classifier = T.must(dependency.version).split(/[.\-]/).last
|
114
153
|
Dependabot.logger.info("Filtered out #{diff} non-#{classifier} classifier versions")
|
115
154
|
end
|
116
155
|
filtered
|
117
156
|
end
|
118
157
|
|
158
|
+
sig { params(version: T::Array[T.untyped]).returns(T::Array[Dependabot::Package::PackageRelease]) }
|
159
|
+
def package_release(version)
|
160
|
+
package_releases = []
|
161
|
+
|
162
|
+
version.map do |info|
|
163
|
+
package_releases << Dependabot::Package::PackageRelease.new(
|
164
|
+
version: info[:version],
|
165
|
+
released_at: info[:released_at],
|
166
|
+
url: info[:source_url]
|
167
|
+
)
|
168
|
+
end
|
169
|
+
package_releases
|
170
|
+
end
|
171
|
+
|
172
|
+
sig { returns(Package::PackageDetailsFetcher) }
|
173
|
+
def package_details_fetcher
|
174
|
+
@package_details_fetcher ||= T.let(Package::PackageDetailsFetcher.new(
|
175
|
+
dependency: dependency,
|
176
|
+
dependency_files: dependency_files,
|
177
|
+
credentials: credentials,
|
178
|
+
forbidden_urls: []
|
179
|
+
), T.nilable(Dependabot::Gradle::Package::PackageDetailsFetcher))
|
180
|
+
end
|
181
|
+
|
119
182
|
sig { params(possible_versions: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
|
120
183
|
def filter_ignored_versions(possible_versions)
|
121
184
|
filtered = possible_versions
|
@@ -124,7 +187,7 @@ module Dependabot
|
|
124
187
|
ignore_requirements = Gradle::Requirement.requirements_array(req)
|
125
188
|
filtered =
|
126
189
|
filtered
|
127
|
-
.reject { |v| ignore_requirements.any? { |r| r.satisfied_by?(v.
|
190
|
+
.reject { |v| ignore_requirements.any? { |r| r.satisfied_by?(v.version) } }
|
128
191
|
end
|
129
192
|
|
130
193
|
if @raise_on_ignored && filter_lower_versions(filtered).empty? &&
|
@@ -140,149 +203,82 @@ module Dependabot
|
|
140
203
|
filtered
|
141
204
|
end
|
142
205
|
|
143
|
-
sig
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
possible_versions.select do |v|
|
148
|
-
v.fetch(:version) > dependency.numeric_version
|
149
|
-
end
|
206
|
+
sig do
|
207
|
+
params(releases: T::Array[Dependabot::Package::PackageRelease])
|
208
|
+
.returns(T::Array[Dependabot::Package::PackageRelease])
|
150
209
|
end
|
210
|
+
def filter_cooldown_versions(releases)
|
211
|
+
return releases unless cooldown_enabled?
|
151
212
|
|
152
|
-
|
153
|
-
return false unless dependency.numeric_version
|
213
|
+
Dependabot.logger.info("Initializing cooldown filter")
|
154
214
|
|
155
|
-
|
156
|
-
end
|
215
|
+
sorted_releases = releases.sort_by(&:version).reverse
|
157
216
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
dependency.numeric_version >= version_class.new(100)
|
162
|
-
end
|
217
|
+
filtered_versions = []
|
218
|
+
cooldown_filtered_versions = 0
|
163
219
|
|
164
|
-
|
165
|
-
|
166
|
-
|
220
|
+
# Iterate through the sorted versions lazily, filtering out cooldown versions
|
221
|
+
sorted_releases.each do |release|
|
222
|
+
if in_cooldown_period?(release)
|
223
|
+
Dependabot.logger.info("Filtered out (cooldown) : #{release}")
|
224
|
+
cooldown_filtered_versions += 1
|
167
225
|
|
168
|
-
|
169
|
-
"#{group_id.tr('.', '/')}/" \
|
170
|
-
"group-index.xml"
|
171
|
-
|
172
|
-
@google_version_details ||=
|
173
|
-
begin
|
174
|
-
response = Dependabot::RegistryClient.get(url: dependency_metadata_url)
|
175
|
-
Nokogiri::XML(response.body)
|
226
|
+
next
|
176
227
|
end
|
177
228
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
@google_version_details.at_xpath(xpath)
|
182
|
-
.attributes.fetch("versions")
|
183
|
-
.value.split(",")
|
184
|
-
.select { |v| version_class.correct?(v) }
|
185
|
-
.map { |v| version_class.new(v) }
|
186
|
-
.map { |version| { version: version, source_url: url } }
|
187
|
-
rescue Nokogiri::XML::XPath::SyntaxError
|
188
|
-
nil
|
189
|
-
end
|
190
|
-
|
191
|
-
def dependency_metadata(repository_details)
|
192
|
-
@dependency_metadata ||= {}
|
193
|
-
@dependency_metadata[repository_details.hash] ||=
|
194
|
-
begin
|
195
|
-
response = Dependabot::RegistryClient.get(
|
196
|
-
url: dependency_metadata_url(repository_details.fetch("url")),
|
197
|
-
headers: repository_details.fetch("auth_headers")
|
198
|
-
)
|
199
|
-
check_response(response, repository_details.fetch("url"))
|
200
|
-
Nokogiri::XML(response.body)
|
201
|
-
rescue URI::InvalidURIError
|
202
|
-
Nokogiri::XML("")
|
203
|
-
rescue Excon::Error::Socket, Excon::Error::Timeout,
|
204
|
-
Excon::Error::TooManyRedirects
|
205
|
-
raise if central_repo_urls.include?(repository_details["url"])
|
206
|
-
|
207
|
-
Nokogiri::XML("")
|
208
|
-
end
|
209
|
-
end
|
229
|
+
filtered_versions << release
|
230
|
+
break
|
231
|
+
end
|
210
232
|
|
211
|
-
|
212
|
-
|
233
|
+
Dependabot.logger.info("Filtered out #{cooldown_filtered_versions} version(s) due to cooldown")
|
234
|
+
filtered_versions
|
213
235
|
end
|
214
236
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
end
|
237
|
+
sig { params(release: Dependabot::Package::PackageRelease).returns(T::Boolean) }
|
238
|
+
def in_cooldown_period?(release)
|
239
|
+
unless release.released_at
|
240
|
+
Dependabot.logger.info("Release date not available for version #{release.version}")
|
241
|
+
return false
|
242
|
+
end
|
222
243
|
|
223
|
-
|
224
|
-
|
244
|
+
current_version = version_class.correct?(dependency.version) ? version_class.new(dependency.version) : nil
|
245
|
+
days = cooldown_days_for(current_version, release.version)
|
225
246
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
else
|
230
|
-
dependency_repository_details +
|
231
|
-
credentials_repository_details
|
232
|
-
end
|
247
|
+
# Calculate the number of seconds passed since the release
|
248
|
+
passed_seconds = Time.now.to_i - release.released_at.to_i
|
249
|
+
passed_days = passed_seconds / DAY_IN_SECONDS
|
233
250
|
|
234
|
-
|
235
|
-
|
236
|
-
|
251
|
+
if passed_days < days
|
252
|
+
Dependabot.logger.info("Version #{release.version}, Release date: #{release.released_at}." \
|
253
|
+
" Days since release: #{passed_days} (cooldown days: #{days})")
|
254
|
+
end
|
237
255
|
|
238
|
-
|
239
|
-
|
240
|
-
end
|
256
|
+
# Check if the release is within the cooldown period
|
257
|
+
passed_seconds < days * DAY_IN_SECONDS
|
241
258
|
end
|
242
259
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
.map do |cred|
|
247
|
-
{
|
248
|
-
"url" => cred.fetch("url").gsub(%r{/+$}, ""),
|
249
|
-
"auth_headers" => auth_headers(cred.fetch("url").gsub(%r{/+$}, ""))
|
250
|
-
}
|
251
|
-
end
|
252
|
-
end
|
260
|
+
sig { returns(T::Boolean) }
|
261
|
+
def wants_prerelease?
|
262
|
+
return false unless dependency.numeric_version
|
253
263
|
|
254
|
-
|
255
|
-
requirement_files =
|
256
|
-
dependency.requirements
|
257
|
-
.map { |r| r.fetch(:file) }
|
258
|
-
.map { |nm| dependency_files.find { |f| f.name == nm } }
|
259
|
-
|
260
|
-
@dependency_repository_details ||=
|
261
|
-
requirement_files.flat_map do |target_file|
|
262
|
-
Gradle::FileParser::RepositoriesFinder.new(
|
263
|
-
dependency_files: dependency_files,
|
264
|
-
target_dependency_file: target_file
|
265
|
-
).repository_urls
|
266
|
-
.map do |url|
|
267
|
-
{ "url" => url, "auth_headers" => {} }
|
268
|
-
end
|
269
|
-
end.uniq
|
264
|
+
T.must(dependency.numeric_version).prerelease?
|
270
265
|
end
|
271
266
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
267
|
+
sig { returns(T::Boolean) }
|
268
|
+
def wants_date_based_version?
|
269
|
+
return false unless dependency.numeric_version
|
270
|
+
|
271
|
+
T.must(dependency.numeric_version) >= version_class.new(100)
|
277
272
|
end
|
278
273
|
|
274
|
+
sig { params(comparison_version: T.untyped).returns(T::Boolean) }
|
279
275
|
def matches_dependency_version_type?(comparison_version)
|
280
276
|
return true unless dependency.version
|
281
277
|
|
282
|
-
current_type = dependency.version
|
283
|
-
|
284
|
-
|
285
|
-
|
278
|
+
current_type = T.must(dependency.version)
|
279
|
+
.gsub("native-mt", "native_mt")
|
280
|
+
.split(/[.\-]/)
|
281
|
+
.find do |type|
|
286
282
|
TYPE_SUFFICES.find { |s| type.include?(s) }
|
287
283
|
end
|
288
284
|
|
@@ -296,58 +292,12 @@ module Dependabot
|
|
296
292
|
current_type == version_type
|
297
293
|
end
|
298
294
|
|
299
|
-
|
300
|
-
filename = dependency.requirements.first.fetch(:file)
|
301
|
-
dependency_files.find { |f| f.name == filename }
|
302
|
-
end
|
303
|
-
|
304
|
-
def dependency_metadata_url(repository_url)
|
305
|
-
group_id, artifact_id = group_and_artifact_ids
|
306
|
-
group_id = "#{KOTLIN_PLUGIN_REPO_PREFIX}.#{group_id}" if kotlin_plugin?
|
307
|
-
|
308
|
-
"#{repository_url}/" \
|
309
|
-
"#{group_id.tr('.', '/')}/" \
|
310
|
-
"#{artifact_id}/" \
|
311
|
-
"maven-metadata.xml"
|
312
|
-
end
|
313
|
-
|
314
|
-
def group_and_artifact_ids
|
315
|
-
if kotlin_plugin?
|
316
|
-
[dependency.name, "#{KOTLIN_PLUGIN_REPO_PREFIX}.#{dependency.name}.gradle.plugin"]
|
317
|
-
elsif plugin?
|
318
|
-
[dependency.name, "#{dependency.name}.gradle.plugin"]
|
319
|
-
else
|
320
|
-
dependency.name.split(":")
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
def plugin?
|
325
|
-
dependency.requirements.any? { |r| r.fetch(:groups).include? "plugins" }
|
326
|
-
end
|
327
|
-
|
328
|
-
def kotlin_plugin?
|
329
|
-
plugin? && dependency.requirements.any? { |r| r.fetch(:groups).include? "kotlin" }
|
330
|
-
end
|
331
|
-
|
332
|
-
def central_repo_urls
|
333
|
-
central_url_without_protocol =
|
334
|
-
Gradle::FileParser::RepositoriesFinder::CENTRAL_REPO_URL
|
335
|
-
.gsub(%r{^.*://}, "")
|
336
|
-
|
337
|
-
%w(http:// https://).map { |p| p + central_url_without_protocol }
|
338
|
-
end
|
339
|
-
|
295
|
+
sig { returns(T.class_of(Dependabot::Version)) }
|
340
296
|
def version_class
|
341
297
|
dependency.version_class
|
342
298
|
end
|
343
|
-
|
344
|
-
def
|
345
|
-
@auth_headers_finder ||= Dependabot::Maven::Utils::AuthHeadersFinder.new(credentials)
|
346
|
-
end
|
347
|
-
|
348
|
-
def auth_headers(maven_repo_url)
|
349
|
-
auth_headers_finder.auth_headers(maven_repo_url)
|
350
|
-
end
|
299
|
+
sig { override.returns(T.nilable(Dependabot::Package::PackageDetails)) }
|
300
|
+
def package_details; end
|
351
301
|
end
|
352
302
|
end
|
353
303
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-gradle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.313.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-05-
|
10
|
+
date: 2025-05-15 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: dependabot-common
|
@@ -15,28 +15,28 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - '='
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 0.
|
18
|
+
version: 0.313.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.313.0
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: dependabot-maven
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
30
|
- - '='
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.
|
32
|
+
version: 0.313.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - '='
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.
|
39
|
+
version: 0.313.0
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: debug
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -266,6 +266,7 @@ files:
|
|
266
266
|
- lib/dependabot/gradle/file_updater/property_value_updater.rb
|
267
267
|
- lib/dependabot/gradle/language.rb
|
268
268
|
- lib/dependabot/gradle/metadata_finder.rb
|
269
|
+
- lib/dependabot/gradle/package/package_details_fetcher.rb
|
269
270
|
- lib/dependabot/gradle/package_manager.rb
|
270
271
|
- lib/dependabot/gradle/requirement.rb
|
271
272
|
- lib/dependabot/gradle/update_checker.rb
|
@@ -278,7 +279,7 @@ licenses:
|
|
278
279
|
- MIT
|
279
280
|
metadata:
|
280
281
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
281
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
282
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.313.0
|
282
283
|
rdoc_options: []
|
283
284
|
require_paths:
|
284
285
|
- lib
|