dependabot-npm_and_yarn 0.266.0 → 0.268.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67babb3510f025790b2e9806bd26290c658b66465bed55f41bbda6d2e4538551
4
- data.tar.gz: cebb0aa37accd77075e95f2cbd6539aa01015a6d44f44cb7709eee40b04cde27
3
+ metadata.gz: 473cf091eca02d2d3e0ff9920708779183b7a9a9dba2771c35ffe602eda18003
4
+ data.tar.gz: 3ff951a1e1970c6818b615b5f10b78950e5cc53c01b3a2b9540a28f3451ac294
5
5
  SHA512:
6
- metadata.gz: eff4ddfd5d0945e47eadce0deb0c8e8a7b8571ac238b809e8a8a86d28a6926d66cdf3074111c41769d040bcd5ec8adbae14f9da0b1a58ba18262b35242695784
7
- data.tar.gz: d5932088b9539ff88c1c43c59b5737de4e50e24222148af147fbea8d2ad068fae1aab6da8ea2bdc552272183afa84829a6900bb6c1c4b5a8e8a9f6680133a4ab
6
+ metadata.gz: 73a7da3b2062a4adaa70d33616698d418bcda9684e8cf301279bac6756537079136872cc68d6623af7f1ea8bd09197d7ac98edd287da6aafef63f1f6f25243c1
7
+ data.tar.gz: 68e3d2e1a3b50ccad6359b961a1e3093d6095d08fb8e79175aa83025c57716f080ca03dd5aea9e4f1dead654fa881cf4f20698971150ac5b361a25efbaa74b04
@@ -79,6 +79,14 @@ module Dependabot
79
79
  INVALID_AUTH_TOKEN =
80
80
  /401 Unauthorized - GET (?<url>.*) - unauthenticated: User cannot be authenticated with the token provided./
81
81
  NPM_PACKAGE_REGISTRY = "https://npm.pkg.github.com"
82
+ EOVERRIDE = /EOVERRIDE\n *.* Override for (?<deps>.*) conflicts with direct dependency/
83
+ NESTED_ALIAS = /nested aliases not supported/
84
+ PEER_DEPS_PATTERNS = T.let([/Cannot read properties of null/,
85
+ /ERESOLVE overriding peer dependency/].freeze, T::Array[Regexp])
86
+
87
+ ERROR_E401 = /code E401/
88
+ ERROR_E403 = /code E403/
89
+ ERROR_EAI_AGAIN = /request to (?<url>.*) failed, reason: getaddrinfo EAI_AGAIN/
82
90
 
83
91
  # TODO: look into fixing this in npm, seems like a bug in the git
84
92
  # downloader introduced in npm 7
@@ -392,7 +400,23 @@ module Dependabot
392
400
  # rubocop:disable Metrics/MethodLength
393
401
  sig { params(error: Exception).returns(T.noreturn) }
394
402
  def handle_npm_updater_error(error)
403
+ Dependabot.logger.warn("NPM : " + error.message)
404
+
395
405
  error_message = error.message
406
+
407
+ # message groups which are related to peer dependency resolution failure. Peer deps can be updated
408
+ # with --legacy-peer-deps flag, but it is not recommended as the flag can mess up dependency resolution
409
+ # and introduce breaking changes. So we let the update fail.
410
+ peerdep_group = Regexp.union(PEER_DEPS_PATTERNS)
411
+ if error_message.match(peerdep_group)
412
+ raise Dependabot::DependencyFileNotResolvable,
413
+ "Error while updating peer dependency."
414
+ end
415
+
416
+ if error_message.match?(ERROR_E401) || error_message.match?(ERROR_E403)
417
+ raise Dependabot::PrivateSourceAuthenticationFailure, error_message
418
+ end
419
+
396
420
  if error_message.match?(MISSING_PACKAGE)
397
421
  package_name = T.must(error_message.match(MISSING_PACKAGE))
398
422
  .named_captures["package_req"]
@@ -516,6 +540,11 @@ module Dependabot
516
540
  raise Dependabot::PrivateSourceAuthenticationFailure, msg
517
541
  end
518
542
 
543
+ if (git_source = error_message.match(ERROR_EAI_AGAIN))
544
+ msg = "Network Error. Access to #{git_source.named_captures.fetch('url')} failed."
545
+ raise Dependabot::PrivateSourceTimedOut, msg
546
+ end
547
+
519
548
  if (registry_source = error_message.match(INVALID_AUTH_TOKEN) ||
520
549
  error_message.match(MISSING_AUTH_TOKEN)) &&
521
550
  T.must(registry_source.named_captures.fetch("url")).include?(NPM_PACKAGE_REGISTRY)
