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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a283fe636a43e4eda5f91a0d40e969f18caf75013ce7b7b697a2abdb97d0d001
4
- data.tar.gz: 2f3a64b55706976119011580025b65b199bc3e2e2e1fd7c54dd1f6506414fa9d
3
+ metadata.gz: 82092e446c633ecd1762c1f5679fd4f10e1f2c17f6c2b054f0a8385bfc1c7faa
4
+ data.tar.gz: 0ee19ced17a63790ee72987906b440808511235ab7de80edbd4c5c507b203cee
5
5
  SHA512:
6
- metadata.gz: fc4b49d40d434b07108c8e858d1af23c6b9c260a1f022ea5d4350a9b5486635289b012fb058cb6058dad7f205205e27ade4a9adf788287afd54458484fc09d77
7
- data.tar.gz: f60d5b3bc19476bf60b85203a7441f694e557f1fe9b9419dfce2369fc271e1e4fad7f76a78f0885453c8aa0e98512ff06af816292f25c6e06a8a7fe89466e5dd
6
+ metadata.gz: 528addbc67e52c6169e418cb9ea3aa12699f44cca19f947c3e3f6acc2551b514f95d02b6b047b46176e2c918dae9212b9e32c2d1133f40f669f7604822b495d4
7
+ data.tar.gz: f1351e33bccd4850928dbaa03c268b6bef43090d77046c86e4676ddc3d1cfd4bb86abc26dcbfc87c6a5e6bc44f0874b097607c55126867d94bb154a3f73f5b5e
@@ -508,7 +508,7 @@ module Dependabot
508
508
  type: "git",
509
509
  url: "https://#{host}/#{details['username']}/#{details['repo']}",
510
510
  branch: nil,
511
- ref: details["ref"] || "master"
511
+ ref: details["ref"]
512
512
  }
513
513
  end
514
514
 
@@ -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: deprecated ? true : false,
182
- yanked_reason: deprecated.is_a?(String) ? deprecated : nil,
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
- with_custom_registry_rescue do
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
- super
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
- super
123
- end
124
- end
118
+ filtered_releases = filter_by_cooldown(possible_releases)
125
119
 
126
- sig do
127
- override
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
- # Apply lazy filtering for yanked versions (min or max logic)
204
- secure_versions = lazy_filter_yanked_versions_by_min_max(secure_versions, check_max: false)
205
-
206
- # Return the lowest non-yanked version
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
- filtered = releases.reject do |release|
162
+ releases.reject do |release|
217
163
  release.version.prerelease? && !related_to_current_pre?(release.version)
218
164
  end
165
+ end
219
166
 
220
- if releases.count > filtered.count
221
- Dependabot.logger.info(
222
- "Filtered out #{releases.count - filtered.count} unrelated pre-release versions"
223
- )
224
- end
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(&:yanked?)
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, { "deprecated" => r.yanked? ? "yanked" : nil }]
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
- Dependabot::Experiments.enabled?(:enable_cooldown_for_npm_and_yarn)
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 { returns(T.nilable(Dependabot::Package::PackageRelease)) }
329
- def version_from_dist_tags # rubocop:disable Metrics/PerceivedComplexity
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
- releases = package_details&.releases
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 if release && !release.yanked?
294
+ return release unless release&.version && yanked_version?(release.version)
344
295
  end
345
296
 
346
- latest_release = find_dist_tag_release("latest", releases)
297
+ return nil unless dist_tags["latest"]
347
298
 
348
- return nil unless latest_release
299
+ latest_version = Version.new(dist_tags["latest"])
349
300
 
350
- return latest_release if wants_latest_dist_tag?(latest_release.version) && !latest_release.yanked?
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
- dependency: Dependabot::Dependency,
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
- versions_array
610
- .select { |v| reqs.all? { |r| r.any? { |o| o.satisfied_by?(v) } } }
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: T.any(LatestVersionFinder, PackageLatestVersionFinder),
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(T.any(LatestVersionFinder, PackageLatestVersionFinder)) }
227
+ sig { params(dep: Dependabot::Dependency) .returns(PackageLatestVersionFinder) }
232
228
  def latest_version_finder(dep)
233
229
  @latest_version_finder[dep] ||=
234
- if enable_cooldown?
235
- PackageLatestVersionFinder.new(
236
- dependency: dep,
237
- dependency_files: dependency_files,
238
- credentials: credentials,
239
- cooldown_options: update_cooldown,
240
- ignored_versions: [],
241
- security_advisories: [],
242
- raise_on_ignored: raise_on_ignored
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
- # TODO: We should use `Dependabot::Version` everywhere
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(T.any(LatestVersionFinder, PackageLatestVersionFinder)) }
410
+ sig { returns(PackageLatestVersionFinder) }
415
411
  def latest_version_finder
416
- @latest_version_finder ||=
417
- if enable_cooldown?
418
- PackageLatestVersionFinder.new(
419
- dependency: dependency,
420
- credentials: credentials,
421
- dependency_files: dependency_files,
422
- ignored_versions: ignored_versions,
423
- raise_on_ignored: raise_on_ignored,
424
- security_advisories: security_advisories,
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.321.3
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.321.3
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.321.3
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.321.3
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