dependabot-bun 0.321.2 → 0.322.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: b7b25cf24328ea21650667fde71b0ff8c13bcbe6315e5955befd245ce53c68a1
4
- data.tar.gz: 56c89a83b706722c9179061c677a9877974e23ab3a45928130a47889bde2fdd4
3
+ metadata.gz: 46499cefe8115a9506d33a7246f6c5cd16519b1be78532117baf9df95d4fd07b
4
+ data.tar.gz: 7de2f41d26d85efda5d73ee4ecc752d134ad26237acb463a6af11a620794e9f5
5
5
  SHA512:
6
- metadata.gz: 4e266a904710e66a2e87767c19e4b74113d9ee927361f447597d22aec9b2c5dd5d487a86e15d86a7c494216ff6911164a5f47c28c64025fc7066fae00ca39372
7
- data.tar.gz: 506d2f229faea438d967e62741329688afc9ad182234119fcf3c57283d021eb4f57b0f78ab92b3cc83d4774db75bd6383c73a322c58f3d2394d4f81ec292eef7
6
+ metadata.gz: f1bec3ed1b2e310cbae6cfb7e4ca995d689b53d6af94f41f97cc21b38bb5ba654ee27342fd39aa4ff3772856ef7af6016d9ad9327fac54d7631d338a953ac52a
7
+ data.tar.gz: fb33aeb0a072aa7ade8c6b10f179a0a66c31dc2d8eb1bed511381a4e0ddb1de27bc8a5ae13b11650d7aad63e3665d417cf66fce3f4617b9ebe891d5888a37e83
@@ -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),
@@ -74,12 +74,14 @@ module Dependabot
74
74
  override.params(language_version: T.nilable(T.any(String, Dependabot::Version)))
75
75
  .returns(T.nilable(Dependabot::Version))
76
76
  end
77
- def latest_version_with_no_unlock(language_version: nil)
77
+ def latest_version_with_no_unlock(language_version: nil) # rubocop:disable Lint/UnusedMethodArgument
78
78
  with_custom_registry_rescue do
79
79
  return unless valid_npm_details?
80
80
  return version_from_dist_tags&.version if specified_dist_tag_requirement?
81
81
 
82
- super
82
+ releases = possible_releases
83
+ in_range_versions = filter_out_of_range_versions(releases)
84
+ in_range_versions.find { |r| !yanked_version?(r.version) }&.version
83
85
  end
84
86
  end
85
87
 
@@ -96,7 +98,7 @@ module Dependabot
96
98
  params(language_version: T.nilable(T.any(String, Dependabot::Version)))
97
99
  .returns(T.nilable(Dependabot::Version))
98
100
  end
99
- def fetch_latest_version(language_version: nil)
101
+ def fetch_latest_version(language_version: nil) # rubocop:disable Lint/UnusedMethodArgument
100
102
  with_custom_registry_rescue do
101
103
  return unless valid_npm_details?
102
104
 
@@ -105,7 +107,7 @@ module Dependabot
105
107
 
106
108
  return if specified_dist_tag_requirement?
107
109
 
108
- super
110
+ possible_releases.find { |r| !yanked_version?(r.version) }&.version
109
111
  end
110
112
  end
111
113
 
@@ -114,65 +116,16 @@ module Dependabot
114
116
  .params(language_version: T.nilable(T.any(String, Dependabot::Version)))
115
117
  .returns(T.nilable(Dependabot::Version))
116
118
  end
117
- def fetch_latest_version_with_no_unlock(language_version: nil)
119
+ def fetch_latest_version_with_no_unlock(language_version: nil) # rubocop:disable Lint/UnusedMethodArgument
118
120
  with_custom_registry_rescue do
119
121
  return unless valid_npm_details?
120
122
  return version_from_dist_tags&.version if specified_dist_tag_requirement?
121
123
 
122
- super
123
- end
124
- end
125
-
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)
124
+ releases = possible_releases
134
125
 
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
- )
126
+ in_range_versions = filter_out_of_range_versions(releases)
127
+ in_range_versions.find { |r| !yanked_version?(r.version) }&.version
141
128
  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
129
  end
177
130
 
178
131
  sig do
@@ -200,11 +153,10 @@ module Dependabot
200
153
  secure_versions = filter_ignored_versions(secure_versions)
201
154
  secure_versions = filter_lower_versions(secure_versions)
202
155
 
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
156
+ # Find first non-yanked version
157
+ secure_versions.sort_by(&:version).find do |version|
158
+ !yanked_version?(version.version)
159
+ end&.version
208
160
  end
209
161
  end
210
162
 
@@ -213,17 +165,16 @@ module Dependabot
213
165
  .returns(T::Array[Dependabot::Package::PackageRelease])
214
166
  end
215
167
  def filter_prerelease_versions(releases)
216
- filtered = releases.reject do |release|
168
+ releases.reject do |release|
217
169
  release.version.prerelease? && !related_to_current_pre?(release.version)
218
170
  end
171
+ end
219
172
 
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
173
+ sig do
174
+ override.returns(T.nilable(T::Array[Dependabot::Package::PackageRelease]))
175
+ end
176
+ def available_versions
177
+ possible_releases
227
178
  end
228
179
 
229
180
  sig do
@@ -271,7 +222,9 @@ module Dependabot
271
222
  .returns(T::Array[Dependabot::Package::PackageRelease])
272
223
  end
273
224
  def possible_releases(filter_ignored: true)
274
- releases = possible_previous_releases.reject(&:yanked?)
225
+ releases = possible_previous_releases.reject do |r|
226
+ r.details["deprecated"]
227
+ end
275
228
 
276
229
  return filter_releases(releases) if filter_ignored
277
230
 
@@ -298,13 +251,13 @@ module Dependabot
298
251
  sig { returns(T::Array[[Dependabot::Version, T::Hash[String, T.nilable(String)]]]) }
299
252
  def possible_previous_versions_with_details
300
253
  possible_previous_releases.map do |r|
301
- [r.version, { "deprecated" => r.yanked? ? "yanked" : nil }]
254
+ [r.version, r.details]
302
255
  end
303
256
  end
304
257
 
305
258
  sig { override.returns(T::Boolean) }
306
259
  def cooldown_enabled?
307
- Dependabot::Experiments.enabled?(:enable_cooldown_for_bun)
260
+ true
308
261
  end
309
262
 
310
263
  private
@@ -334,20 +287,24 @@ module Dependabot
334
287
  .find { |r| dist_tags.include?(r[:requirement]) }
335
288
  &.fetch(:requirement)
336
289
 
337
- releases = package_details&.releases
290
+ # For cooldown filtering, use filtered releases
291
+ releases = available_versions
338
292
 
339
293
  releases = filter_by_cooldown(releases) if releases
340
294
 
341
295
  if dist_tag_req
342
296
  release = find_dist_tag_release(dist_tag_req, releases)
343
- return release if release && !release.yanked?
297
+ return release unless release&.version && yanked_version?(release.version)
344
298
  end
345
299
 
346
- latest_release = find_dist_tag_release("latest", releases)
300
+ return nil unless dist_tags["latest"]
347
301
 
348
- return nil unless latest_release
302
+ latest_version = Version.new(dist_tags["latest"])
349
303
 
350
- return latest_release if wants_latest_dist_tag?(latest_release.version) && !latest_release.yanked?
304
+ if wants_latest_dist_tag?(latest_version)
305
+ # Find the release object for this version, even if deprecated
306
+ return possible_previous_releases.find { |r| r.version == latest_version }
307
+ end
351
308
 
352
309
  nil
353
310
  end
@@ -440,515 +397,19 @@ module Dependabot
440
397
  def yanked_version?(version)
441
398
  package_fetcher.yanked?(version)
442
399
  end
443
- end
444
-
445
- class LatestVersionFinder # rubocop:disable Metrics/ClassLength
446
- extend T::Sig
447
-
448
- 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
400
 
545
401
  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
402
+ params(releases: T::Array[Dependabot::Package::PackageRelease])
403
+ .returns(T::Array[Dependabot::Package::PackageRelease])
601
404
  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)
405
+ def filter_out_of_range_versions(releases)
605
406
  reqs = dependency.requirements.filter_map do |r|
606
407
  Bun::Requirement.requirements_array(r.fetch(:requirement))
607
408
  end
608
409
 
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)
410
+ releases.select do |release|
411
+ reqs.all? { |r| r.any? { |o| o.satisfied_by?(release.version) } }
639
412
  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
- Bun::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
667
- end
668
- 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
- )
922
- @registry_finder
923
- end
924
-
925
- sig { returns(T::Array[Dependabot::Requirement]) }
926
- def ignore_requirements
927
- ignored_versions.flat_map { |req| requirement_class.requirements_array(req) }
928
- end
929
-
930
- sig { returns(T.class_of(Version)) }
931
- def version_class
932
- Dependabot::Bun::Version
933
- end
934
-
935
- sig { returns(T.class_of(Requirement)) }
936
- def requirement_class
937
- Dependabot::Bun::Requirement
938
- end
939
-
940
- sig { returns(T.nilable(Dependabot::DependencyFile)) }
941
- def npmrc_file
942
- dependency_files.find { |f| f.name.end_with?(".npmrc") }
943
- end
944
-
945
- sig { returns(T::Boolean) }
946
- def git_dependency?
947
- # ignored_version/raise_on_ignored are irrelevant.
948
- GitCommitChecker.new(
949
- dependency: dependency,
950
- credentials: credentials
951
- ).git_dependency?
952
413
  end
953
414
  end
954
415
  end
@@ -60,7 +60,7 @@ module Dependabot
60
60
  dependency_files: T::Array[Dependabot::DependencyFile],
61
61
  credentials: T::Array[Dependabot::Credential],
62
62
  latest_allowable_version: T.nilable(T.any(String, Gem::Version)),
63
- latest_version_finder: T.any(LatestVersionFinder, PackageLatestVersionFinder),
63
+ latest_version_finder: PackageLatestVersionFinder,
64
64
  repo_contents_path: T.nilable(String),
65
65
  dependency_group: T.nilable(Dependabot::DependencyGroup),
66
66
  raise_on_ignored: T::Boolean,
@@ -79,11 +79,7 @@ module Dependabot
79
79
  @latest_allowable_version = latest_allowable_version
80
80
  @dependency_group = dependency_group
81
81
 
82
- @latest_version_finder = T.let(
83
- {},
84
- T::Hash[Dependabot::Dependency, T.any(LatestVersionFinder, PackageLatestVersionFinder)
85
- ]
86
- )
82
+ @latest_version_finder = T.let({}, T::Hash[Dependabot::Dependency, PackageLatestVersionFinder])
87
83
  @latest_version_finder[dependency] = latest_version_finder
88
84
  @repo_contents_path = repo_contents_path
89
85
  @raise_on_ignored = raise_on_ignored
@@ -189,34 +185,18 @@ module Dependabot
189
185
  sig { returns(T::Boolean) }
190
186
  attr_reader :raise_on_ignored
191
187
 
192
- sig { params(dep: Dependabot::Dependency) .returns(T.any(LatestVersionFinder, PackageLatestVersionFinder)) }
188
+ sig { params(dep: Dependabot::Dependency) .returns(PackageLatestVersionFinder) }
193
189
  def latest_version_finder(dep)
194
190
  @latest_version_finder[dep] ||=
195
- if enable_cooldown?
196
- PackageLatestVersionFinder.new(
197
- dependency: dep,
198
- dependency_files: dependency_files,
199
- credentials: credentials,
200
- cooldown_options: update_cooldown,
201
- ignored_versions: [],
202
- security_advisories: [],
203
- raise_on_ignored: raise_on_ignored
204
- )
205
- else
206
- LatestVersionFinder.new(
207
- dependency: dep,
208
- credentials: credentials,
209
- dependency_files: dependency_files,
210
- ignored_versions: [],
211
- security_advisories: [],
212
- raise_on_ignored: raise_on_ignored
213
- )
214
- end
215
- end
216
-
217
- sig { returns(T::Boolean) }
218
- def enable_cooldown?
219
- Dependabot::Experiments.enabled?(:enable_cooldown_for_npm_and_yarn)
191
+ PackageLatestVersionFinder.new(
192
+ dependency: dep,
193
+ dependency_files: dependency_files,
194
+ credentials: credentials,
195
+ cooldown_options: update_cooldown,
196
+ ignored_versions: [],
197
+ security_advisories: [],
198
+ raise_on_ignored: raise_on_ignored
199
+ )
220
200
  end
221
201
 
222
202
  # rubocop:disable Metrics/PerceivedComplexity
@@ -533,7 +513,11 @@ module Dependabot
533
513
  rescue Gem::Requirement::BadRequirementError
534
514
  false
535
515
  end
536
- end.map(&:first)
516
+ end.map do |versions_with_details| # rubocop:disable Style/MultilineBlockChain
517
+ # Return just the version
518
+ version, = versions_with_details
519
+ version
520
+ end
537
521
  end
538
522
 
539
523
  # rubocop:enable Metrics/PerceivedComplexity
@@ -41,7 +41,7 @@ module Dependabot
41
41
  requirements_update_strategy: nil, dependency_group: nil,
42
42
  update_cooldown: nil, options: {})
43
43
  @latest_version = T.let(nil, T.nilable(T.any(String, Gem::Version)))
44
- @latest_resolvable_version = T.let(nil, T.nilable(T.any(String, Gem::Version)))
44
+ @latest_resolvable_version = T.let(nil, T.nilable(T.any(String, Dependabot::Version)))
45
45
  @updated_requirements = T.let(nil, T.nilable(T::Array[T::Hash[Symbol, T.untyped]]))
46
46
  @vulnerability_audit = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
47
47
  @vulnerable_versions = T.let(nil, T.nilable(T::Array[T.any(String, Gem::Version)]))
@@ -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))
@@ -86,17 +84,23 @@ module Dependabot
86
84
  end
87
85
  end
88
86
 
89
- sig { override.returns(T.nilable(T.any(String, Dependabot::Version))) }
87
+ sig { override.returns(T.nilable(T.any(String, Gem::Version))) }
90
88
  def latest_resolvable_version
91
89
  return unless latest_version
92
90
 
93
91
  @latest_resolvable_version ||=
94
92
  if dependency.top_level?
95
- version_resolver.latest_resolvable_version
93
+ T.cast(
94
+ version_resolver.latest_resolvable_version,
95
+ T.nilable(T.any(String, Dependabot::Version))
96
+ )
96
97
  else
97
98
  # If the dependency is indirect its version is constrained by the
98
99
  # requirements placed on it by dependencies lower down the tree
99
- subdependency_version_resolver.latest_resolvable_version
100
+ T.cast(
101
+ subdependency_version_resolver.latest_resolvable_version,
102
+ T.nilable(T.any(String, Dependabot::Version))
103
+ )
100
104
  end
101
105
  end
102
106
 
@@ -131,7 +135,9 @@ module Dependabot
131
135
 
132
136
  sig { override.returns(T.nilable(T.any(String, Dependabot::Version))) }
133
137
  def latest_resolvable_version_with_no_unlock
134
- return latest_resolvable_version unless dependency.top_level?
138
+ unless dependency.top_level?
139
+ return T.cast(latest_resolvable_version, T.nilable(T.any(String, Dependabot::Version)))
140
+ end
135
141
 
136
142
  return latest_resolvable_version_with_no_unlock_for_git_dependency if git_dependency?
137
143
 
@@ -165,7 +171,7 @@ module Dependabot
165
171
  requirements: dependency.requirements,
166
172
  updated_source: updated_source,
167
173
  latest_resolvable_version: resolvable_version,
168
- update_strategy: requirements_update_strategy
174
+ update_strategy: T.must(requirements_update_strategy)
169
175
  ).updated_requirements
170
176
  end
171
177
 
@@ -324,7 +330,7 @@ module Dependabot
324
330
  requirements: original_dep.requirements,
325
331
  updated_source: original_dep == dependency ? updated_source : original_source(original_dep),
326
332
  latest_resolvable_version: version,
327
- update_strategy: requirements_update_strategy
333
+ update_strategy: T.must(requirements_update_strategy)
328
334
  ).updated_requirements,
329
335
  previous_version: previous_version,
330
336
  previous_requirements: original_dep.requirements,
@@ -401,34 +407,17 @@ module Dependabot
401
407
  end
402
408
  end
403
409
 
404
- sig { returns(T.any(LatestVersionFinder, PackageLatestVersionFinder)) }
410
+ sig { returns(PackageLatestVersionFinder) }
405
411
  def latest_version_finder
406
- @latest_version_finder ||=
407
- if enable_cooldown?
408
- PackageLatestVersionFinder.new(
409
- dependency: dependency,
410
- credentials: credentials,
411
- dependency_files: dependency_files,
412
- ignored_versions: ignored_versions,
413
- raise_on_ignored: raise_on_ignored,
414
- security_advisories: security_advisories,
415
- cooldown_options: @update_cooldown
416
- )
417
- else
418
- LatestVersionFinder.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
- )
426
- end
427
- end
428
-
429
- sig { returns(T::Boolean) }
430
- def enable_cooldown?
431
- Dependabot::Experiments.enabled?(:enable_cooldown_for_bun)
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
+ )
432
421
  end
433
422
 
434
423
  sig { returns(VersionResolver) }
@@ -514,7 +503,7 @@ module Dependabot
514
503
 
515
504
  @library =
516
505
  LibraryDetector.new(
517
- package_json_file: package_json,
506
+ package_json_file: T.must(package_json),
518
507
  credentials: credentials,
519
508
  dependency_files: dependency_files
520
509
  ).library?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-bun
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.321.2
4
+ version: 0.322.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.321.2
18
+ version: 0.322.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.321.2
25
+ version: 0.322.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -347,7 +347,7 @@ licenses:
347
347
  - MIT
348
348
  metadata:
349
349
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
350
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.321.2
350
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.322.0
351
351
  rdoc_options: []
352
352
  require_paths:
353
353
  - lib