dependabot-npm_and_yarn 0.274.0 → 0.276.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: 4fe1263109daa3956820bc6977b9d31f6b372d93fac8ee628d98f4f53fdcb992
4
- data.tar.gz: 9b8ce74245d5957e545fa43e2fabefb0a0987e9ea8aa0e978a97cd51c59da550
3
+ metadata.gz: 71f857c622a3e71c8c1e3099f585ebcc9aa7451b2d4fffc696770ed110b71405
4
+ data.tar.gz: 6c345e58a378ac08049a9593708f92735d565b48283a23d52233d303cb700d66
5
5
  SHA512:
6
- metadata.gz: 81ead43e58c76eed9c89dbfb0fe31c23f95dc692a079e097f540ac136a464d5eeaae7d861c2b8b81de58861bb5b7630875499e2e17154989f3617f06ac3599ed
7
- data.tar.gz: 6355efedf3c69ff07f21c1c7bb548045b318fafb0e7acabebdcc231e0564baead08b52fd862707d545b52be77d1dae26077b9ff86cb16592786ed81ebc2d5cd7
6
+ metadata.gz: ec358314a3ce776ab90fa8b9d34e5bd3ec4006bb388467e412d58042bd1bcab2803e51b3fcc816ac49e5cdb6e64fbac2bed472dbb27d36c91e527f904a44797e
7
+ data.tar.gz: bbbc9073fddf986810a9ca35e1800d9030c8df3743f20d8ba7802a303eb815bf650e171d55beb63cab8f31fb5d9fbe9c65b84b7f2e2ec0db018a15f08ceae1ed
@@ -98,6 +98,21 @@ module Dependabot
98
98
  /Couldn't find package "(?<pkg>.*)" required by "(?<dep>.*)" on the "(?<regis>.*)" registry./
99
99
  ].freeze, T::Array[Regexp])
100
100
 
101
+ # dependency access protocol not supported by packagemanager
102
+ UNSUPPORTED_PROTOCOL = /EUNSUPPORTEDPROTOCOL\n(.*?)Unsupported URL Type "(?<access_method>.*)"/
103
+
104
+ # Internal server error returned from registry
105
+ SERVER_ERROR_500 = /500 Internal Server Error - GET (?<regis>.*)/
106
+
107
+ # issue related when dependency url is not mentioned correctly
108
+ UNRESOLVED_REFERENCE = /Unable to resolve reference (?<deps>.*)/
109
+
110
+ # npm git related error for dependencies
111
+ GIT_CHECKOUT_ERROR_REGEX = /Command failed: git checkout (?<sha>.*)/
112
+
113
+ # Invalid version format found for dependency in package.json file
114
+ INVALID_VERSION = /Invalid Version: (?<ver>.*)/
115
+
101
116
  # TODO: look into fixing this in npm, seems like a bug in the git
102
117
  # downloader introduced in npm 7
103
118
  #
@@ -428,6 +443,18 @@ module Dependabot
428
443
  raise Dependabot::PrivateSourceAuthenticationFailure, url
429
444
  end
430
445
 
446
+ if error_message.match?(SERVER_ERROR_500)
447
+ url = T.must(URI.decode_www_form_component(error_message).split("https://").last).split("/").first
448
+ msg = "Server error (500) while accessing #{url}."
449
+ raise Dependabot::DependencyFileNotResolvable, msg
450
+ end
451
+
452
+ if (error_msg = error_message.match(UNRESOLVED_REFERENCE))
453
+ dep = error_msg.named_captures["deps"]
454
+ msg = "Unable to resolve reference #{dep}."
455
+ raise Dependabot::DependencyFileNotResolvable, msg
456
+ end
457
+
431
458
  if error_message.match?(MISSING_PACKAGE)
432
459
  package_name = T.must(error_message.match(MISSING_PACKAGE))
433
460
  .named_captures["package_req"]
@@ -590,6 +617,20 @@ module Dependabot
590
617
  raise Dependabot::DependencyFileNotResolvable, msg
591
618
  end
592
619
 