@@ -523,6 +552,16 @@ module Dependabot
523
552
  raise Dependabot::InvalidGitAuthToken, T.must(msg)
524
553
  end
525
554
 
555
+ if (dep = error_message.match(EOVERRIDE))
556
+ msg = "Override for #{dep.named_captures.fetch('deps')} conflicts with direct dependency"
557
+ raise Dependabot::DependencyFileNotResolvable, msg
558
+ end
559
+
560
+ if error_message.match(NESTED_ALIAS)
561
+ msg = "Nested aliases are not supported in NPM versions earlier than 6.9.0."
562
+ raise Dependabot::DependencyFileNotResolvable, msg
563
+ end
564
+
526
565
  raise error
527
566
  end
528
567
  # rubocop:enable Metrics/AbcSize
@@ -130,18 +130,14 @@ module Dependabot
130
130
  end
131
131
  end
132
132
  rescue SharedHelpers::HelperSubprocessFailed => e
133
- # package.json name cannot contain characters like empty string or @.
134
- raise Dependabot::DependencyFileNotParseable, e.message if e.message.include?(INVALID_NAME_IN_PACKAGE_JSON)
133
+ package_missing = error_handler.package_missing(e.message)
135
134
 
136
- names = dependencies.map(&:name)
137
- package_missing = names.any? do |name|
138
- e.message.include?("find package \"#{name}")
135
+ unless package_missing
136
+ error_handler.handle_error(e, {
137
+ yarn_lock: yarn_lock
138
+ })
139
139
  end
140
140
 
141
- package_missing = e.message.match(PACKAGE_MISSING_REGEX) || package_missing
142
-
143
- error_handler.handle_error(e) unless package_missing
144
-
145
141
  raise unless package_missing
146
142
 
147
143
  retry_count ||= 0
@@ -229,39 +225,19 @@ module Dependabot
229
225
  end
230
226
  end
231
227
 
232
- # rubocop:disable Metrics/AbcSize
233
- # rubocop:disable Metrics/PerceivedComplexity
234
- # rubocop:disable Metrics/MethodLength
235
228
  def handle_yarn_lock_updater_error(error, yarn_lock)
236
229
  error_message = error.message
237
230
 
238
- # Invalid package: When package.json doesn't include a name or version
239
- # Local path error: When installing a git dependency which
240
- # is using local file paths for sub-dependencies (e.g. unbuilt yarn
241
- # workspace project)
242
- if error_message.match?(INVALID_PACKAGE_REGEX) ||
243
- error_message.include?(SUB_DEP_LOCAL_PATH_TEXT)
244
- error_handler.raise_resolvability_error(error_message, yarn_lock)
245
- end
231
+ error_handler.handle_error(error, {
232
+ yarn_lock: yarn_lock
233
+ })
246
234
 
247
- error_handler.handle_error(error)
235
+ package_not_found = error_handler.handle_package_not_found(error_message, yarn_lock)
248
236
 
249
- if error_message.include?("Couldn't find package")
250
- package_name = error_message.match(/package "(?<package_req>.*?)"/)
251
- .named_captures["package_req"]
252
- .split(/(?<=\w)\@/).first
253
- sanitized_name = sanitize_package_name(package_name)
254
- sanitized_error = error_message.gsub(package_name, sanitized_name)
255
- handle_missing_package(sanitized_name, sanitized_error, yarn_lock)
256
- end
257
-
258
- if error_message.match?(%r{/[^/]+: Not found})
259
- package_name = error_message
260
- .match(%r{/(?<package_name>[^/]+): Not found})
261
- .named_captures["package_name"]
262
- sanitized_name = sanitize_package_name(package_name)
263
- sanitized_error = error_message.gsub(package_name, sanitized_name)
264
- handle_missing_package(sanitized_name, sanitized_error, yarn_lock)
237
+ if package_not_found.any?
238
+ sanitized_name = package_not_found[:sanitized_name]
239
+ sanitized_message = package_not_found[:sanitized_message]
240
+ handle_missing_package(sanitized_name, sanitized_message, yarn_lock)
265
241
  end
266
242
 
267
243
  # TODO: Move this logic to the version resolver and check if a new
@@ -283,7 +259,7 @@ module Dependabot
283
259
  # This happens if a new version has been published but npm is having
284
260
  # consistency issues and the version isn't fully available on all
285
261
  # queries
286
- if error_message.start_with?("Couldn't find any versions") &&
262
+ if error_message.start_with?(DEPENDENCY_NO_VERSION_FOUND) &&
287
263
  dependencies_in_error_message?(error_message) &&
