dependabot-npm_and_yarn 0.235.0 → 0.237.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 +4 -4
- data/helpers/lib/pnpm/lockfile-parser.js +1 -0
- data/helpers/package-lock.json +144 -132
- data/helpers/package.json +4 -4
- data/lib/dependabot/npm_and_yarn/file_fetcher.rb +25 -6
- data/lib/dependabot/npm_and_yarn/file_parser/json_lock.rb +1 -1
- data/lib/dependabot/npm_and_yarn/file_parser/lockfile_parser.rb +1 -1
- data/lib/dependabot/npm_and_yarn/file_parser/pnpm_lock.rb +1 -1
- data/lib/dependabot/npm_and_yarn/file_parser/yarn_lock.rb +1 -1
- data/lib/dependabot/npm_and_yarn/file_parser.rb +49 -75
- data/lib/dependabot/npm_and_yarn/file_updater/npm_lockfile_updater.rb +15 -21
- data/lib/dependabot/npm_and_yarn/file_updater/npmrc_builder.rb +10 -2
- data/lib/dependabot/npm_and_yarn/file_updater/package_json_preparer.rb +6 -8
- data/lib/dependabot/npm_and_yarn/file_updater/package_json_updater.rb +1 -1
- data/lib/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater.rb +14 -5
- data/lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb +1 -1
- data/lib/dependabot/npm_and_yarn/helpers.rb +14 -9
- data/lib/dependabot/npm_and_yarn/package_manager.rb +4 -4
- data/lib/dependabot/npm_and_yarn/registry_parser.rb +75 -0
- data/lib/dependabot/npm_and_yarn/update_checker/registry_finder.rb +76 -61
- data/lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb +1 -10
- data/lib/dependabot/npm_and_yarn/update_checker.rb +1 -2
- data/lib/dependabot/npm_and_yarn.rb +1 -1
- metadata +22 -7
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "json"
|
5
|
+
require "sorbet-runtime"
|
5
6
|
require "dependabot/experiments"
|
6
7
|
require "dependabot/logger"
|
7
8
|
require "dependabot/file_fetchers"
|
@@ -14,6 +15,9 @@ require "dependabot/npm_and_yarn/file_parser/lockfile_parser"
|
|
14
15
|
module Dependabot
|
15
16
|
module NpmAndYarn
|
16
17
|
class FileFetcher < Dependabot::FileFetchers::Base # rubocop:disable Metrics/ClassLength
|
18
|
+
extend T::Sig
|
19
|
+
extend T::Helpers
|
20
|
+
|
17
21
|
require_relative "file_fetcher/path_dependency_builder"
|
18
22
|
|
19
23
|
# Npm always prefixes file paths in the lockfile "version" with "file:"
|
@@ -56,7 +60,7 @@ module Dependabot
|
|
56
60
|
def ecosystem_versions
|
57
61
|
package_managers = {}
|
58
62
|
|
59
|
-
package_managers["npm"] =
|
63
|
+
package_managers["npm"] = npm_version if package_lock
|
60
64
|
package_managers["yarn"] = yarn_version if yarn_version
|
61
65
|
package_managers["pnpm"] = pnpm_version if pnpm_version
|
62
66
|
package_managers["shrinkwrap"] = 1 if shrinkwrap
|
@@ -67,8 +71,7 @@ module Dependabot
|
|
67
71
|
}
|
68
72
|
end
|
69
73
|
|
70
|
-
|
71
|
-
|
74
|
+
sig { override.returns(T::Array[DependencyFile]) }
|
72
75
|
def fetch_files
|
73
76
|
fetched_files = []
|
74
77
|
fetched_files << package_json
|
@@ -82,6 +85,12 @@ module Dependabot
|
|
82
85
|
fetched_files.uniq
|
83
86
|
end
|
84
87
|
|
88
|
+
private
|
89
|
+
|
90
|
+
def recurse_submodules_when_cloning?
|
91
|
+
true
|
92
|
+
end
|
93
|
+
|
85
94
|
def npm_files
|
86
95
|
fetched_npm_files = []
|
87
96
|
fetched_npm_files << package_lock if package_lock
|
@@ -161,10 +170,14 @@ module Dependabot
|
|
161
170
|
@inferred_npmrc = nil
|
162
171
|
end
|
163
172
|
|
173
|
+
def npm_version
|
174
|
+
Helpers.npm_version_numeric(package_lock.content)
|
175
|
+
end
|
176
|
+
|
164
177
|
def yarn_version
|
165
178
|
return @yarn_version if defined?(@yarn_version)
|
166
179
|
|
167
|
-
@yarn_version = package_manager.
|
180
|
+
@yarn_version = package_manager.requested_version("yarn") || guess_yarn_version
|
168
181
|
end
|
169
182
|
|
170
183
|
def guess_yarn_version
|
@@ -176,13 +189,19 @@ module Dependabot
|
|
176
189
|
def pnpm_version
|
177
190
|
return @pnpm_version if defined?(@pnpm_version)
|
178
191
|
|
179
|
-
|
192
|
+
version = package_manager.requested_version("pnpm") || guess_pnpm_version
|
193
|
+
|
194
|
+
if version && Version.new(version.to_s) < Version.new("7")
|
195
|
+
raise ToolVersionNotSupported.new("PNPM", version.to_s, "7.*, 8.*")
|
196
|
+
end
|
197
|
+
|
198
|
+
@pnpm_version = version
|
180
199
|
end
|
181
200
|
|
182
201
|
def guess_pnpm_version
|
183
202
|
return unless pnpm_lock
|
184
203
|
|
185
|
-
Helpers.
|
204
|
+
Helpers.pnpm_version_numeric(pnpm_lock)
|
186
205
|
end
|
187
206
|
|
188
207
|
def package_manager
|
@@ -7,7 +7,7 @@ require "dependabot/npm_and_yarn/helpers"
|
|
7
7
|
|
8
8
|
module Dependabot
|
9
9
|
module NpmAndYarn
|
10
|
-
class FileParser
|
10
|
+
class FileParser < Dependabot::FileParsers::Base
|
11
11
|
class LockfileParser
|
12
12
|
require "dependabot/npm_and_yarn/file_parser/yarn_lock"
|
13
13
|
require "dependabot/npm_and_yarn/file_parser/pnpm_lock"
|
@@ -11,6 +11,7 @@ require "dependabot/npm_and_yarn/helpers"
|
|
11
11
|
require "dependabot/npm_and_yarn/native_helpers"
|
12
12
|
require "dependabot/npm_and_yarn/version"
|
13
13
|
require "dependabot/npm_and_yarn/requirement"
|
14
|
+
require "dependabot/npm_and_yarn/registry_parser"
|
14
15
|
require "dependabot/git_metadata_fetcher"
|
15
16
|
require "dependabot/git_commit_checker"
|
16
17
|
require "dependabot/errors"
|
@@ -34,6 +35,15 @@ module Dependabot
|
|
34
35
|
)?$
|
35
36
|
}ix
|
36
37
|
|
38
|
+
def self.each_dependency(json)
|
39
|
+
DEPENDENCY_TYPES.each do |type|
|
40
|
+
deps = json[type] || {}
|
41
|
+
deps.each do |name, requirement|
|
42
|
+
yield name, requirement, type
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
37
47
|
def parse
|
38
48
|
dependency_set = DependencySet.new
|
39
49
|
dependency_set += manifest_dependencies
|
@@ -41,11 +51,16 @@ module Dependabot
|
|
41
51
|
|
42
52
|
dependencies = Helpers.dependencies_with_all_versions_metadata(dependency_set)
|
43
53
|
|
44
|
-
# TODO: Currently, Dependabot can't handle dependencies that have both
|
45
|
-
# a git source *and* a non-git source. Fix that!
|
46
54
|
dependencies.reject do |dep|
|
47
|
-
|
48
|
-
|
55
|
+
reqs = dep.requirements
|
56
|
+
|
57
|
+
# Ignore dependencies defined in support files, since we don't want PRs for those
|
58
|
+
support_reqs = reqs.select { |r| support_package_files.any? { |f| f.name == r[:file] } }
|
59
|
+
next true if support_reqs.any?
|
60
|
+
|
61
|
+
# TODO: Currently, Dependabot can't handle dependencies that have both
|
62
|
+
# a git source *and* a non-git source. Fix that!
|
63
|
+
git_reqs = reqs.select { |r| r.dig(:source, :type) == "git" }
|
49
64
|
next false if git_reqs.none?
|
50
65
|
next true if git_reqs.map { |r| r.fetch(:source) }.uniq.count > 1
|
51
66
|
|
@@ -59,22 +74,24 @@ module Dependabot
|
|
59
74
|
dependency_set = DependencySet.new
|
60
75
|
|
61
76
|
package_files.each do |file|
|
77
|
+
json = JSON.parse(file.content)
|
78
|
+
|
62
79
|
# TODO: Currently, Dependabot can't handle flat dependency files
|
63
80
|
# (and will error at the FileUpdater stage, because the
|
64
81
|
# UpdateChecker doesn't take account of flat resolution).
|
65
|
-
next if
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
82
|
+
next if json["flat"]
|
83
|
+
|
84
|
+
self.class.each_dependency(json) do |name, requirement, type|
|
85
|
+
next unless requirement.is_a?(String)
|
86
|
+
|
87
|
+
# Skip dependencies using Yarn workspace cross-references as requirements
|
88
|
+
next if requirement.start_with?("workspace:")
|
89
|
+
|
90
|
+
requirement = "*" if requirement == ""
|
91
|
+
dep = build_dependency(
|
92
|
+
file: file, type: type, name: name, requirement: requirement
|
93
|
+
)
|
94
|
+
dependency_set << dep if dep
|
78
95
|
end
|
79
96
|
end
|
80
97
|
|
@@ -253,7 +270,10 @@ module Dependabot
|
|
253
270
|
return unless resolved_url.start_with?("http")
|
254
271
|
return if resolved_url.match?(/(?<!pkg\.)github/)
|
255
272
|
|
256
|
-
|
273
|
+
RegistryParser.new(
|
274
|
+
resolved_url: resolved_url,
|
275
|
+
credentials: credentials
|
276
|
+
).registry_source_for(name)
|
257
277
|
end
|
258
278
|
|
259
279
|
def requirement_for(requirement)
|
@@ -286,69 +306,23 @@ module Dependabot
|
|
286
306
|
}
|
287
307
|
end
|
288
308
|
|
289
|
-
def
|
290
|
-
|
291
|
-
if resolved_url.include?("/~/")
|
292
|
-
# Gemfury format
|
293
|
-
resolved_url.split("/~/").first
|
294
|
-
elsif resolved_url.include?("/#{name}/-/#{name}")
|
295
|
-
# MyGet / Bintray format
|
296
|
-
resolved_url.split("/#{name}/-/#{name}").first
|
297
|
-
.gsub("dl.bintray.com//", "api.bintray.com/npm/").
|
298
|
-
# GitLab format
|
299
|
-
gsub(%r{\/projects\/\d+}, "")
|
300
|
-
elsif resolved_url.include?("/#{name}/-/#{name.split('/').last}")
|
301
|
-
# Sonatype Nexus / Artifactory JFrog format
|
302
|
-
resolved_url.split("/#{name}/-/#{name.split('/').last}").first
|
303
|
-
elsif (cred_url = url_for_relevant_cred(resolved_url)) then cred_url
|
304
|
-
else
|
305
|
-
resolved_url.split("/")[0..2].join("/")
|
306
|
-
end
|
307
|
-
|
308
|
-
{ type: "registry", url: url }
|
309
|
+
def support_package_files
|
310
|
+
@support_package_files ||= sub_package_files.select(&:support_file?)
|
309
311
|
end
|
310
312
|
|
311
|
-
def
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
.select { |cred| cred["type"] == "npm_registry" }
|
317
|
-
.sort_by { |cred| cred["registry"].length }
|
318
|
-
.find do |details|
|
319
|
-
next true if resolved_url_host == details["registry"]
|
320
|
-
|
321
|
-
uri = if details["registry"]&.include?("://")
|
322
|
-
URI(details["registry"])
|
323
|
-
else
|
324
|
-
URI("https://#{details['registry']}")
|
325
|
-
end
|
326
|
-
resolved_url_host == uri.host && resolved_url.include?(details["registry"])
|
327
|
-
end
|
328
|
-
|
329
|
-
return unless credential_matching_url
|
330
|
-
|
331
|
-
# Trim the resolved URL so that it ends at the same point as the
|
332
|
-
# credential registry
|
333
|
-
reg = credential_matching_url["registry"]
|
334
|
-
resolved_url.gsub(/#{Regexp.quote(reg)}.*/, "") + reg
|
313
|
+
def sub_package_files
|
314
|
+
@sub_package_files ||=
|
315
|
+
dependency_files.select { |f| f.name.end_with?("package.json") }
|
316
|
+
.reject { |f| f.name == "package.json" }
|
317
|
+
.reject { |f| f.name.include?("node_modules/") }
|
335
318
|
end
|
336
319
|
|
337
320
|
def package_files
|
338
321
|
@package_files ||=
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
.reject { |f| f.name == "package.json" }
|
344
|
-
.reject { |f| f.name.include?("node_modules/") }
|
345
|
-
.reject(&:support_file?)
|
346
|
-
|
347
|
-
[
|
348
|
-
dependency_files.find { |f| f.name == "package.json" },
|
349
|
-
*sub_packages
|
350
|
-
].compact
|
351
|
-
end
|
322
|
+
[
|
323
|
+
dependency_files.find { |f| f.name == "package.json" },
|
324
|
+
*sub_package_files
|
325
|
+
].compact
|
352
326
|
end
|
353
327
|
|
354
328
|
def version_class
|
@@ -13,7 +13,7 @@ require "dependabot/shared_helpers"
|
|
13
13
|
# rubocop:disable Metrics/ClassLength
|
14
14
|
module Dependabot
|
15
15
|
module NpmAndYarn
|
16
|
-
class FileUpdater
|
16
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
17
17
|
class NpmLockfileUpdater
|
18
18
|
require_relative "npmrc_builder"
|
19
19
|
require_relative "package_json_updater"
|
@@ -562,13 +562,11 @@ module Dependabot
|
|
562
562
|
return content if git_dependencies_to_lock.empty?
|
563
563
|
|
564
564
|
json = JSON.parse(content)
|
565
|
-
NpmAndYarn::FileParser
|
566
|
-
|
567
|
-
|
568
|
-
next unless updated_version
|
565
|
+
NpmAndYarn::FileParser.each_dependency(json) do |nm, _, type|
|
566
|
+
updated_version = git_dependencies_to_lock.dig(nm, :version)
|
567
|
+
next unless updated_version
|
569
568
|
|
570
|
-
|
571
|
-
end
|
569
|
+
json[type][nm] = git_dependencies_to_lock[nm][:version]
|
572
570
|
end
|
573
571
|
|
574
572
|
indent = detect_indentation(content)
|
@@ -605,12 +603,10 @@ module Dependabot
|
|
605
603
|
def lock_deps_with_latest_reqs(content)
|
606
604
|
json = JSON.parse(content)
|
607
605
|
|
608
|
-
NpmAndYarn::FileParser
|
609
|
-
|
610
|
-
next unless requirement == "latest"
|
606
|
+
NpmAndYarn::FileParser.each_dependency(json) do |nm, requirement, type|
|
607
|
+
next unless requirement == "latest"
|
611
608
|
|
612
|
-
|
613
|
-
end
|
609
|
+
json[type][nm] = "*"
|
614
610
|
end
|
615
611
|
|
616
612
|
indent = detect_indentation(content)
|
@@ -721,17 +717,15 @@ module Dependabot
|
|
721
717
|
|
722
718
|
dependency_names_to_restore = (dependencies.map(&:name) + git_dependencies_to_lock.keys).uniq
|
723
719
|
|
724
|
-
NpmAndYarn::FileParser
|
725
|
-
|
726
|
-
next unless dependency_names_to_restore.include?(dependency_name)
|
720
|
+
NpmAndYarn::FileParser.each_dependency(parsed_package_json) do |dependency_name, original_requirement, type|
|
721
|
+
next unless dependency_names_to_restore.include?(dependency_name)
|
727
722
|
|
728
|
-
|
729
|
-
|
723
|
+
locked_requirement = parsed_updated_lockfile_content.dig("packages", "", type, dependency_name)
|
724
|
+
next unless locked_requirement
|
730
725
|
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
end
|
726
|
+
locked_req = %("#{dependency_name}": "#{locked_requirement}")
|
727
|
+
original_req = %("#{dependency_name}": "#{original_requirement}")
|
728
|
+
updated_lockfile_content = updated_lockfile_content.gsub(locked_req, original_req)
|
735
729
|
end
|
736
730
|
|
737
731
|
updated_lockfile_content
|
@@ -5,7 +5,7 @@ require "dependabot/npm_and_yarn/file_updater"
|
|
5
5
|
|
6
6
|
module Dependabot
|
7
7
|
module NpmAndYarn
|
8
|
-
class FileUpdater
|
8
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
9
9
|
# Build a .npmrc file from the lockfile content, credentials, and any
|
10
10
|
# committed .npmrc
|
11
11
|
# We should refactor this to use UpdateChecker::RegistryFinder
|
@@ -140,7 +140,10 @@ module Dependabot
|
|
140
140
|
@dependency_urls = dependencies.map do |dependency|
|
141
141
|
UpdateChecker::RegistryFinder.new(
|
142
142
|
dependency: dependency,
|
143
|
-
credentials: credentials
|
143
|
+
credentials: credentials,
|
144
|
+
npmrc_file: npmrc_file,
|
145
|
+
yarnrc_file: yarnrc_file,
|
146
|
+
yarnrc_yml_file: yarnrc_yml_file
|
144
147
|
).dependency_url
|
145
148
|
end
|
146
149
|
return @dependency_urls
|
@@ -309,6 +312,11 @@ module Dependabot
|
|
309
312
|
.find { |f| f.name.end_with?(".yarnrc") }
|
310
313
|
end
|
311
314
|
|
315
|
+
def yarnrc_yml_file
|
316
|
+
@yarnrc_yml_file ||= dependency_files
|
317
|
+
.find { |f| f.name.end_with?(".yarnrc.yml") }
|
318
|
+
end
|
319
|
+
|
312
320
|
def yarn_lock
|
313
321
|
@yarn_lock ||= dependency_files.find { |f| f.name == "yarn.lock" }
|
314
322
|
end
|
@@ -6,7 +6,7 @@ require "dependabot/npm_and_yarn/file_parser"
|
|
6
6
|
|
7
7
|
module Dependabot
|
8
8
|
module NpmAndYarn
|
9
|
-
class FileUpdater
|
9
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
10
10
|
class PackageJsonPreparer
|
11
11
|
def initialize(package_json_content:)
|
12
12
|
@package_json_content = package_json_content
|
@@ -72,14 +72,12 @@ module Dependabot
|
|
72
72
|
|
73
73
|
@git_ssh_requirements_to_swap = []
|
74
74
|
|
75
|
-
NpmAndYarn::FileParser
|
76
|
-
|
77
|
-
|
78
|
-
next unless req.start_with?("git+ssh:")
|
75
|
+
NpmAndYarn::FileParser.each_dependency(JSON.parse(package_json_content)) do |_, req, _t|
|
76
|
+
next unless req.is_a?(String)
|
77
|
+
next unless req.start_with?("git+ssh:")
|
79
78
|
|
80
|
-
|
81
|
-
|
82
|
-
end
|
79
|
+
req = req.split("#").first
|
80
|
+
@git_ssh_requirements_to_swap << req
|
83
81
|
end
|
84
82
|
|
85
83
|
@git_ssh_requirements_to_swap
|
@@ -5,7 +5,7 @@ require "dependabot/npm_and_yarn/file_updater"
|
|
5
5
|
|
6
6
|
module Dependabot
|
7
7
|
module NpmAndYarn
|
8
|
-
class FileUpdater
|
8
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
9
9
|
class PackageJsonUpdater
|
10
10
|
def initialize(package_json:, dependencies:)
|
11
11
|
@package_json = package_json
|
@@ -3,11 +3,12 @@
|
|
3
3
|
|
4
4
|
require "dependabot/npm_and_yarn/helpers"
|
5
5
|
require "dependabot/npm_and_yarn/update_checker/registry_finder"
|
6
|
+
require "dependabot/npm_and_yarn/registry_parser"
|
6
7
|
require "dependabot/shared_helpers"
|
7
8
|
|
8
9
|
module Dependabot
|
9
10
|
module NpmAndYarn
|
10
|
-
class FileUpdater
|
11
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
11
12
|
class PnpmLockfileUpdater
|
12
13
|
require_relative "npmrc_builder"
|
13
14
|
require_relative "package_json_updater"
|
@@ -35,7 +36,8 @@ module Dependabot
|
|
35
36
|
|
36
37
|
IRRESOLVABLE_PACKAGE = "ERR_PNPM_NO_MATCHING_VERSION"
|
37
38
|
INVALID_REQUIREMENT = "ERR_PNPM_SPEC_NOT_SUPPORTED_BY_ANY_RESOLVER"
|
38
|
-
|
39
|
+
UNREACHABLE_GIT = %r{ERR_PNPM_FETCH_404[ [^:print:]]+GET (?<url>https://codeload\.github\.com/[^/]+/[^/]+)/}
|
40
|
+
MISSING_PACKAGE = /ERR_PNPM_FETCH_404[ [^:print:]]+GET (?<dependency_url>.*): Not Found - 404/
|
39
41
|
|
40
42
|
def run_pnpm_update(pnpm_lock:)
|
41
43
|
SharedHelpers.in_a_temporary_repo_directory(base_dir, repo_contents_path) do
|
@@ -87,11 +89,18 @@ module Dependabot
|
|
87
89
|
raise_resolvability_error(error_message, pnpm_lock)
|
88
90
|
end
|
89
91
|
|
92
|
+
if error_message.match?(UNREACHABLE_GIT)
|
93
|
+
dependency_url = error_message.match(UNREACHABLE_GIT).named_captures.fetch("url")
|
94
|
+
|
95
|
+
raise Dependabot::GitDependenciesNotReachable, dependency_url
|
96
|
+
end
|
97
|
+
|
90
98
|
raise unless error_message.match?(MISSING_PACKAGE)
|
91
99
|
|
92
|
-
|
93
|
-
|
94
|
-
|
100
|
+
dependency_url = error_message.match(MISSING_PACKAGE)
|
101
|
+
.named_captures["dependency_url"]
|
102
|
+
|
103
|
+
package_name = RegistryParser.new(resolved_url: dependency_url, credentials: credentials).dependency_name
|
95
104
|
raise_missing_package_error(package_name, error_message, pnpm_lock)
|
96
105
|
end
|
97
106
|
|
@@ -14,7 +14,7 @@ require "dependabot/errors"
|
|
14
14
|
# rubocop:disable Metrics/ClassLength
|
15
15
|
module Dependabot
|
16
16
|
module NpmAndYarn
|
17
|
-
class FileUpdater
|
17
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
18
18
|
class YarnLockfileUpdater
|
19
19
|
require_relative "npmrc_builder"
|
20
20
|
require_relative "package_json_updater"
|
@@ -25,6 +25,16 @@ module Dependabot
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
# Mapping from lockfile versions to PNPM versions is at
|
29
|
+
# https://github.com/pnpm/spec/tree/274ff02de23376ad59773a9f25ecfedd03a41f64/lockfile, but simplify it for now.
|
30
|
+
def self.pnpm_version_numeric(pnpm_lock)
|
31
|
+
if pnpm_lockfile_version(pnpm_lock).to_f >= 5.4
|
32
|
+
8
|
33
|
+
else
|
34
|
+
6
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
28
38
|
def self.fetch_yarnrc_yml_value(key, default_value)
|
29
39
|
if File.exist?(".yarnrc.yml") && (yarnrc = YAML.load_file(".yarnrc.yml"))
|
30
40
|
yarnrc.fetch(key, default_value)
|
@@ -44,20 +54,11 @@ module Dependabot
|
|
44
54
|
@yarn_major_version ||= fetch_yarn_major_version
|
45
55
|
end
|
46
56
|
|
47
|
-
def self.pnpm_major_version
|
48
|
-
@pnpm_major_version ||= fetch_pnpm_major_version
|
49
|
-
end
|
50
|
-
|
51
57
|
def self.fetch_yarn_major_version
|
52
58
|
output = SharedHelpers.run_shell_command("yarn --version")
|
53
59
|
Version.new(output).major
|
54
60
|
end
|
55
61
|
|
56
|
-
def self.fetch_pnpm_major_version
|
57
|
-
output = SharedHelpers.run_shell_command("pnpm --version")
|
58
|
-
Version.new(output).major
|
59
|
-
end
|
60
|
-
|
61
62
|
def self.yarn_zero_install?
|
62
63
|
File.exist?(".pnp.cjs")
|
63
64
|
end
|
@@ -122,6 +123,10 @@ module Dependabot
|
|
122
123
|
SharedHelpers.run_shell_command(command, fingerprint: fingerprint)
|
123
124
|
end
|
124
125
|
|
126
|
+
def self.pnpm_lockfile_version(pnpm_lock)
|
127
|
+
pnpm_lock.content.match(/^lockfileVersion: ['"]?(?<version>[\d.]+)/)[:version]
|
128
|
+
end
|
129
|
+
|
125
130
|
def self.dependencies_with_all_versions_metadata(dependency_set)
|
126
131
|
dependency_set.dependencies.map do |dependency|
|
127
132
|
dependency.metadata[:all_versions] = dependency_set.all_versions_for_name(dependency.name)
|
@@ -8,11 +8,11 @@ module Dependabot
|
|
8
8
|
@package_json = package_json
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
return unless
|
11
|
+
def requested_version(name)
|
12
|
+
version = @package_json.fetch("packageManager", nil)
|
13
|
+
return unless version
|
14
14
|
|
15
|
-
version_match =
|
15
|
+
version_match = version.match(/#{name}@(?<version>\d+.\d+.\d+)/)
|
16
16
|
version_match&.named_captures&.fetch("version", nil)
|
17
17
|
end
|
18
18
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Dependabot
|
5
|
+
module NpmAndYarn
|
6
|
+
class RegistryParser
|
7
|
+
def initialize(resolved_url:, credentials:)
|
8
|
+
@resolved_url = resolved_url
|
9
|
+
@credentials = credentials
|
10
|
+
end
|
11
|
+
|
12
|
+
def registry_source_for(name)
|
13
|
+
url =
|
14
|
+
if resolved_url.include?("/~/")
|
15
|
+
# Gemfury format
|
16
|
+
resolved_url.split("/~/").first
|
17
|
+
elsif resolved_url.include?("/#{name}/-/#{name}")
|
18
|
+
# MyGet / Bintray format
|
19
|
+
resolved_url.split("/#{name}/-/#{name}").first
|
20
|
+
.gsub("dl.bintray.com//", "api.bintray.com/npm/").
|
21
|
+
# GitLab format
|
22
|
+
gsub(%r{\/projects\/\d+}, "")
|
23
|
+
elsif resolved_url.include?("/#{name}/-/#{name.split('/').last}")
|
24
|
+
# Sonatype Nexus / Artifactory JFrog format
|
25
|
+
resolved_url.split("/#{name}/-/#{name.split('/').last}").first
|
26
|
+
elsif (cred_url = url_for_relevant_cred) then cred_url
|
27
|
+
else
|
28
|
+
resolved_url.split("/")[0..2].join("/")
|
29
|
+
end
|
30
|
+
|
31
|
+
{ type: "registry", url: url }
|
32
|
+
end
|
33
|
+
|
34
|
+
def dependency_name
|
35
|
+
url_base = if resolved_url.include?("/-/")
|
36
|
+
resolved_url.split("/-/").first
|
37
|
+
else
|
38
|
+
resolved_url
|
39
|
+
end
|
40
|
+
|
41
|
+
url_base.split("/")[3..-1].join("/").gsub("%2F", "/")
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
attr_reader :resolved_url, :credentials
|
47
|
+
|
48
|
+
def url_for_relevant_cred
|
49
|
+
resolved_url_host = URI(resolved_url).host
|
50
|
+
|
51
|
+
credential_matching_url =
|
52
|
+
credentials
|
53
|
+
.select { |cred| cred["type"] == "npm_registry" }
|
54
|
+
.sort_by { |cred| cred["registry"].length }
|
55
|
+
.find do |details|
|
56
|
+
next true if resolved_url_host == details["registry"]
|
57
|
+
|
58
|
+
uri = if details["registry"]&.include?("://")
|
59
|
+
URI(details["registry"])
|
60
|
+
else
|
61
|
+
URI("https://#{details['registry']}")
|
62
|
+
end
|
63
|
+
resolved_url_host == uri.host && resolved_url.include?(details["registry"])
|
64
|
+
end
|
65
|
+
|
66
|
+
return unless credential_matching_url
|
67
|
+
|
68
|
+
# Trim the resolved URL so that it ends at the same point as the
|
69
|
+
# credential registry
|
70
|
+
reg = credential_matching_url["registry"]
|
71
|
+
resolved_url.gsub(/#{Regexp.quote(reg)}.*/, "") + reg
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|