620
+ if (error_msg = error_message.match(UNSUPPORTED_PROTOCOL))
621
+ msg = "Unsupported protocol \"#{error_msg.named_captures.fetch('access_method')}\" while accessing dependency." # rubocop:disable Layout/LineLength
622
+ raise Dependabot::DependencyFileNotResolvable, msg
623
+ end
624
+
625
+ if (error_msg = error_message.match(GIT_CHECKOUT_ERROR_REGEX))
626
+ raise Dependabot::DependencyFileNotResolvable, error_msg
627
+ end
628
+
629
+ if (error_msg = error_message.match(INVALID_VERSION))
630
+ msg = "Found invalid version \"#{error_msg.named_captures.fetch('ver')}\" while updating"
631
+ raise Dependabot::DependencyFileNotResolvable, msg
632
+ end
633
+
593
634
  raise error
594
635
  end
595
636
  # rubocop:enable Metrics/AbcSize
@@ -2,20 +2,55 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/shared_helpers"
5
+ require "dependabot/npm_and_yarn/version_selector"
5
6
 
6
7
  module Dependabot
7
8
  module NpmAndYarn
8
9
  class PackageManager
10
+ extend T::Sig
11
+ extend T::Helpers
9
12
  def initialize(package_json, lockfiles:)
10
13
  @package_json = package_json
11
14
  @lockfiles = lockfiles
12
15
  @package_manager = package_json.fetch("packageManager", nil)
16
+ @engines = package_json.fetch("engines", nil)
13
17
  end
14
18
 
19
+ # rubocop:disable Metrics/CyclomaticComplexity
20
+ # rubocop:disable Metrics/PerceivedComplexity
15
21
  def setup(name)
16
- return unless @package_manager.nil? || @package_manager.start_with?("#{name}@")
22
+ # we prioritize version mentioned in "packageManager" instead of "engines"
23
+ # i.e. if { engines : "pnpm" : "6" } and { packageManager: "pnpm@6.0.2" },
24
+ # we go for the specificity mentioned in packageManager (6.0.2)
17
25
 
18
- version = requested_version(name)
26
+ if Dependabot::Experiments.enabled?(:enable_pnpm_yarn_dynamic_engine)
27
+
28
+ unless @package_manager&.start_with?("#{name}@") || (@package_manager&.==name.to_s) || @package_manager.nil?
29
+ return
30
+ end
31
+
32
+ if @engines && @package_manager.nil?
33
+ # if "packageManager" doesn't exists in manifest file,
34
+ # we check if we can extract "engines" information
35
+ Dependabot.logger.info("No \"packageManager\" info found for \"#{name}\"")
36
+ version = check_engine_version(name)
37
+
38
+ elsif @package_manager&.==name.to_s
39
+ # if "packageManager" is found but no version is specified (i.e. pnpm@1.2.3),
40
+ # we check if we can get "engines" info to override default version
41
+ Dependabot.logger.info("Found \"packageManager\" : \"#{@package_manager}\"")
42
+ version = check_engine_version(name) if @engines
43
+
44
+ elsif @package_manager&.start_with?("#{name}@")
45
+ # if "packageManager" info has version specification i.e. yarn@3.3.1
46
+ # we go with the version in "packageManager"
47
+ Dependabot.logger.info("Found \"packageManager\" : \"#{@package_manager}\". Skipped checking \"engines\".")
48
+ end
49
+ else
50
+ return unless @package_manager.nil? || @package_manager&.start_with?("#{name}@")
51
+ end
52
+
53
+ version ||= requested_version(name)
19
54
 
20
55
  if version
21
56
  raise_if_unsupported!(name, version)
@@ -33,6 +68,8 @@ module Dependabot
33
68
 
34
69
  version
35
70
  end
71
+ # rubocop:enable Metrics/CyclomaticComplexity
72
+ # rubocop:enable Metrics/PerceivedComplexity
36
73
 
37
74
  private
38
75
 
@@ -44,6 +81,8 @@ module Dependabot
44
81
  end
45
82
 
46
83
  def install(name, version)