288
264
  resolvable_before_update?(yarn_lock)
289
265
 
@@ -293,24 +269,13 @@ module Dependabot
293
269
  raise Dependabot::InconsistentRegistryResponse, error_message
294
270
  end
295
271
 
296
- if error_message.include?(ONLY_PRIVATE_WORKSPACE_TEXT)
297
- raise Dependabot::DependencyFileNotEvaluatable, error_message
298
- end
299
-
300
- if error_message.match?(UNREACHABLE_GIT_CHECK_REGEX)
301
- dependency_url = error_message.match(UNREACHABLE_GIT_CHECK_REGEX)
302
- .named_captures.fetch("url")
303
-
304
- raise Dependabot::GitDependenciesNotReachable, dependency_url
305
- end
306
-
307
272
  handle_timeout(error_message, yarn_lock) if error_message.match?(
308
273
  TIMEOUT_FETCHING_PACKAGE_REGEX
309
274
  )
310
275
 
311
- if error_message.start_with?("Couldn't find any versions") ||
312
- error_message.include?(": Not found") ||
313
- error_message.include?("Couldn't find match for")
276
+ if error_message.start_with?(DEPENDENCY_VERSION_NOT_FOUND) ||
277
+ error_message.include?(DEPENDENCY_NOT_FOUND) ||
278
+ error_message.include?(DEPENDENCY_MATCH_NOT_FOUND)
314
279
 
315
280
  unless resolvable_before_update?(yarn_lock)
316
281
  error_handler.raise_resolvability_error(error_message, yarn_lock)
@@ -323,9 +288,6 @@ module Dependabot
323
288
 
324
289
  raise error
325
290
  end
326
- # rubocop:enable Metrics/AbcSize
327
- # rubocop:enable Metrics/PerceivedComplexity
328
- # rubocop:enable Metrics/MethodLength
329
291
 
330
292
  def resolvable_before_update?(yarn_lock)
331
293
  @resolvable_before_update ||= {}
@@ -583,6 +545,7 @@ module Dependabot
583
545
  class YarnErrorHandler
584
546
  extend T::Sig
585
547
 
548
+ # Initializes the YarnErrorHandler with dependencies and dependency files
586
549
  sig do
587
550
  params(
588
551
  dependencies: T::Array[Dependabot::Dependency],
@@ -615,26 +578,27 @@ module Dependabot
615
578
  end
616
579
 
617
580
  # Main error handling method
618
- sig { params(error: SharedHelpers::HelperSubprocessFailed).void }
619
- def handle_error(error)
620
- # Check if defined yarn error codes contained in the error message
621
- # and raise the corresponding error class
622
- handle_yarn_error(error)
581
+ sig { params(error: SharedHelpers::HelperSubprocessFailed, params: T::Hash[Symbol, String]).void }
582
+ def handle_error(error, params)
583
+ error_message = error.message
623
584
 
624
585
  # Extract the usage error message from the raw error message
625
- usage_error_message = find_usage_error(error.message) || ""
586
+ usage_error_message = find_usage_error(error_message) || ""
626
587
 
627
- # Check if the error message contains any group patterns and raise
628
- # the corresponding error class
629
- handle_group_patterns(error, usage_error_message)
588
+ # Check if the error message contains any group patterns and raise the corresponding error class
589
+ handle_group_patterns(error, usage_error_message, params)
590
+
591
+ # Check if defined yarn error codes contained in the error message
592
+ # and raise the corresponding error class
593
+ handle_yarn_error(error, params)
630
594
  end
631
595
 
632
596
  # Handles errors with specific to yarn error codes
633
- sig { params(error: SharedHelpers::HelperSubprocessFailed).void }
634
- def handle_yarn_error(error)
635
- error_message = error.message
636
- regex = YARN_CODE_REGEX
637
- matches = error_message.scan(regex)
597
+ sig { params(error: SharedHelpers::HelperSubprocessFailed, params: T::Hash[Symbol, String]).void }
598
+ def handle_yarn_error(error, params)
599
+ ## Clean error message from ANSI escape codes
600
+ error_message = error.message.gsub(/\e\[\d+(;\d+)*m/, "")
601
+ matches = error_message.scan(YARN_CODE_REGEX)
638
602
  return if matches.empty?
639
603
 
640
604
  # Go through each match backwards in the error message and raise the corresponding error class
@@ -646,8 +610,8 @@ module Dependabot
646
610
  next unless yarn_error.is_a?(Hash)
647
611
 
648
612
  message = yarn_error[:message]
649
- new_error = yarn_error[:new_error]
650
- next unless new_error
613
+ handler = yarn_error[:handler]
614
+ next unless handler
651
615
 
652
616
  modified_error_message = if message
653
617
  "[#{code}]: #{message}, Detail: #{error_message}"
@@ -655,7 +619,7 @@ module Dependabot
655
619
  "[#{code}]: #{error_message}"
656
620
  end
657
621
 
658
- raise new_error.call(error, modified_error_message)
622
+ raise create_error(handler, modified_error_message, error, params)
659
623
  end
660
624
  end
661
625
 
@@ -663,30 +627,48 @@ module Dependabot
663
627
  sig do
664
628
  params(
665
629
  error: SharedHelpers::HelperSubprocessFailed,
666
- usage_error_message: String
630
+ usage_error_message: String,
631
+ params: T::Hash[Symbol, String]
667
632
  ).void
668
633
  end
669
- def handle_group_patterns(error, usage_error_message) # rubocop:disable Metrics/PerceivedComplexity
634
+ def handle_group_patterns(error, usage_error_message, params) # rubocop:disable Metrics/PerceivedComplexity
670
635
  error_message = error.message
671
636
  VALIDATION_GROUP_PATTERNS.each do |group|
672
637
  patterns = group[:patterns]
673
638
  matchfn = group[:matchfn]
674
- new_error = group[:new_error]
639
+ handler = group[:handler]
675
640
  in_usage = group[:in_usage] || false
676
641
 
677
- next unless (patterns || matchfn) && new_error
642
+ next unless (patterns || matchfn) && handler
678
643
 
679
644
  message = usage_error_message.empty? ? error_message : usage_error_message
680
645
  if in_usage && pattern_in_message(patterns, usage_error_message)
681
- raise new_error.call(error, message)
682
- elsif !in_usage && pattern_in_message(patterns, error_message)
683
- raise new_error.call(error, error.message)
646
+ raise create_error(handler, message, error, params)
647
+ elsif !in_usage && pattern_in_message(patterns, error.message)
648
+ raise create_error(handler, error.message, error, params)
684
649
  end
685
650
 
686
- raise new_error.call(error, message) if matchfn&.call(usage_error_message, error_message)
651
+ raise create_error(handler, message, error, params) if matchfn&.call(usage_error_message, error_message)
687
652
  end
688
653
  end
689
654
 
655
+ # Creates a new error based on the provided parameters
656
+ sig do
657
+ params(
658
+ handler: ErrorHandler,
659
+ message: String,
660
+ error: SharedHelpers::HelperSubprocessFailed,
661
+ params: T::Hash[Symbol, String]
662
+ ).returns(Dependabot::DependabotError)
663
+ end
664
+ def create_error(handler, message, error, params)
665
+ handler.call(message, error, {
666
+ dependencies: dependencies,
667
+ dependency_files: dependency_files,
668
+ **params
669
+ })
670
+ end
671
+
690
672
  # Raises a resolvability error for a dependency file
691
673
  sig do
692
674
  params(
@@ -708,16 +690,68 @@ module Dependabot
708
690
  ).returns(T::Boolean)
709
691
  end
710
692
  def pattern_in_message(patterns, message)
711
- patterns.any? do |pattern|
693
+ patterns.each do |pattern|
712
694
  if pattern.is_a?(String)
713
- return message.include?(pattern)
695
+ return true if message.include?(pattern)
714
696
  elsif pattern.is_a?(Regexp)
715
- message = message.gsub(/\e\[[\d;]*[A-Za-z]/, "")
716
- return message.match?(pattern)
697
+ return true if message.gsub(/\e\[[\d;]*[A-Za-z]/, "").match?(pattern)
717
698
  end
718
699
  end
719
700
  false
720
701
  end
702
+
703
+ sig do
704
+ params(error_message: String, yarn_lock: Dependabot::DependencyFile)
705
+ .returns(T::Hash[T.any(Symbol, String), T.any(String, NilClass)])
706
+ end
707
+ def handle_package_not_found(error_message, yarn_lock) # rubocop:disable Metrics/PerceivedComplexity
708
+ # There are 2 different package not found error messages
709
+ package_not_found = error_message.include?(PACKAGE_NOT_FOUND)
710
+ package_not_found2 = error_message.match?(PACKAGE_NOT_FOUND2)
711
+
712
+ # If non of the patterns are found, return an empty hash
713
+ return {} unless package_not_found || package_not_found2
714
+
715
+ sanitized_name = T.let(nil, T.nilable(String))
716
+
717
+ if package_not_found
718
+ package_name =
719
+ error_message
720
+ .match(PACKAGE_NOT_FOUND_PACKAGE_NAME_REGEX)
721
+ &.named_captures
722
+ &.[](PACKAGE_NOT_FOUND_PACKAGE_NAME_CAPTURE)
723
+ &.split(PACKAGE_NOT_FOUND_PACKAGE_NAME_CAPTURE_SPLIT_REGEX)
724
+ &.first
725
+ end
726
+
727
+ if package_not_found2
728
+ package_name =
729
+ error_message
730
+ .match(PACKAGE_NOT_FOUND2_PACKAGE_NAME_REGEX)
731
+ &.named_captures
732
+ &.[](PACKAGE_NOT_FOUND2_PACKAGE_NAME_CAPTURE)
733
+ end
734
+
735
+ raise_resolvability_error(error_message, yarn_lock) unless package_name
736
+ sanitized_name = sanitize_package_name(package_name) if package_name
737
+ error_message = error_message.gsub(package_name, sanitized_name) if package_name && sanitized_name
738
+ { sanitized_name: sanitized_name, sanitized_message: error_message }
739
+ end
740
+
741
+ # Checks if a package is missing from the error message
742
+ sig { params(error_message: String).returns(T::Boolean) }
743
+ def package_missing(error_message)
744
+ names = dependencies.map(&:name)
745
+ package_missing = names.any? { |name| error_message.include?("find package \"#{name}") }
746
+ !!error_message.match(PACKAGE_MISSING_REGEX) || package_missing
747
+ end
748
+
749
+ sig { params(package_name: T.nilable(String)).returns(T.nilable(String)) }
750
+ def sanitize_package_name(package_name)
751
+ return package_name.gsub("%2f", "/").gsub("%2F", "/") if package_name
752
+
753
+ nil
754
+ end
721
755
  end
722
756
  end
723
757
  end
@@ -309,6 +309,10 @@ module Dependabot
309
309
 
310
310
  latest_version = latest_version_finder(original_package).latest_version_from_registry
311
311
 
312
+ # If the latest version is within the scope of the current requirements,
313
+ # latest_version will be nil. In such cases, there is no update available.
314
+ return false if latest_version.nil?
315
+
312
316
  original_package_version < latest_version
313
317
  end
314
318
 
@@ -26,6 +26,13 @@ Dependabot::Dependency.register_production_check(
26
26
  end
27
27
  )
28
28
 
29
+ ## A type used for defining a proc that creates a new error object
30
+ ErrorHandler = T.type_alias do
31
+ T.proc
32
+ .params(message: String, error: Dependabot::DependabotError, params: T::Hash[Symbol, T.untyped])
33
+ .returns(Dependabot::DependabotError)
34
+ end
35
+
29
36
  module Dependabot
30
37
  module NpmAndYarn
31
38
  NODE_VERSION_NOT_SATISFY_REGEX = /The current Node version (?<current_version>v?\d+\.\d+\.\d+) does not satisfy the required version (?<required_version>v?\d+\.\d+\.\d+)\./ # rubocop:disable Layout/LineLength
@@ -36,7 +43,10 @@ module Dependabot
36
43
  # Used to check if url is http or https
37
44
  HTTP_CHECK_REGEX = %r{https?://}
38
45
 
39
- # Error message when a package.json name include invalid characters
46
+ # Used to check capture url match in regex capture group
47
+ URL_CAPTURE = "url"
48
+
49
+ # When package name contains package.json name cannot contain characters like empty string or @.
40
50
  INVALID_NAME_IN_PACKAGE_JSON = "Name contains illegal characters"
41
51
 
42
52
  # Used to identify error messages indicating a package is missing, unreachable,
@@ -56,7 +66,29 @@ module Dependabot
56
66
  SUB_DEP_LOCAL_PATH_TEXT = "refers to a non-existing file"
57
67
 
58
68
  # Used to identify invalid package error when package is not found in registry
59
- INVALID_PACKAGE_REGEX = /Can't add "(?<package_req>.*)": invalid/
69
+ INVALID_PACKAGE_REGEX = /Can't add "[\w\-.]+": invalid/
70
+
71
+ # Used to identify error if package not found in registry
72
+ PACKAGE_NOT_FOUND = "Couldn't find package"
73
+ PACKAGE_NOT_FOUND_PACKAGE_NAME_REGEX = /package "(?<package_req>.*?)"/
74
+ PACKAGE_NOT_FOUND_PACKAGE_NAME_CAPTURE = "package_req"
75
+ PACKAGE_NOT_FOUND_PACKAGE_NAME_CAPTURE_SPLIT_REGEX = /(?<=\w)\@/
76
+
77
+ YN0035 = T.let({
78
+ PACKAGE_NOT_FOUND: %r{(?<package_req>@[\w-]+\/[\w-]+@\S+): Package not found},
79
+ FAILED_TO_RETRIEVE: %r{(?<package_req>@[\w-]+\/[\w-]+@\S+): The remote server failed to provide the requested resource} # rubocop:disable Layout/LineLength
80
+ }.freeze, T::Hash[String, Regexp])
81
+
82
+ PACKAGE_NOT_FOUND2 = %r{/[^/]+: Not found}
83
+ PACKAGE_NOT_FOUND2_PACKAGE_NAME_REGEX = %r{/(?<package_name>[^/]+): Not found}
84
+ PACKAGE_NOT_FOUND2_PACKAGE_NAME_CAPTURE = "package_name"
85
+
86
+ # Used to identify error if package not found in registry
87
+ DEPENDENCY_VERSION_NOT_FOUND = "Couldn't find any versions"
88
+ DEPENDENCY_NOT_FOUND = ": Not found"
89
+ DEPENDENCY_MATCH_NOT_FOUND = "Couldn't find match for"
90
+
91
+ DEPENDENCY_NO_VERSION_FOUND = "Couldn't find any versions"
60
92
 
61
93
  # Used to identify error if node_modules state file not resolved
62
94
  NODE_MODULES_STATE_FILE_NOT_FOUND = "Couldn't find the node_modules state file"
@@ -74,6 +106,8 @@ module Dependabot
74
106
  # Used to identify if error message is related to yarn workspaces
75
107
  DEPENDENCY_FILE_NOT_RESOLVABLE = "conflicts with direct dependency"
76
108
 
109
+ ENV_VAR_NOT_RESOLVABLE = /Failed to replace env in config: \$\{(?<var>.*)\}/
110
+
77
111
  class Utils
78
112
  extend T::Sig
79
113
 
@@ -87,88 +121,176 @@ module Dependabot
87
121
  required_version: match_data[:required_version]
88
122
  }
89
123
  end
124
+
125
+ sig { params(error_message: String).returns(String) }
126
+ def self.extract_var(error_message)
127
+ match_data = T.must(error_message.match(ENV_VAR_NOT_RESOLVABLE)).named_captures["var"]
128
+ return "" unless match_data
129
+
130
+ match_data
131
+ end
132
+
133
+ sig do
134
+ params(
135
+ error_message: String,
136
+ dependencies: T::Array[Dependabot::Dependency],
137
+ yarn_lock: Dependabot::DependencyFile
138
+ ).returns(String)
139
+ end
140
+ def self.sanitize_resolvability_message(error_message, dependencies, yarn_lock)
141
+ dependency_names = dependencies.map(&:name).join(", ")
142
+ "Error whilst updating #{dependency_names} in #{yarn_lock.path}:\n#{error_message}"
143
+ end
90
144
  end
91
145
 
92
146
  YARN_CODE_REGEX = /(YN\d{4})/
93
147
  YARN_ERROR_CODES = T.let({
94
148
  "YN0001" => {
95
149
  message: "Exception error",
96
- new_error: ->(_error, message) { Dependabot::DependabotError.new(message) }
150
+ handler: lambda { |message, _error, _params|
151
+ Dependabot::DependabotError.new(message)
152
+ }
97
153
  },
98
154
  "YN0002" => {
99
155
  message: "Missing peer dependency",
100
- new_error: ->(_error, message) { Dependabot::DependencyFileNotResolvable.new(message) }
156
+ handler: lambda { |message, _error, _params|
157
+ Dependabot::DependencyFileNotResolvable.new(message)
158
+ }
101
159
  },
102
160
  "YN0016" => {
103
161
  message: "Remote not found",
104
- new_error: ->(_error, message) { Dependabot::GitDependenciesNotReachable.new(message) }
162
+ handler: lambda { |message, _error, _params|
163
+ Dependabot::GitDependenciesNotReachable.new(message)
164
+ }
105
165
  },
106
166
  "YN0020" => {
107
167
  message: "Missing lockfile entry",
108
- new_error: ->(_error, message) { Dependabot::DependencyFileNotFound.new(message) }
168
+ handler: lambda { |message, _error, _params|
169
+ Dependabot::DependencyFileNotFound.new(message)
170
+ }
171
+ },
172
+ "YN0035" => {
173
+ message: "Package not found",
174
+ handler: lambda { |message, _error, _params|
175
+ YN0035.each do |(_yn0035_key, yn0035_regex)|
176
+ if (match_data = message.match(yn0035_regex)) && (package_req = match_data[:package_req])
177
+ return Dependabot::DependencyNotFound.new(
178
+ "#{package_req} Detail: #{message}"
179
+ )
180
+ end
181
+ end
182
+ Dependabot::DependencyNotFound.new(message)
183
+ }
109
184
  },
110
185
  "YN0046" => {
111
186
  message: "Automerge failed to parse",
112
- new_error: ->(_error, message) { Dependabot::MisconfiguredTooling.new("Yarn", message) }
187
+ handler: lambda { |message, _error, _params|
188
+ Dependabot::MisconfiguredTooling.new("Yarn", message)
189
+ }
113
190
  },
114
191
  "YN0047" => {
115
192
  message: "Automerge immutable",
116
- new_error: ->(_error, message) { Dependabot::MisconfiguredTooling.new("Yarn", message) }
193
+ handler: lambda { |message, _error, _params|
194
+ Dependabot::MisconfiguredTooling.new("Yarn", message)
195
+ }
117
196
  },
118
197
  "YN0062" => {
119
198
  message: "Incompatible OS",
120
- new_error: ->(_error, message) { Dependabot::DependabotError.new(message) }
199
+ handler: lambda { |message, _error, _params|
200
+ Dependabot::DependabotError.new(message)
201
+ }
121
202
  },
122
203
  "YN0063" => {
123
204
  message: "Incompatible CPU",
124
- new_error: ->(_error, message) { Dependabot::IncompatibleCPU.new(message) }
205
+ handler: lambda { |message, _error, _params|
206
+ Dependabot::IncompatibleCPU.new(message)
207
+ }
125
208
  },
126
209
  "YN0071" => {
127
210
  message: "NM can't install external soft link",
128
- new_error: ->(_error, message) { Dependabot::MisconfiguredTooling.new("Yarn", message) }
211
+ handler: lambda { |message, _error, _params|
212
+ Dependabot::MisconfiguredTooling.new("Yarn", message)
213
+ }
129
214
  },
130
215
  "YN0072" => {
131
216
  message: "NM preserve symlinks required",
132
- new_error: ->(_error, message) { Dependabot::MisconfiguredTooling.new("Yarn", message) }
217
+ handler: lambda { |message, _error, _params|
218
+ Dependabot::MisconfiguredTooling.new("Yarn", message)
219
+ }
133
220
  },
134
221
  "YN0075" => {
135
222
  message: "Prolog instantiation error",
136
- new_error: ->(_error, message) { Dependabot::MisconfiguredTooling.new("Yarn", message) }
223
+ handler: lambda { |message, _error, _params|
224
+ Dependabot::MisconfiguredTooling.new("Yarn", message)
225
+ }
137
226
  },
138
227
  "YN0077" => {
139
228
  message: "Ghost architecture",
140
- new_error: ->(_error, message) { Dependabot::MisconfiguredTooling.new("Yarn", message) }
229
+ handler: lambda { |message, _error, _params|
230
+ Dependabot::MisconfiguredTooling.new("Yarn", message)
231
+ }
141
232
  },
142
233
  "YN0080" => {
143
234
  message: "Network disabled",
144
- new_error: ->(_error, message) { Dependabot::MisconfiguredTooling.new("Yarn", message) }
235
+ handler: lambda { |message, _error, _params|
236
+ Dependabot::MisconfiguredTooling.new("Yarn", message)
237
+ }
145
238
  },
146
239
  "YN0081" => {
147
240
  message: "Network unsafe HTTP",
148
- new_error: ->(_error, message) { Dependabot::NetworkUnsafeHTTP.new(message) }
241
+ handler: lambda { |message, _error, _params|
242
+ Dependabot::NetworkUnsafeHTTP.new(message)
243
+ }
149
244
  }
150
245
  }.freeze, T::Hash[String, {
151
246
  message: T.any(String, NilClass),
152
- new_error: T.proc.params(error: Dependabot::DependabotError, message: String).returns(Dependabot::DependabotError)
247
+ handler: ErrorHandler
153
248
  }])
154
249
 
155
250
  # Group of patterns to validate error message and raise specific error
156
251
  VALIDATION_GROUP_PATTERNS = T.let([
252
+ {
253
+ patterns: [INVALID_NAME_IN_PACKAGE_JSON],
254
+ handler: lambda { |message, _error, _params|
255
+ Dependabot::DependencyFileNotParseable.new(message)
256
+ },
257
+ in_usage: false,
258
+ matchfn: nil
259
+ },
260
+ {
261
+ # Check if sub dependency is using local path and raise a resolvability error
262
+ patterns: [INVALID_PACKAGE_REGEX, SUB_DEP_LOCAL_PATH_TEXT],
263
+ handler: lambda { |message, _error, params|
264
+ Dependabot::DependencyFileNotResolvable.new(
265
+ Utils.sanitize_resolvability_message(
266
+ message,
267
+ params[:dependencies],
268
+ params[:yarn_lock]
269
+ )
270
+ )
271
+ },
272
+ in_usage: false,
273
+ matchfn: nil
274
+ },
157
275
  {
158
276
  patterns: [NODE_MODULES_STATE_FILE_NOT_FOUND],
159
- new_error: ->(_error, message) { Dependabot::MisconfiguredTooling.new("Yarn", message) },
277
+ handler: lambda { |message, _error, _params|
278
+ Dependabot::MisconfiguredTooling.new("Yarn", message)
279
+ },
160
280
  in_usage: true,
161
281
  matchfn: nil
162
282
  },
163
283
  {
164
284
  patterns: [TARBALL_IS_NOT_IN_NETWORK],
165
- new_error: ->(_error, message) { Dependabot::DependencyFileNotResolvable.new(message) },
285
+ handler: lambda { |message, _error, _params|
286
+ Dependabot::DependencyFileNotResolvable.new(message)
287
+ },
166
288
  in_usage: false,
167
289
  matchfn: nil
168
290
  },
169
291
  {
170
292
  patterns: [NODE_VERSION_NOT_SATISFY_REGEX],
171
- new_error: lambda { |_error, message|
293
+ handler: lambda { |message, _error, _params|
172
294
  versions = Utils.extract_node_versions(message)
173
295
  current_version = versions[:current_version]
174
296
  required_version = versions[:required_version]
@@ -182,20 +304,51 @@ module Dependabot
182
304
  },
183
305
  {
184
306
  patterns: [AUTHENTICATION_TOKEN_NOT_PROVIDED, AUTHENTICATION_IS_NOT_CONFIGURED],
185
- new_error: ->(_error, message) { Dependabot::PrivateSourceAuthenticationFailure.new(message) },
307
+ handler: lambda { |message, _error, _params|
308
+ Dependabot::PrivateSourceAuthenticationFailure.new(message)
309
+ },
186
310
  in_usage: false,
187
311
  matchfn: nil
188
312
  },
189
313
  {
190
314
  patterns: [DEPENDENCY_FILE_NOT_RESOLVABLE],
191
- new_error: ->(_error, message) { DependencyFileNotResolvable.new(message) },
315
+ handler: lambda { |message, _error, _params|
316
+ DependencyFileNotResolvable.new(message)
317
+ },
318
+ in_usage: false,
319
+ matchfn: nil
320
+ },
321
+ {
322
+ patterns: [ENV_VAR_NOT_RESOLVABLE],
323
+ handler: lambda { |message, _error, _params|
324
+ var = Utils.extract_var(message)
325
+
326
+ Dependabot::MissingEnvironmentVariable.new(var, message)
327
+ },
328
+ in_usage: false,
329
+ matchfn: nil
330
+ },
331
+ {
332
+ patterns: [ONLY_PRIVATE_WORKSPACE_TEXT],
333
+ handler: lambda { |message, _error, _params|
334
+ Dependabot::DependencyFileNotEvaluatable.new(message)
335
+ },
336
+ in_usage: false,
337
+ matchfn: nil
338
+ },
339
+ {
340
+ patterns: [UNREACHABLE_GIT_CHECK_REGEX],
341
+ handler: lambda { |message, _error, _params|
342
+ dependency_url = message.match(UNREACHABLE_GIT_CHECK_REGEX).named_captures.fetch(URL_CAPTURE)
343
+
344
+ Dependabot::GitDependenciesNotReachable.new(dependency_url)
345
+ },
192
346
  in_usage: false,
193
347
  matchfn: nil
194
348
  }
195
349
  ].freeze, T::Array[{
196
350
  patterns: T::Array[T.any(String, Regexp)],
197
- new_error: T.proc.params(error: Dependabot::DependabotError,
198
- message: String).returns(Dependabot::DependabotError),
351
+ handler: ErrorHandler,
199
352
  in_usage: T.nilable(T::Boolean),
200
353
  matchfn: T.nilable(T.proc.params(usage: String, message: String).returns(T::Boolean))
201
354
  }])
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-npm_and_yarn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.266.0
4
+ version: 0.268.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-18 00:00:00.000000000 Z
11
+ date: 2024-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.266.0
19
+ version: 0.268.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.266.0
26
+ version: 0.268.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -345,7 +345,7 @@ licenses:
345
345
  - MIT
346
346
  metadata:
347
347
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
348
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.266.0
348
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.268.0
349
349
  post_install_message:
350
350
  rdoc_options: []
351
351
  require_paths: