dependabot-npm_and_yarn 0.321.3 → 0.322.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 +4 -4
- data/lib/dependabot/npm_and_yarn/file_parser.rb +1 -1
- data/lib/dependabot/npm_and_yarn/package/package_details_fetcher.rb +2 -4
- data/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb +48 -600
- data/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb +12 -32
- data/lib/dependabot/npm_and_yarn/update_checker.rb +12 -33
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82092e446c633ecd1762c1f5679fd4f10e1f2c17f6c2b054f0a8385bfc1c7faa
|
4
|
+
data.tar.gz: 0ee19ced17a63790ee72987906b440808511235ab7de80edbd4c5c507b203cee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 528addbc67e52c6169e418cb9ea3aa12699f44cca19f947c3e3f6acc2551b514f95d02b6b047b46176e2c918dae9212b9e32c2d1133f40f669f7604822b495d4
|
7
|
+
data.tar.gz: f1351e33bccd4850928dbaa03c268b6bef43090d77046c86e4676ddc3d1cfd4bb86abc26dcbfc87c6a5e6bc44f0874b097607c55126867d94bb154a3f73f5b5e
|
@@ -173,13 +173,11 @@ module Dependabot
|
|
173
173
|
|
174
174
|
package_type = infer_package_type(details)
|
175
175
|
|
176
|
-
deprecated = fetch_value_from_hash(details, RELEASE_DEPRECATION_KEY)
|
177
|
-
|
178
176
|
Dependabot::Package::PackageRelease.new(
|
179
177
|
version: Version.new(version),
|
180
178
|
released_at: time_data[version] ? Time.parse(time_data[version]) : nil,
|
181
|
-
yanked:
|
182
|
-
yanked_reason:
|
179
|
+
yanked: false,
|
180
|
+
yanked_reason: nil,
|
183
181
|
downloads: nil,
|
184
182
|
latest: latest_version.to_s == version,
|
185
183
|
url: package_version_url(version),
|
@@ -75,12 +75,7 @@ module Dependabot
|
|
75
75
|
.returns(T.nilable(Dependabot::Version))
|
76
76
|
end
|
77
77
|
def latest_version_with_no_unlock(language_version: nil)
|
78
|
-
|
79
|
-
return unless valid_npm_details?
|
80
|
-
return version_from_dist_tags&.version if specified_dist_tag_requirement?
|
81
|
-
|
82
|
-
super
|
83
|
-
end
|
78
|
+
fetch_latest_version_with_no_unlock(language_version: language_version)
|
84
79
|
end
|
85
80
|
|
86
81
|
sig do
|
@@ -96,16 +91,17 @@ module Dependabot
|
|
96
91
|
params(language_version: T.nilable(T.any(String, Dependabot::Version)))
|
97
92
|
.returns(T.nilable(Dependabot::Version))
|
98
93
|
end
|
99
|
-
def fetch_latest_version(language_version: nil)
|
94
|
+
def fetch_latest_version(language_version: nil) # rubocop:disable Lint/UnusedMethodArgument
|
100
95
|
with_custom_registry_rescue do
|
101
96
|
return unless valid_npm_details?
|
102
97
|
|
103
|
-
tag_release = version_from_dist_tags
|
98
|
+
tag_release = version_from_dist_tags(cooldown: true)
|
104
99
|
return tag_release.version if tag_release
|
105
100
|
|
106
101
|
return if specified_dist_tag_requirement?
|
107
102
|
|
108
|
-
|
103
|
+
filtered_releases = filter_by_cooldown(possible_releases)
|
104
|
+
filtered_releases.find { |r| !yanked_version?(r.version) }&.version
|
109
105
|
end
|
110
106
|
end
|
111
107
|
|
@@ -114,65 +110,16 @@ module Dependabot
|
|
114
110
|
.params(language_version: T.nilable(T.any(String, Dependabot::Version)))
|
115
111
|
.returns(T.nilable(Dependabot::Version))
|
116
112
|
end
|
117
|
-
def fetch_latest_version_with_no_unlock(language_version: nil)
|
113
|
+
def fetch_latest_version_with_no_unlock(language_version: nil) # rubocop:disable Lint/UnusedMethodArgument
|
118
114
|
with_custom_registry_rescue do
|
119
115
|
return unless valid_npm_details?
|
120
|
-
return version_from_dist_tags&.version if specified_dist_tag_requirement?
|
116
|
+
return version_from_dist_tags(cooldown: true)&.version if specified_dist_tag_requirement?
|
121
117
|
|
122
|
-
|
123
|
-
end
|
124
|
-
end
|
118
|
+
filtered_releases = filter_by_cooldown(possible_releases)
|
125
119
|
|
126
|
-
|
127
|
-
|
128
|
-
.params(releases: T::Array[Dependabot::Package::PackageRelease])
|
129
|
-
.returns(T::Array[Dependabot::Package::PackageRelease])
|
130
|
-
end
|
131
|
-
def apply_post_fetch_latest_versions_filter(releases)
|
132
|
-
original_count = releases.count
|
133
|
-
filtered_versions = lazy_filter_yanked_versions_by_min_max(releases, check_max: true)
|
134
|
-
|
135
|
-
# Log the filter if any versions were removed
|
136
|
-
if original_count > filtered_versions.count
|
137
|
-
Dependabot.logger.info(
|
138
|
-
"Filtered out #{original_count - filtered_versions.count} " \
|
139
|
-
"yanked (not found) versions after fetching latest versions"
|
140
|
-
)
|
120
|
+
in_range_versions = filter_out_of_range_versions(filtered_releases)
|
121
|
+
in_range_versions.find { |r| !yanked_version?(r.version) }&.version
|
141
122
|
end
|
142
|
-
|
143
|
-
filtered_versions
|
144
|
-
end
|
145
|
-
|
146
|
-
sig do
|
147
|
-
params(
|
148
|
-
releases: T::Array[Dependabot::Package::PackageRelease],
|
149
|
-
check_max: T::Boolean
|
150
|
-
).returns(T::Array[Dependabot::Package::PackageRelease])
|
151
|
-
end
|
152
|
-
def lazy_filter_yanked_versions_by_min_max(releases, check_max: true)
|
153
|
-
# Sort the versions based on the check_max flag (max -> descending, min -> ascending)
|
154
|
-
sorted_releases = if check_max
|
155
|
-
releases.sort_by(&:version).reverse
|
156
|
-
else
|
157
|
-
releases.sort_by(&:version)
|
158
|
-
end
|
159
|
-
|
160
|
-
filtered_versions = []
|
161
|
-
|
162
|
-
not_yanked = T.let(false, T::Boolean)
|
163
|
-
|
164
|
-
# Iterate through the sorted versions lazily, filtering out yanked versions
|
165
|
-
sorted_releases.each do |release|
|
166
|
-
next if !not_yanked && yanked_version?(release.version)
|
167
|
-
|
168
|
-
not_yanked = true
|
169
|
-
|
170
|
-
# Once we find a valid (non-yanked) version, add it to the filtered list
|
171
|
-
filtered_versions << release
|
172
|
-
break
|
173
|
-
end
|
174
|
-
|
175
|
-
filtered_versions
|
176
123
|
end
|
177
124
|
|
178
125
|
sig do
|
@@ -200,11 +147,10 @@ module Dependabot
|
|
200
147
|
secure_versions = filter_ignored_versions(secure_versions)
|
201
148
|
secure_versions = filter_lower_versions(secure_versions)
|
202
149
|
|
203
|
-
#
|
204
|
-
secure_versions
|
205
|
-
|
206
|
-
|
207
|
-
secure_versions.max_by(&:version)&.version
|
150
|
+
# Find first non-yanked version
|
151
|
+
secure_versions.sort_by(&:version).find do |version|
|
152
|
+
!yanked_version?(version.version)
|
153
|
+
end&.version
|
208
154
|
end
|
209
155
|
end
|
210
156
|
|
@@ -213,17 +159,16 @@ module Dependabot
|
|
213
159
|
.returns(T::Array[Dependabot::Package::PackageRelease])
|
214
160
|
end
|
215
161
|
def filter_prerelease_versions(releases)
|
216
|
-
|
162
|
+
releases.reject do |release|
|
217
163
|
release.version.prerelease? && !related_to_current_pre?(release.version)
|
218
164
|
end
|
165
|
+
end
|
219
166
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
filtered
|
167
|
+
sig do
|
168
|
+
override.returns(T.nilable(T::Array[Dependabot::Package::PackageRelease]))
|
169
|
+
end
|
170
|
+
def available_versions
|
171
|
+
possible_releases
|
227
172
|
end
|
228
173
|
|
229
174
|
sig do
|
@@ -271,7 +216,9 @@ module Dependabot
|
|
271
216
|
.returns(T::Array[Dependabot::Package::PackageRelease])
|
272
217
|
end
|
273
218
|
def possible_releases(filter_ignored: true)
|
274
|
-
releases = possible_previous_releases.reject
|
219
|
+
releases = possible_previous_releases.reject do |r|
|
220
|
+
r.details["deprecated"]
|
221
|
+
end
|
275
222
|
|
276
223
|
return filter_releases(releases) if filter_ignored
|
277
224
|
|
@@ -298,13 +245,13 @@ module Dependabot
|
|
298
245
|
sig { returns(T::Array[[Dependabot::Version, T::Hash[String, T.nilable(String)]]]) }
|
299
246
|
def possible_previous_versions_with_details
|
300
247
|
possible_previous_releases.map do |r|
|
301
|
-
[r.version,
|
248
|
+
[r.version, r.details]
|
302
249
|
end
|
303
250
|
end
|
304
251
|
|
305
252
|
sig { override.returns(T::Boolean) }
|
306
253
|
def cooldown_enabled?
|
307
|
-
|
254
|
+
true
|
308
255
|
end
|
309
256
|
|
310
257
|
private
|
@@ -325,8 +272,11 @@ module Dependabot
|
|
325
272
|
!!package_details&.releases&.any?
|
326
273
|
end
|
327
274
|
|
328
|
-
sig
|
329
|
-
|
275
|
+
sig do
|
276
|
+
params(cooldown: T::Boolean)
|
277
|
+
.returns(T.nilable(Dependabot::Package::PackageRelease))
|
278
|
+
end
|
279
|
+
def version_from_dist_tags(cooldown: false) # rubocop:disable Metrics/PerceivedComplexity
|
330
280
|
dist_tags = package_details&.dist_tags
|
331
281
|
return nil unless dist_tags
|
332
282
|
|
@@ -334,20 +284,26 @@ module Dependabot
|
|
334
284
|
.find { |r| dist_tags.include?(r[:requirement]) }
|
335
285
|
&.fetch(:requirement)
|
336
286
|
|
337
|
-
|
287
|
+
# For cooldown filtering, use filtered releases
|
288
|
+
releases = available_versions
|
338
289
|
|
339
|
-
releases = filter_by_cooldown(releases) if releases
|
290
|
+
releases = filter_by_cooldown(releases) if cooldown && releases
|
340
291
|
|
341
292
|
if dist_tag_req
|
342
293
|
release = find_dist_tag_release(dist_tag_req, releases)
|
343
|
-
return release
|
294
|
+
return release unless release&.version && yanked_version?(release.version)
|
344
295
|
end
|
345
296
|
|
346
|
-
|
297
|
+
return nil unless dist_tags["latest"]
|
347
298
|
|
348
|
-
|
299
|
+
latest_version = Version.new(dist_tags["latest"])
|
349
300
|
|
350
|
-
|
301
|
+
if wants_latest_dist_tag?(latest_version)
|
302
|
+
# Find the release object for this version, even if deprecated
|
303
|
+
releases = possible_previous_releases
|
304
|
+
releases = filter_by_cooldown(releases) if cooldown
|
305
|
+
return releases.find { |r| r.version == latest_version }
|
306
|
+
end
|
351
307
|
|
352
308
|
nil
|
353
309
|
end
|
@@ -440,528 +396,20 @@ module Dependabot
|
|
440
396
|
def yanked_version?(version)
|
441
397
|
package_fetcher.yanked?(version)
|
442
398
|
end
|
443
|
-
end
|
444
|
-
|
445
|
-
class LatestVersionFinder # rubocop:disable Metrics/ClassLength
|
446
|
-
extend T::Sig
|
447
399
|
|
448
400
|
sig do
|
449
|
-
params(
|
450
|
-
|
451
|
-
dependency_files: T::Array[Dependabot::DependencyFile],
|
452
|
-
credentials: T::Array[Dependabot::Credential],
|
453
|
-
ignored_versions: T::Array[String],
|
454
|
-
security_advisories: T::Array[Dependabot::SecurityAdvisory],
|
455
|
-
raise_on_ignored: T::Boolean
|
456
|
-
).void
|
457
|
-
end
|
458
|
-
def initialize(
|
459
|
-
dependency:,
|
460
|
-
dependency_files:,
|
461
|
-
credentials:,
|
462
|
-
ignored_versions:,
|
463
|
-
security_advisories:,
|
464
|
-
raise_on_ignored: false
|
465
|
-
)
|
466
|
-
@dependency = dependency
|
467
|
-
@credentials = credentials
|
468
|
-
@dependency_files = dependency_files
|
469
|
-
@ignored_versions = ignored_versions
|
470
|
-
@raise_on_ignored = raise_on_ignored
|
471
|
-
@security_advisories = security_advisories
|
472
|
-
|
473
|
-
@possible_previous_versions_with_details = T.let(nil, T.nilable(T::Array[T::Array[T.untyped]]))
|
474
|
-
@yanked = T.let({}, T::Hash[Version, T.nilable(T::Boolean)])
|
475
|
-
@npm_details = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
|
476
|
-
@registry_finder = T.let(nil, T.nilable(Package::RegistryFinder))
|
477
|
-
@version_endpoint_working = T.let(nil, T.nilable(T::Boolean))
|
478
|
-
end
|
479
|
-
|
480
|
-
sig { returns(T.nilable(Version)) }
|
481
|
-
def latest_version_from_registry
|
482
|
-
return unless valid_npm_details?
|
483
|
-
return version_from_dist_tags if version_from_dist_tags
|
484
|
-
return if specified_dist_tag_requirement?
|
485
|
-
|
486
|
-
possible_versions.find { |v| !yanked?(v) }
|
487
|
-
rescue Excon::Error::Socket, Excon::Error::Timeout, RegistryError
|
488
|
-
raise if dependency_registry == "registry.npmjs.org"
|
489
|
-
# Custom registries can be flaky. We don't want to make that
|
490
|
-
# our problem, so we quietly return `nil` here.
|
491
|
-
end
|
492
|
-
|
493
|
-
sig { returns(T.nilable(Version)) }
|
494
|
-
def latest_version_with_no_unlock
|
495
|
-
return unless valid_npm_details?
|
496
|
-
return version_from_dist_tags if specified_dist_tag_requirement?
|
497
|
-
|
498
|
-
in_range_versions = filter_out_of_range_versions(possible_versions)
|
499
|
-
in_range_versions.find { |version| !yanked?(version) }
|
500
|
-
rescue Excon::Error::Socket, Excon::Error::Timeout
|
501
|
-
raise if dependency_registry == "registry.npmjs.org"
|
502
|
-
# Sometimes custom registries are flaky. We don't want to make that
|
503
|
-
# our problem, so we quietly return `nil` here.
|
504
|
-
end
|
505
|
-
|
506
|
-
sig { returns(T.nilable(Version)) }
|
507
|
-
def lowest_security_fix_version
|
508
|
-
return unless valid_npm_details?
|
509
|
-
|
510
|
-
secure_versions =
|
511
|
-
if specified_dist_tag_requirement?
|
512
|
-
[version_from_dist_tags].compact
|
513
|
-
else
|
514
|
-
possible_versions(filter_ignored: false)
|
515
|
-
end
|
516
|
-
|
517
|
-
secure_versions = Dependabot::UpdateCheckers::VersionFilters
|
518
|
-
.filter_vulnerable_versions(
|
519
|
-
secure_versions,
|
520
|
-
security_advisories
|
521
|
-
)
|
522
|
-
secure_versions = filter_ignored_versions(secure_versions)
|
523
|
-
secure_versions = filter_lower_versions(secure_versions)
|
524
|
-
|
525
|
-
secure_versions.reverse.find { |version| !yanked?(version) }
|
526
|
-
rescue Excon::Error::Socket, Excon::Error::Timeout
|
527
|
-
raise if dependency_registry == "registry.npmjs.org"
|
528
|
-
# Sometimes custom registries are flaky. We don't want to make that
|
529
|
-
# our problem, so we quietly return `nil` here.
|
530
|
-
end
|
531
|
-
|
532
|
-
sig { returns(T::Array[T::Array[T.untyped]]) }
|
533
|
-
def possible_previous_versions_with_details # rubocop:disable Metrics/PerceivedComplexity
|
534
|
-
return @possible_previous_versions_with_details if @possible_previous_versions_with_details
|
535
|
-
|
536
|
-
@possible_previous_versions_with_details =
|
537
|
-
npm_details&.fetch("versions", {})
|
538
|
-
&.transform_keys { |k| version_class.new(k) }
|
539
|
-
&.reject do |v, _|
|
540
|
-
v.prerelease? && !related_to_current_pre?(v)
|
541
|
-
end&.sort_by(&:first)&.reverse
|
542
|
-
@possible_previous_versions_with_details
|
543
|
-
end
|
544
|
-
|
545
|
-
sig do
|
546
|
-
params(filter_ignored: T::Boolean)
|
547
|
-
.returns(T::Array[T::Array[T.untyped]])
|
548
|
-
end
|
549
|
-
def possible_versions_with_details(filter_ignored: true)
|
550
|
-
versions = possible_previous_versions_with_details
|
551
|
-
.reject { |_, details| details["deprecated"] }
|
552
|
-
|
553
|
-
return filter_ignored_versions(versions) if filter_ignored
|
554
|
-
|
555
|
-
versions
|
556
|
-
end
|
557
|
-
|
558
|
-
sig do
|
559
|
-
params(filter_ignored: T::Boolean)
|
560
|
-
.returns(T::Array[Version])
|
561
|
-
end
|
562
|
-
def possible_versions(filter_ignored: true)
|
563
|
-
possible_versions_with_details(filter_ignored: filter_ignored)
|
564
|
-
.map(&:first)
|
565
|
-
end
|
566
|
-
|
567
|
-
private
|
568
|
-
|
569
|
-
sig { returns(Dependabot::Dependency) }
|
570
|
-
attr_reader :dependency
|
571
|
-
sig { returns(T::Array[Dependabot::Credential]) }
|
572
|
-
attr_reader :credentials
|
573
|
-
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
574
|
-
attr_reader :dependency_files
|
575
|
-
sig { returns(T::Array[String]) }
|
576
|
-
attr_reader :ignored_versions
|
577
|
-
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
578
|
-
attr_reader :security_advisories
|
579
|
-
|
580
|
-
sig { returns(T::Boolean) }
|
581
|
-
def valid_npm_details?
|
582
|
-
!npm_details&.fetch("dist-tags", nil).nil?
|
583
|
-
end
|
584
|
-
|
585
|
-
sig { params(versions_array: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
|
586
|
-
def filter_ignored_versions(versions_array)
|
587
|
-
filtered = versions_array.reject do |v, _|
|
588
|
-
ignore_requirements.any? { |r| r.satisfied_by?(v) }
|
589
|
-
end
|
590
|
-
|
591
|
-
if @raise_on_ignored && filter_lower_versions(filtered).empty? && filter_lower_versions(versions_array).any?
|
592
|
-
raise AllVersionsIgnored
|
593
|
-
end
|
594
|
-
|
595
|
-
if versions_array.count > filtered.count
|
596
|
-
diff = versions_array.count - filtered.count
|
597
|
-
Dependabot.logger.info("Filtered out #{diff} ignored versions")
|
598
|
-
end
|
599
|
-
|
600
|
-
filtered
|
401
|
+
params(releases: T::Array[Dependabot::Package::PackageRelease])
|
402
|
+
.returns(T::Array[Dependabot::Package::PackageRelease])
|
601
403
|
end
|
602
|
-
|
603
|
-
sig { params(versions_array: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
|
604
|
-
def filter_out_of_range_versions(versions_array)
|
404
|
+
def filter_out_of_range_versions(releases)
|
605
405
|
reqs = dependency.requirements.filter_map do |r|
|
606
406
|
NpmAndYarn::Requirement.requirements_array(r.fetch(:requirement))
|
607
407
|
end
|
608
408
|
|
609
|
-
|
610
|
-
|
611
|
-
end
|
612
|
-
|
613
|
-
sig { params(versions_array: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
|
614
|
-
def filter_lower_versions(versions_array)
|
615
|
-
return versions_array unless dependency.numeric_version
|
616
|
-
|
617
|
-
versions_array
|
618
|
-
.select { |version, _| version > dependency.numeric_version }
|
619
|
-
end
|
620
|
-
|
621
|
-
sig { returns(T.nilable(Version)) }
|
622
|
-
def version_from_dist_tags
|
623
|
-
details = npm_details
|
624
|
-
|
625
|
-
return nil unless details
|
626
|
-
|
627
|
-
dist_tags = details["dist-tags"].keys
|
628
|
-
|
629
|
-
# Check if a dist tag was specified as a requirement. If it was, and
|
630
|
-
# it exists, use it.
|
631
|
-
dist_tag_req = dependency.requirements
|
632
|
-
.find { |r| dist_tags.include?(r[:requirement]) }
|
633
|
-
&.fetch(:requirement)
|
634
|
-
|
635
|
-
if dist_tag_req
|
636
|
-
tag_vers =
|
637
|
-
version_class.new(details["dist-tags"][dist_tag_req])
|
638
|
-
return tag_vers unless yanked?(tag_vers)
|
639
|
-
end
|
640
|
-
|
641
|
-
# Use the latest dist tag unless there's a reason not to
|
642
|
-
return nil unless details["dist-tags"]["latest"]
|
643
|
-
|
644
|
-
latest = version_class.new(details["dist-tags"]["latest"])
|
645
|
-
|
646
|
-
wants_latest_dist_tag?(latest) ? latest : nil
|
647
|
-
end
|
648
|
-
|
649
|
-
sig { params(version: Version).returns(T::Boolean) }
|
650
|
-
def related_to_current_pre?(version)
|
651
|
-
current_version = dependency.numeric_version
|
652
|
-
if current_version&.prerelease? &&
|
653
|
-
current_version.release == version.release
|
654
|
-
return true
|
655
|
-
end
|
656
|
-
|
657
|
-
dependency.requirements.any? do |req|
|
658
|
-
next unless req[:requirement]&.match?(/\d-[A-Za-z]/)
|
659
|
-
|
660
|
-
NpmAndYarn::Requirement
|
661
|
-
.requirements_array(req.fetch(:requirement))
|
662
|
-
.any? do |r|
|
663
|
-
r.requirements.any? { |a| a.last.release == version.release }
|
664
|
-
end
|
665
|
-
rescue Gem::Requirement::BadRequirementError
|
666
|
-
false
|
409
|
+
releases.select do |release|
|
410
|
+
reqs.all? { |r| r.any? { |o| o.satisfied_by?(release.version) } }
|
667
411
|
end
|
668
412
|
end
|
669
|
-
|
670
|
-
sig { returns(T::Boolean) }
|
671
|
-
def specified_dist_tag_requirement?
|
672
|
-
dependency.requirements.any? do |req|
|
673
|
-
next false if req[:requirement].nil?
|
674
|
-
next false unless req[:requirement].match?(/^[A-Za-z]/)
|
675
|
-
|
676
|
-
!req[:requirement].match?(/^v\d/i)
|
677
|
-
end
|
678
|
-
end
|
679
|
-
|
680
|
-
sig { params(latest_version: Version).returns(T::Boolean) }
|
681
|
-
def wants_latest_dist_tag?(latest_version)
|
682
|
-
ver = latest_version
|
683
|
-
return false if related_to_current_pre?(ver) ^ ver.prerelease?
|
684
|
-
return false if current_version_greater_than?(ver)
|
685
|
-
return false if current_requirement_greater_than?(ver)
|
686
|
-
return false if ignore_requirements.any? { |r| r.satisfied_by?(ver) }
|
687
|
-
return false if yanked?(ver)
|
688
|
-
|
689
|
-
true
|
690
|
-
end
|
691
|
-
|
692
|
-
sig { params(version: Version).returns(T::Boolean) }
|
693
|
-
def current_version_greater_than?(version)
|
694
|
-
return false unless dependency.numeric_version
|
695
|
-
|
696
|
-
T.must(dependency.numeric_version) > version
|
697
|
-
end
|
698
|
-
|
699
|
-
sig { params(version: Version).returns(T::Boolean) }
|
700
|
-
def current_requirement_greater_than?(version)
|
701
|
-
dependency.requirements.any? do |req|
|
702
|
-
next false unless req[:requirement]
|
703
|
-
|
704
|
-
req_version = req[:requirement].sub(/^\^|~|>=?/, "")
|
705
|
-
next false unless version_class.correct?(req_version)
|
706
|
-
|
707
|
-
version_class.new(req_version) > version
|
708
|
-
end
|
709
|
-
end
|
710
|
-
|
711
|
-
sig { params(version: Version).returns(T::Boolean) }
|
712
|
-
def yanked?(version)
|
713
|
-
return @yanked[version] || false if @yanked.key?(version)
|
714
|
-
|
715
|
-
@yanked[version] =
|
716
|
-
begin
|
717
|
-
if dependency_registry == "registry.npmjs.org"
|
718
|
-
status = Dependabot::RegistryClient.head(
|
719
|
-
url: registry_finder.tarball_url(version),
|
720
|
-
headers: registry_auth_headers
|
721
|
-
).status
|
722
|
-
else
|
723
|
-
status = Dependabot::RegistryClient.get(
|
724
|
-
url: dependency_url + "/#{version}",
|
725
|
-
headers: registry_auth_headers
|
726
|
-
).status
|
727
|
-
|
728
|
-
if status == 404
|
729
|
-
# Some registries don't handle escaped package names properly
|
730
|
-
status = Dependabot::RegistryClient.get(
|
731
|
-
url: dependency_url.gsub("%2F", "/") + "/#{version}",
|
732
|
-
headers: registry_auth_headers
|
733
|
-
).status
|
734
|
-
end
|
735
|
-
end
|
736
|
-
|
737
|
-
version_not_found = status == 404
|
738
|
-
version_not_found && version_endpoint_working?
|
739
|
-
rescue Excon::Error::Timeout, Excon::Error::Socket
|
740
|
-
# Give the benefit of the doubt if the registry is playing up
|
741
|
-
false
|
742
|
-
end
|
743
|
-
|
744
|
-
@yanked[version] || false
|
745
|
-
end
|
746
|
-
|
747
|
-
sig { returns(T.nilable(T::Boolean)) }
|
748
|
-
def version_endpoint_working?
|
749
|
-
return true if dependency_registry == "registry.npmjs.org"
|
750
|
-
|
751
|
-
return @version_endpoint_working if @version_endpoint_working
|
752
|
-
|
753
|
-
@version_endpoint_working =
|
754
|
-
begin
|
755
|
-
Dependabot::RegistryClient.get(
|
756
|
-
url: dependency_url + "/latest",
|
757
|
-
headers: registry_auth_headers
|
758
|
-
).status < 400
|
759
|
-
rescue Excon::Error::Timeout, Excon::Error::Socket
|
760
|
-
# Give the benefit of the doubt if the registry is playing up
|
761
|
-
true
|
762
|
-
end
|
763
|
-
@version_endpoint_working
|
764
|
-
end
|
765
|
-
|
766
|
-
sig { returns(T.nilable(T::Hash[String, T.untyped])) }
|
767
|
-
def npm_details
|
768
|
-
return @npm_details if @npm_details
|
769
|
-
|
770
|
-
@npm_details = fetch_npm_details
|
771
|
-
end
|
772
|
-
|
773
|
-
sig { returns(T.nilable(T::Hash[String, T.untyped])) }
|
774
|
-
def fetch_npm_details
|
775
|
-
npm_response = fetch_npm_response
|
776
|
-
|
777
|
-
return nil unless npm_response
|
778
|
-
|
779
|
-
check_npm_response(npm_response)
|
780
|
-
JSON.parse(npm_response.body)
|
781
|
-
rescue JSON::ParserError,
|
782
|
-
Excon::Error::Timeout,
|
783
|
-
Excon::Error::Socket,
|
784
|
-
RegistryError => e
|
785
|
-
if git_dependency?
|
786
|
-
nil
|
787
|
-
else
|
788
|
-
raise_npm_details_error(e)
|
789
|
-
end
|
790
|
-
end
|
791
|
-
|
792
|
-
sig { returns(T.nilable(Excon::Response)) }
|
793
|
-
def fetch_npm_response
|
794
|
-
response = Dependabot::RegistryClient.get(
|
795
|
-
url: dependency_url,
|
796
|
-
headers: registry_auth_headers
|
797
|
-
)
|
798
|
-
return response unless response.status == 500
|
799
|
-
return response unless registry_auth_headers["Authorization"]
|
800
|
-
|
801
|
-
auth = registry_auth_headers["Authorization"]
|
802
|
-
return response unless auth&.start_with?("Basic")
|
803
|
-
|
804
|
-
decoded_token = Base64.decode64(auth.gsub("Basic ", ""))
|
805
|
-
return unless decoded_token.include?(":")
|
806
|
-
|
807
|
-
username, password = decoded_token.split(":")
|
808
|
-
Dependabot::RegistryClient.get(
|
809
|
-
url: dependency_url,
|
810
|
-
options: {
|
811
|
-
user: username,
|
812
|
-
password: password
|
813
|
-
}
|
814
|
-
)
|
815
|
-
rescue URI::InvalidURIError => e
|
816
|
-
raise DependencyFileNotResolvable, e.message
|
817
|
-
end
|
818
|
-
|
819
|
-
sig { params(npm_response: Excon::Response).void }
|
820
|
-
def check_npm_response(npm_response)
|
821
|
-
return if git_dependency?
|
822
|
-
|
823
|
-
if private_dependency_not_reachable?(npm_response)
|
824
|
-
raise PrivateSourceAuthenticationFailure, dependency_registry
|
825
|
-
end
|
826
|
-
|
827
|
-
# handles scenario when private registry returns a server error 5xx
|
828
|
-
if private_dependency_server_error?(npm_response)
|
829
|
-
msg = "Server error #{npm_response.status} returned while accessing registry" \
|
830
|
-
" #{dependency_registry}."
|
831
|
-
raise DependencyFileNotResolvable, msg
|
832
|
-
end
|
833
|
-
|
834
|
-
status = npm_response.status
|
835
|
-
|
836
|
-
# handles issue when status 200 is returned from registry but with an invalid JSON object
|
837
|
-
if status.to_s.start_with?("2") && response_invalid_json?(npm_response)
|
838
|
-
msg = "Invalid JSON object returned from registry #{dependency_registry}."
|
839
|
-
Dependabot.logger.warn("#{msg} Response body (truncated) : #{npm_response.body[0..500]}...")
|
840
|
-
raise DependencyFileNotResolvable, msg
|
841
|
-
end
|
842
|
-
|
843
|
-
return if status.to_s.start_with?("2")
|
844
|
-
|
845
|
-
# Ignore 404s from the registry for updates where a lockfile doesn't
|
846
|
-
# need to be generated. The 404 won't cause problems later.
|
847
|
-
return if status == 404 && dependency.version.nil?
|
848
|
-
|
849
|
-
msg = "Got #{status} response with body #{npm_response.body}"
|
850
|
-
raise RegistryError.new(status, msg)
|
851
|
-
end
|
852
|
-
|
853
|
-
sig { params(error: Exception).void }
|
854
|
-
def raise_npm_details_error(error)
|
855
|
-
raise if dependency_registry == "registry.npmjs.org"
|
856
|
-
raise unless error.is_a?(Excon::Error::Timeout)
|
857
|
-
|
858
|
-
raise PrivateSourceTimedOut, dependency_registry
|
859
|
-
end
|
860
|
-
|
861
|
-
sig { params(npm_response: Excon::Response).returns(T::Boolean) }
|
862
|
-
def private_dependency_not_reachable?(npm_response)
|
863
|
-
return true if npm_response.body.start_with?(/user ".*?" is not a /)
|
864
|
-
return false unless [401, 402, 403, 404].include?(npm_response.status)
|
865
|
-
|
866
|
-
# Check whether this dependency is (likely to be) private
|
867
|
-
if dependency_registry == "registry.npmjs.org"
|
868
|
-
return false unless dependency.name.start_with?("@")
|
869
|
-
|
870
|
-
web_response = Dependabot::RegistryClient.get(url: "https://www.npmjs.com/package/#{dependency.name}")
|
871
|
-
# NOTE: returns 429 when the login page is rate limited
|
872
|
-
return web_response.body.include?("Forgot password?") ||
|
873
|
-
web_response.status == 429
|
874
|
-
end
|
875
|
-
|
876
|
-
true
|
877
|
-
end
|
878
|
-
|
879
|
-
sig { params(npm_response: Excon::Response).returns(T::Boolean) }
|
880
|
-
def private_dependency_server_error?(npm_response)
|
881
|
-
if [500, 501, 502, 503].include?(npm_response.status)
|
882
|
-
Dependabot.logger.warn("#{dependency_registry} returned code #{npm_response.status} with " \
|
883
|
-
"body #{npm_response.body}.")
|
884
|
-
return true
|
885
|
-
end
|
886
|
-
false
|
887
|
-
end
|
888
|
-
|
889
|
-
sig { params(npm_response: Excon::Response).returns(T::Boolean) }
|
890
|
-
def response_invalid_json?(npm_response)
|
891
|
-
result = JSON.parse(npm_response.body)
|
892
|
-
result.is_a?(Hash) || result.is_a?(Array)
|
893
|
-
false
|
894
|
-
rescue JSON::ParserError, TypeError
|
895
|
-
true
|
896
|
-
end
|
897
|
-
|
898
|
-
sig { returns(String) }
|
899
|
-
def dependency_url
|
900
|
-
registry_finder.dependency_url
|
901
|
-
end
|
902
|
-
|
903
|
-
sig { returns(String) }
|
904
|
-
def dependency_registry
|
905
|
-
registry_finder.registry
|
906
|
-
end
|
907
|
-
|
908
|
-
sig { returns(T::Hash[String, String]) }
|
909
|
-
def registry_auth_headers
|
910
|
-
registry_finder.auth_headers
|
911
|
-
end
|
912
|
-
|
913
|
-
sig { returns(Package::RegistryFinder) }
|
914
|
-
def registry_finder
|
915
|
-
return @registry_finder if @registry_finder
|
916
|
-
|
917
|
-
@registry_finder = Package::RegistryFinder.new(
|
918
|
-
dependency: dependency,
|
919
|
-
credentials: credentials,
|
920
|
-
npmrc_file: npmrc_file,
|
921
|
-
yarnrc_file: yarnrc_file,
|
922
|
-
yarnrc_yml_file: yarnrc_yml_file
|
923
|
-
)
|
924
|
-
@registry_finder
|
925
|
-
end
|
926
|
-
|
927
|
-
sig { returns(T::Array[Dependabot::Requirement]) }
|
928
|
-
def ignore_requirements
|
929
|
-
ignored_versions.flat_map { |req| requirement_class.requirements_array(req) }
|
930
|
-
end
|
931
|
-
|
932
|
-
sig { returns(T.class_of(Version)) }
|
933
|
-
def version_class
|
934
|
-
Dependabot::NpmAndYarn::Version
|
935
|
-
end
|
936
|
-
|
937
|
-
sig { returns(T.class_of(Requirement)) }
|
938
|
-
def requirement_class
|
939
|
-
Dependabot::NpmAndYarn::Requirement
|
940
|
-
end
|
941
|
-
|
942
|
-
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
943
|
-
def npmrc_file
|
944
|
-
dependency_files.find { |f| f.name.end_with?(".npmrc") }
|
945
|
-
end
|
946
|
-
|
947
|
-
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
948
|
-
def yarnrc_file
|
949
|
-
dependency_files.find { |f| f.name.end_with?(".yarnrc") }
|
950
|
-
end
|
951
|
-
|
952
|
-
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
953
|
-
def yarnrc_yml_file
|
954
|
-
dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") }
|
955
|
-
end
|
956
|
-
|
957
|
-
sig { returns(T::Boolean) }
|
958
|
-
def git_dependency?
|
959
|
-
# ignored_version/raise_on_ignored are irrelevant.
|
960
|
-
GitCommitChecker.new(
|
961
|
-
dependency: dependency,
|
962
|
-
credentials: credentials
|
963
|
-
).git_dependency?
|
964
|
-
end
|
965
413
|
end
|
966
414
|
end
|
967
415
|
end
|
@@ -97,7 +97,7 @@ module Dependabot
|
|
97
97
|
dependency_files: T::Array[Dependabot::DependencyFile],
|
98
98
|
credentials: T::Array[Dependabot::Credential],
|
99
99
|
latest_allowable_version: T.nilable(T.any(String, Gem::Version)),
|
100
|
-
latest_version_finder:
|
100
|
+
latest_version_finder: PackageLatestVersionFinder,
|
101
101
|
repo_contents_path: T.nilable(String),
|
102
102
|
dependency_group: T.nilable(Dependabot::DependencyGroup),
|
103
103
|
raise_on_ignored: T::Boolean,
|
@@ -116,11 +116,7 @@ module Dependabot
|
|
116
116
|
@latest_allowable_version = latest_allowable_version
|
117
117
|
@dependency_group = dependency_group
|
118
118
|
|
119
|
-
@latest_version_finder = T.let(
|
120
|
-
{},
|
121
|
-
T::Hash[Dependabot::Dependency, T.any(LatestVersionFinder, PackageLatestVersionFinder)
|
122
|
-
]
|
123
|
-
)
|
119
|
+
@latest_version_finder = T.let({}, T::Hash[Dependabot::Dependency, PackageLatestVersionFinder])
|
124
120
|
@latest_version_finder[dependency] = latest_version_finder
|
125
121
|
@repo_contents_path = repo_contents_path
|
126
122
|
@raise_on_ignored = raise_on_ignored
|
@@ -228,34 +224,18 @@ module Dependabot
|
|
228
224
|
sig { returns(T::Boolean) }
|
229
225
|
attr_reader :raise_on_ignored
|
230
226
|
|
231
|
-
sig { params(dep: Dependabot::Dependency) .returns(
|
227
|
+
sig { params(dep: Dependabot::Dependency) .returns(PackageLatestVersionFinder) }
|
232
228
|
def latest_version_finder(dep)
|
233
229
|
@latest_version_finder[dep] ||=
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
)
|
244
|
-
else
|
245
|
-
LatestVersionFinder.new(
|
246
|
-
dependency: dep,
|
247
|
-
credentials: credentials,
|
248
|
-
dependency_files: dependency_files,
|
249
|
-
ignored_versions: [],
|
250
|
-
security_advisories: [],
|
251
|
-
raise_on_ignored: raise_on_ignored
|
252
|
-
)
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
sig { returns(T::Boolean) }
|
257
|
-
def enable_cooldown?
|
258
|
-
Dependabot::Experiments.enabled?(:enable_cooldown_for_npm_and_yarn)
|
230
|
+
PackageLatestVersionFinder.new(
|
231
|
+
dependency: dep,
|
232
|
+
dependency_files: dependency_files,
|
233
|
+
credentials: credentials,
|
234
|
+
cooldown_options: update_cooldown,
|
235
|
+
ignored_versions: [],
|
236
|
+
security_advisories: [],
|
237
|
+
raise_on_ignored: raise_on_ignored
|
238
|
+
)
|
259
239
|
end
|
260
240
|
|
261
241
|
# rubocop:disable Metrics/PerceivedComplexity
|
@@ -49,9 +49,7 @@ module Dependabot
|
|
49
49
|
@latest_version_for_git_dependency = T.let(nil, T.nilable(T.any(String, Gem::Version)))
|
50
50
|
@latest_released_version = T.let(nil, T.nilable(Gem::Version))
|
51
51
|
@latest_version_details = T.let(nil, T.nilable(T::Hash[Symbol, T.untyped]))
|
52
|
-
@latest_version_finder = T.let(
|
53
|
-
nil, T.nilable(T.any(LatestVersionFinder, PackageLatestVersionFinder))
|
54
|
-
)
|
52
|
+
@latest_version_finder = T.let(nil, T.nilable(PackageLatestVersionFinder))
|
55
53
|
@version_resolver = T.let(nil, T.nilable(VersionResolver))
|
56
54
|
@subdependency_version_resolver = T.let(nil, T.nilable(SubdependencyVersionResolver))
|
57
55
|
@library = T.let(nil, T.nilable(T::Boolean))
|
@@ -138,9 +136,7 @@ module Dependabot
|
|
138
136
|
sig { override.returns(T.nilable(T.any(String, Dependabot::Version))) }
|
139
137
|
def latest_resolvable_version_with_no_unlock
|
140
138
|
unless dependency.top_level?
|
141
|
-
|
142
|
-
return T.cast(latest_resolvable_version,
|
143
|
-
T.nilable(T.any(String, Dependabot::Version)))
|
139
|
+
return T.cast(latest_resolvable_version, T.nilable(T.any(String, Dependabot::Version)))
|
144
140
|
end
|
145
141
|
|
146
142
|
return latest_resolvable_version_with_no_unlock_for_git_dependency if git_dependency?
|
@@ -411,34 +407,17 @@ module Dependabot
|
|
411
407
|
end
|
412
408
|
end
|
413
409
|
|
414
|
-
sig { returns(
|
410
|
+
sig { returns(PackageLatestVersionFinder) }
|
415
411
|
def latest_version_finder
|
416
|
-
@latest_version_finder ||=
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
cooldown_options: @update_cooldown
|
426
|
-
)
|
427
|
-
else
|
428
|
-
LatestVersionFinder.new(
|
429
|
-
dependency: dependency,
|
430
|
-
credentials: credentials,
|
431
|
-
dependency_files: dependency_files,
|
432
|
-
ignored_versions: ignored_versions,
|
433
|
-
raise_on_ignored: raise_on_ignored,
|
434
|
-
security_advisories: security_advisories
|
435
|
-
)
|
436
|
-
end
|
437
|
-
end
|
438
|
-
|
439
|
-
sig { returns(T::Boolean) }
|
440
|
-
def enable_cooldown?
|
441
|
-
Dependabot::Experiments.enabled?(:enable_cooldown_for_npm_and_yarn)
|
412
|
+
@latest_version_finder ||= PackageLatestVersionFinder.new(
|
413
|
+
dependency: dependency,
|
414
|
+
credentials: credentials,
|
415
|
+
dependency_files: dependency_files,
|
416
|
+
ignored_versions: ignored_versions,
|
417
|
+
raise_on_ignored: raise_on_ignored,
|
418
|
+
security_advisories: security_advisories,
|
419
|
+
cooldown_options: @update_cooldown
|
420
|
+
)
|
442
421
|
end
|
443
422
|
|
444
423
|
sig { returns(VersionResolver) }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-npm_and_yarn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.322.1
|
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.322.1
|
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.322.1
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: debug
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -356,7 +356,7 @@ licenses:
|
|
356
356
|
- MIT
|
357
357
|
metadata:
|
358
358
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
359
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
359
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.322.1
|
360
360
|
rdoc_options: []
|
361
361
|
require_paths:
|
362
362
|
- lib
|