84
+ Dependabot.logger.info("Installing \"#{name}@#{version}\"")
85
+
47
86
  SharedHelpers.run_shell_command(
48
87
  "corepack install #{name}@#{version} --global --cache-only",
49
88
  fingerprint: "corepack install <name>@<version> --global --cache-only"
@@ -53,9 +92,10 @@ module Dependabot
53
92
  def requested_version(name)
54
93
  return unless @package_manager
55
94
 
56
- match = @package_manager.match(/#{name}@(?<version>\d+.\d+.\d+)/)
95
+ match = @package_manager.match(/^#{name}@(?<version>\d+.\d+.\d+)/)
57
96
  return unless match
58
97
 
98
+ Dependabot.logger.info("Requested version #{match['version']}")
59
99
  match["version"]
60
100
  end
61
101
 
@@ -63,8 +103,24 @@ module Dependabot
63
103
  lockfile = @lockfiles[name.to_sym]
64
104
  return unless lockfile
65
105
 
106
+ Dependabot.logger.info("Estimating version")
66
107
  Helpers.send(:"#{name}_version_numeric", lockfile)
67
108
  end
109
+
110
+ sig { params(name: T.untyped).returns(T.nilable(String)) }
111
+ def check_engine_version(name)
112
+ version_selector = VersionSelector.new
113
+ engine_versions = version_selector.setup(@package_json, name)
114
+
115
+ if engine_versions.empty?
116
+ Dependabot.logger.info("No relevant (engines) info for \"#{name}\"")
117
+ return
118
+ end
119
+
120
+ version = engine_versions[name]
121
+ Dependabot.logger.info("Returned (engines) info \"#{name}\" : \"#{version}\"")
122
+ version
123
+ end
68
124
  end
69
125
  end
70
126
  end
@@ -45,7 +45,8 @@ module Dependabot
45
45
  resolved_url
46
46
  end
47
47
 
48
- T.must(T.must(url_base[/@.*/]).gsub("%2F", "/").split("/")[0..1]).join("/")
48
+ package_name = url_base.gsub("%2F", "/").match(%r{@.*/})
49
+ "#{T.must(package_name)}#{T.must(url_base.gsub('%2F', '/').split('/').last)}"
49
50
  end
50
51
 
51
52
  private
@@ -17,15 +17,6 @@ module Dependabot
17
17
  class LatestVersionFinder
18
18
  extend T::Sig
19
19
 
20
- class RegistryError < StandardError
21
- attr_reader :status
22
-
23
- def initialize(status, msg)
24
- @status = status
25
- super(msg)
26
- end
27
- end
28
-
29
20
  def initialize(dependency:, credentials:, dependency_files:,
30
21
  ignored_versions:, security_advisories:,
31
22
  raise_on_ignored: false)
@@ -329,6 +320,8 @@ module Dependabot
329
320
  password: password
330
321
  }
331
322
  )
323
+ rescue URI::InvalidURIError => e
324
+ raise DependencyFileNotResolvable, e.message
332
325
  end
333
326
 
334
327
  def check_npm_response(npm_response)
@@ -90,6 +90,8 @@ module Dependabot
90
90
  Excon::Error::Socket,
91
91
  JSON::ParserError
92
92
  nil
93
+ rescue URI::InvalidURIError => e
94
+ raise DependencyFileNotResolvable, e.message
93
95
  end&.fetch("registry")
94
96
 
95
97
  @first_registry_with_dependency_details ||= global_registry.sub(%r{/+$}, "").sub(%r{^.*?//}, "")
@@ -0,0 +1,45 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "dependabot/shared_helpers"
5
+
6
+ module Dependabot
7
+ module NpmAndYarn
8
+ class VersionSelector
9
+ extend T::Sig
10
+ extend T::Helpers
11
+
12
+ # For limited testing, allowing only specific versions defined in engines in package.json
13
+ # such as "20.8.7", "8.1.2", "8.21.2",
14
+ NODE_ENGINE_SUPPORTED_REGEX = /^\d+(?:\.\d+)*$/
15
+
16
+ sig { params(manifest_json: T::Hash[String, T.untyped], name: String).returns(T::Hash[Symbol, T.untyped]) }
17
+ def setup(manifest_json, name)
18
+ engine_versions = manifest_json["engines"]
19
+
20
+ if engine_versions.nil?
21
+ Dependabot.logger.info("No info (engines) found")
22
+ return {}
23
+ end
24
+
25
+ # logs entries for analysis purposes
26
+ log = engine_versions.select do |engine, _value|
27
+ engine.to_s.match(name)
28
+ end
29
+ Dependabot.logger.info("Found engine info #{log}") unless log.empty?
30
+
31
+ # Only keep matching specs versions i.e. "20.21.2", "7.1.2",
32
+ # Additional specs can be added later
33
+ engine_versions.delete_if { |_key, value| !valid_extracted_version?(value) }
34
+ version = engine_versions.select { |engine, _value| engine.to_s.match(name) }
35
+
36
+ version
37
+ end
38
+
39
+ sig { params(version: String).returns(T::Boolean) }
40
+ def valid_extracted_version?(version)
41
+ version.match?(NODE_ENGINE_SUPPORTED_REGEX)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -160,6 +160,14 @@ module Dependabot
160
160
  AUTH_ERROR: /YN0001:*.*Fatal Error: could not read Username for '(?<url>.*)': terminal prompts disabled/
161
161
  }.freeze, T::Hash[String, Regexp])
162
162
 
163
+ YN0001_REQ_NOT_FOUND_CODES = T.let({
164
+ REQUIREMENT_NOT_SATISFIED: /provides (?<dep>.*)(.*?)with version (?<ver>.*), which doesn't satisfy what (?<pkg>.*) requests/, # rubocop:disable Layout/LineLength
165
+ REQUIREMENT_NOT_PROVIDED: /(?<dep>.*)(.*?)doesn't provide (?<pkg>.*)(.*?), requested by (?<parent>.*)/
166
+ }.freeze, T::Hash[String, Regexp])
167
+
168
+ # registry returns malformed response
169
+ REGISTRY_NOT_REACHABLE = /Received malformed response from registry for "(?<ver>.*)". The registry may be down./
170
+
163
171
  class Utils
164
172
  extend T::Sig
165
173
 
@@ -212,6 +220,13 @@ module Dependabot
212
220
  return Dependabot::PrivateSourceAuthenticationFailure.new(url)
213
221
  end
214
222
  end
223
+
224
+ YN0001_REQ_NOT_FOUND_CODES.each do |(_yn0001_key, yn0001_regex)|
225
+ if (msg = message.match(yn0001_regex))
226
+ return Dependabot::DependencyFileNotResolvable.new(msg)
227
+ end
228
+ end
229
+
215
230
  Dependabot::DependabotError.new(message)
216
231
  }
217
232
  },
@@ -568,6 +583,15 @@ module Dependabot
568
583
  },
569
584
  in_usage: false,
570
585
  matchfn: nil
586
+ },
587
+ {
588
+ patterns: [REGISTRY_NOT_REACHABLE],
589
+ handler: lambda { |message, _error, _params|
590
+ msg = message.match(REGISTRY_NOT_REACHABLE)
591
+ Dependabot::DependencyFileNotResolvable.new(msg)
592
+ },
593
+ in_usage: false,
594
+ matchfn: nil
571
595
  }
572
596
  ].freeze, T::Array[{
573
597
  patterns: T::Array[T.any(String, Regexp)],
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.274.0
4
+ version: 0.276.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-09-05 00:00:00.000000000 Z
11
+ date: 2024-09-19 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.274.0
19
+ version: 0.276.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.274.0
26
+ version: 0.276.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -340,12 +340,13 @@ files:
340
340
  - lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb
341
341
  - lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb
342
342
  - lib/dependabot/npm_and_yarn/version.rb
343
+ - lib/dependabot/npm_and_yarn/version_selector.rb
343
344
  homepage: https://github.com/dependabot/dependabot-core
344
345
  licenses:
345
346
  - MIT
346
347
  metadata:
347
348
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
348
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.274.0
349
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.276.0
349
350
  post_install_message:
350
351
  rdoc_options: []
351
352
  require_paths: