dependabot-npm_and_yarn 0.212.0 → 0.214.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/helpers/.eslintrc +1 -1
- data/helpers/README.md +2 -2
- data/helpers/lib/npm/vulnerability-auditor.js +7 -7
- data/helpers/package-lock.json +2781 -2547
- data/helpers/package.json +5 -5
- data/helpers/test/npm6/fixtures/conflicting-dependency-parser/deeply-nested/package-lock.json +3 -3
- data/lib/dependabot/npm_and_yarn/file_fetcher/path_dependency_builder.rb +11 -2
- data/lib/dependabot/npm_and_yarn/file_fetcher.rb +90 -5
- data/lib/dependabot/npm_and_yarn/file_parser/lockfile_parser.rb +15 -4
- data/lib/dependabot/npm_and_yarn/file_parser.rb +15 -6
- data/lib/dependabot/npm_and_yarn/file_updater/npm_lockfile_updater.rb +35 -21
- data/lib/dependabot/npm_and_yarn/file_updater/npmrc_builder.rb +86 -7
- data/lib/dependabot/npm_and_yarn/file_updater/package_json_updater.rb +2 -2
- data/lib/dependabot/npm_and_yarn/file_updater/yarn_lockfile_updater.rb +96 -32
- data/lib/dependabot/npm_and_yarn/file_updater.rb +53 -1
- data/lib/dependabot/npm_and_yarn/helpers.rb +94 -0
- data/lib/dependabot/npm_and_yarn/package_name.rb +2 -2
- data/lib/dependabot/npm_and_yarn/requirement.rb +3 -3
- data/lib/dependabot/npm_and_yarn/update_checker/dependency_files_builder.rb +43 -1
- data/lib/dependabot/npm_and_yarn/update_checker/latest_version_finder.rb +13 -14
- data/lib/dependabot/npm_and_yarn/update_checker/library_detector.rb +16 -3
- data/lib/dependabot/npm_and_yarn/update_checker/registry_finder.rb +77 -23
- data/lib/dependabot/npm_and_yarn/update_checker/requirements_updater.rb +3 -4
- data/lib/dependabot/npm_and_yarn/update_checker/subdependency_version_resolver.rb +19 -4
- data/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb +74 -30
- data/lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb +33 -8
- data/lib/dependabot/npm_and_yarn/update_checker.rb +76 -21
- data/lib/dependabot/npm_and_yarn/version.rb +1 -1
- data/lib/dependabot/npm_and_yarn.rb +2 -0
- metadata +13 -56
- data/lib/dependabot/npm_and_yarn/file_parser/yarn_lockfile_parser.rb +0 -59
@@ -4,6 +4,7 @@ require "uri"
|
|
4
4
|
|
5
5
|
require "dependabot/npm_and_yarn/file_updater"
|
6
6
|
require "dependabot/npm_and_yarn/file_parser"
|
7
|
+
require "dependabot/npm_and_yarn/helpers"
|
7
8
|
require "dependabot/npm_and_yarn/update_checker/registry_finder"
|
8
9
|
require "dependabot/npm_and_yarn/native_helpers"
|
9
10
|
require "dependabot/shared_helpers"
|
@@ -17,9 +18,10 @@ module Dependabot
|
|
17
18
|
require_relative "npmrc_builder"
|
18
19
|
require_relative "package_json_updater"
|
19
20
|
|
20
|
-
def initialize(dependencies:, dependency_files:, credentials:)
|
21
|
+
def initialize(dependencies:, dependency_files:, repo_contents_path:, credentials:)
|
21
22
|
@dependencies = dependencies
|
22
23
|
@dependency_files = dependency_files
|
24
|
+
@repo_contents_path = repo_contents_path
|
23
25
|
@credentials = credentials
|
24
26
|
end
|
25
27
|
|
@@ -35,12 +37,11 @@ module Dependabot
|
|
35
37
|
|
36
38
|
private
|
37
39
|
|
38
|
-
attr_reader :dependencies, :dependency_files, :credentials
|
40
|
+
attr_reader :dependencies, :dependency_files, :repo_contents_path, :credentials
|
39
41
|
|
40
|
-
UNREACHABLE_GIT = /ls-remote --tags --heads (?<url>.*)
|
41
|
-
TIMEOUT_FETCHING_PACKAGE =
|
42
|
-
|
43
|
-
INVALID_PACKAGE = /Can't add "(?<package_req>.*)": invalid/.freeze
|
42
|
+
UNREACHABLE_GIT = /ls-remote --tags --heads (?<url>.*)/
|
43
|
+
TIMEOUT_FETCHING_PACKAGE = %r{(?<url>.+)/(?<package>[^/]+): ETIMEDOUT}
|
44
|
+
INVALID_PACKAGE = /Can't add "(?<package_req>.*)": invalid/
|
44
45
|
|
45
46
|
def top_level_dependencies
|
46
47
|
dependencies.select(&:top_level?)
|
@@ -51,13 +52,14 @@ module Dependabot
|
|
51
52
|
end
|
52
53
|
|
53
54
|
def updated_yarn_lock(yarn_lock)
|
54
|
-
|
55
|
-
|
55
|
+
base_dir = dependency_files.first.directory
|
56
|
+
SharedHelpers.in_a_temporary_repo_directory(base_dir, repo_contents_path) do
|
57
|
+
write_temporary_dependency_files(yarn_lock)
|
56
58
|
lockfile_name = Pathname.new(yarn_lock.name).basename.to_s
|
57
59
|
path = Pathname.new(yarn_lock.name).dirname.to_s
|
58
60
|
updated_files = run_current_yarn_update(
|
59
61
|
path: path,
|
60
|
-
|
62
|
+
yarn_lock: yarn_lock
|
61
63
|
)
|
62
64
|
updated_files.fetch(lockfile_name)
|
63
65
|
end
|
@@ -65,7 +67,7 @@ module Dependabot
|
|
65
67
|
handle_yarn_lock_updater_error(e, yarn_lock)
|
66
68
|
end
|
67
69
|
|
68
|
-
def run_current_yarn_update(path:,
|
70
|
+
def run_current_yarn_update(path:, yarn_lock:)
|
69
71
|
top_level_dependency_updates = top_level_dependencies.map do |d|
|
70
72
|
{
|
71
73
|
name: d.name,
|
@@ -76,12 +78,12 @@ module Dependabot
|
|
76
78
|
|
77
79
|
run_yarn_updater(
|
78
80
|
path: path,
|
79
|
-
|
81
|
+
yarn_lock: yarn_lock,
|
80
82
|
top_level_dependency_updates: top_level_dependency_updates
|
81
83
|
)
|
82
84
|
end
|
83
85
|
|
84
|
-
def run_previous_yarn_update(path:,
|
86
|
+
def run_previous_yarn_update(path:, yarn_lock:)
|
85
87
|
previous_top_level_dependencies = top_level_dependencies.map do |d|
|
86
88
|
{
|
87
89
|
name: d.name,
|
@@ -94,22 +96,29 @@ module Dependabot
|
|
94
96
|
|
95
97
|
run_yarn_updater(
|
96
98
|
path: path,
|
97
|
-
|
99
|
+
yarn_lock: yarn_lock,
|
98
100
|
top_level_dependency_updates: previous_top_level_dependencies
|
99
101
|
)
|
100
102
|
end
|
101
103
|
|
102
104
|
# rubocop:disable Metrics/PerceivedComplexity
|
103
|
-
def run_yarn_updater(path:,
|
104
|
-
top_level_dependency_updates:)
|
105
|
+
def run_yarn_updater(path:, yarn_lock:, top_level_dependency_updates:)
|
105
106
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
106
107
|
Dir.chdir(path) do
|
107
108
|
if top_level_dependency_updates.any?
|
108
|
-
|
109
|
-
top_level_dependency_updates: top_level_dependency_updates
|
110
|
-
|
109
|
+
if Helpers.yarn_berry?(yarn_lock)
|
110
|
+
run_yarn_berry_top_level_updater(top_level_dependency_updates: top_level_dependency_updates,
|
111
|
+
yarn_lock: yarn_lock)
|
112
|
+
else
|
113
|
+
|
114
|
+
run_yarn_top_level_updater(
|
115
|
+
top_level_dependency_updates: top_level_dependency_updates
|
116
|
+
)
|
117
|
+
end
|
118
|
+
elsif Helpers.yarn_berry?(yarn_lock)
|
119
|
+
run_yarn_berry_subdependency_updater(yarn_lock: yarn_lock)
|
111
120
|
else
|
112
|
-
run_yarn_subdependency_updater(
|
121
|
+
run_yarn_subdependency_updater(yarn_lock: yarn_lock)
|
113
122
|
end
|
114
123
|
end
|
115
124
|
end
|
@@ -133,6 +142,43 @@ module Dependabot
|
|
133
142
|
|
134
143
|
# rubocop:enable Metrics/PerceivedComplexity
|
135
144
|
|
145
|
+
def run_yarn_berry_top_level_updater(top_level_dependency_updates:, yarn_lock:)
|
146
|
+
write_temporary_dependency_files(yarn_lock)
|
147
|
+
# If the requirements have changed, it means we've updated the
|
148
|
+
# package.json file(s), and we can just run yarn install to get the
|
149
|
+
# lockfile in the right state. Otherwise we'll need to manually update
|
150
|
+
# the lockfile.
|
151
|
+
|
152
|
+
command = if top_level_dependency_updates.all? { |dep| requirements_changed?(dep[:name]) }
|
153
|
+
"yarn install #{Helpers.yarn_berry_args}".strip
|
154
|
+
else
|
155
|
+
updates = top_level_dependency_updates.collect do |dep|
|
156
|
+
dep[:name]
|
157
|
+
end
|
158
|
+
|
159
|
+
"yarn up -R #{updates.join(' ')} #{Helpers.yarn_berry_args}".strip
|
160
|
+
end
|
161
|
+
Helpers.run_yarn_commands(command)
|
162
|
+
{ yarn_lock.name => File.read(yarn_lock.name) }
|
163
|
+
end
|
164
|
+
|
165
|
+
def requirements_changed?(dependency_name)
|
166
|
+
dep = top_level_dependencies.first { |d| d.name == dependency_name }
|
167
|
+
dep.requirements != dep.previous_requirements
|
168
|
+
end
|
169
|
+
|
170
|
+
def run_yarn_berry_subdependency_updater(yarn_lock:)
|
171
|
+
dep = sub_dependencies.first
|
172
|
+
update = "#{dep.name}@#{dep.version}"
|
173
|
+
|
174
|
+
Helpers.run_yarn_commands(
|
175
|
+
"yarn add #{update} #{Helpers.yarn_berry_args}".strip,
|
176
|
+
"yarn dedupe #{dep.name} #{Helpers.yarn_berry_args}".strip,
|
177
|
+
"yarn remove #{dep.name} #{Helpers.yarn_berry_args}".strip
|
178
|
+
)
|
179
|
+
{ yarn_lock.name => File.read(yarn_lock.name) }
|
180
|
+
end
|
181
|
+
|
136
182
|
def run_yarn_top_level_updater(top_level_dependency_updates:)
|
137
183
|
SharedHelpers.run_helper_subprocess(
|
138
184
|
command: NativeHelpers.helper_path,
|
@@ -144,7 +190,8 @@ module Dependabot
|
|
144
190
|
)
|
145
191
|
end
|
146
192
|
|
147
|
-
def run_yarn_subdependency_updater(
|
193
|
+
def run_yarn_subdependency_updater(yarn_lock:)
|
194
|
+
lockfile_name = Pathname.new(yarn_lock.name).basename.to_s
|
148
195
|
SharedHelpers.run_helper_subprocess(
|
149
196
|
command: NativeHelpers.helper_path,
|
150
197
|
function: "yarn:updateSubdependency",
|
@@ -259,12 +306,11 @@ module Dependabot
|
|
259
306
|
|
260
307
|
@resolvable_before_update[yarn_lock.name] =
|
261
308
|
begin
|
262
|
-
|
263
|
-
|
264
|
-
|
309
|
+
base_dir = dependency_files.first.directory
|
310
|
+
SharedHelpers.in_a_temporary_repo_directory(base_dir, repo_contents_path) do
|
311
|
+
write_temporary_dependency_files(yarn_lock, update_package_json: false)
|
265
312
|
path = Pathname.new(yarn_lock.name).dirname.to_s
|
266
|
-
run_previous_yarn_update(path: path,
|
267
|
-
lockfile_name: lockfile_name)
|
313
|
+
run_previous_yarn_update(path: path, yarn_lock: yarn_lock)
|
268
314
|
end
|
269
315
|
|
270
316
|
true
|
@@ -282,11 +328,15 @@ module Dependabot
|
|
282
328
|
end
|
283
329
|
end
|
284
330
|
|
285
|
-
def write_temporary_dependency_files(update_package_json: true)
|
331
|
+
def write_temporary_dependency_files(yarn_lock, update_package_json: true)
|
286
332
|
write_lockfiles
|
287
333
|
|
288
|
-
|
289
|
-
|
334
|
+
if Helpers.yarn_berry?(yarn_lock)
|
335
|
+
File.write(".yarnrc.yml", yarnrc_yml_content) if yarnrc_yml_file
|
336
|
+
else
|
337
|
+
File.write(".npmrc", npmrc_content) unless Helpers.yarn_berry?(yarn_lock)
|
338
|
+
File.write(".yarnrc", yarnrc_content) if yarnrc_specifies_private_reg?
|
339
|
+
end
|
290
340
|
|
291
341
|
package_files.each do |file|
|
292
342
|
path = file.name
|
@@ -420,7 +470,8 @@ module Dependabot
|
|
420
470
|
dependency: missing_dep,
|
421
471
|
credentials: credentials,
|
422
472
|
npmrc_file: npmrc_file,
|
423
|
-
yarnrc_file: yarnrc_file
|
473
|
+
yarnrc_file: yarnrc_file,
|
474
|
+
yarnrc_yml_file: yarnrc_yml_file
|
424
475
|
).registry
|
425
476
|
|
426
477
|
return if UpdateChecker::RegistryFinder.central_registry?(reg) && !package_name.start_with?("@")
|
@@ -471,7 +522,7 @@ module Dependabot
|
|
471
522
|
npmrc_content.match?(/^package-lock\s*=\s*false/)
|
472
523
|
end
|
473
524
|
|
474
|
-
def
|
525
|
+
def yarnrc_specifies_private_reg?
|
475
526
|
return false unless yarnrc_file
|
476
527
|
|
477
528
|
regex = UpdateChecker::RegistryFinder::YARN_GLOBAL_REGISTRY_REGEX
|
@@ -484,11 +535,16 @@ module Dependabot
|
|
484
535
|
|
485
536
|
return false unless yarnrc_global_registry
|
486
537
|
|
487
|
-
|
538
|
+
UpdateChecker::RegistryFinder::CENTRAL_REGISTRIES.any? do |r|
|
539
|
+
r.include?(URI(yarnrc_global_registry).host)
|
540
|
+
end
|
488
541
|
end
|
489
542
|
|
490
543
|
def yarnrc_content
|
491
|
-
|
544
|
+
NpmrcBuilder.new(
|
545
|
+
credentials: credentials,
|
546
|
+
dependency_files: dependency_files
|
547
|
+
).yarnrc_content
|
492
548
|
end
|
493
549
|
|
494
550
|
def sanitized_package_json_content(content)
|
@@ -524,6 +580,14 @@ module Dependabot
|
|
524
580
|
def npmrc_file
|
525
581
|
dependency_files.find { |f| f.name == ".npmrc" }
|
526
582
|
end
|
583
|
+
|
584
|
+
def yarnrc_yml_file
|
585
|
+
dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") }
|
586
|
+
end
|
587
|
+
|
588
|
+
def yarnrc_yml_content
|
589
|
+
yarnrc_yml_file.content
|
590
|
+
end
|
527
591
|
end
|
528
592
|
end
|
529
593
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "dependabot/file_updaters"
|
4
4
|
require "dependabot/file_updaters/base"
|
5
|
+
require "dependabot/file_updaters/vendor_updater"
|
5
6
|
require "dependabot/npm_and_yarn/dependency_files_filterer"
|
6
7
|
require "dependabot/npm_and_yarn/sub_dependency_files_filterer"
|
7
8
|
|
@@ -53,11 +54,61 @@ module Dependabot
|
|
53
54
|
)
|
54
55
|
end
|
55
56
|
|
56
|
-
updated_files
|
57
|
+
vendor_updated_files(updated_files)
|
57
58
|
end
|
58
59
|
|
59
60
|
private
|
60
61
|
|
62
|
+
def vendor_updated_files(updated_files)
|
63
|
+
base_dir = updated_files.first.directory
|
64
|
+
pnp_updater.updated_vendor_cache_files(base_directory: base_dir).each do |file|
|
65
|
+
updated_files << file if file.name == ".pnp.cjs" || file.name == ".pnp.data.json"
|
66
|
+
end
|
67
|
+
# updated .pnp.cjs means zero install, include cache
|
68
|
+
if updated_files.find { |f| f.name == ".pnp.cjs" }
|
69
|
+
vendor_updater.updated_vendor_cache_files(base_directory: base_dir).each { |file| updated_files << file }
|
70
|
+
end
|
71
|
+
install_state_updater.updated_vendor_cache_files(base_directory: base_dir).each do |file|
|
72
|
+
updated_files << file
|
73
|
+
end
|
74
|
+
|
75
|
+
updated_files
|
76
|
+
end
|
77
|
+
|
78
|
+
# Dynamically fetch the vendor cache folder from yarn
|
79
|
+
def vendor_cache_dir
|
80
|
+
return @vendor_cache_dir if defined?(@vendor_cache_dir)
|
81
|
+
|
82
|
+
@vendor_cache_dir = Helpers.fetch_yarnrc_yml_value("cacheFolder", "./.yarn/cache")
|
83
|
+
end
|
84
|
+
|
85
|
+
def install_state_path
|
86
|
+
return @install_state_path if defined?(@install_state_path)
|
87
|
+
|
88
|
+
@install_state_path = Helpers.fetch_yarnrc_yml_value("installStatePath", "./.yarn/install-state.gz")
|
89
|
+
end
|
90
|
+
|
91
|
+
def vendor_updater
|
92
|
+
Dependabot::FileUpdaters::VendorUpdater.new(
|
93
|
+
repo_contents_path: repo_contents_path,
|
94
|
+
vendor_dir: vendor_cache_dir
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
def install_state_updater
|
99
|
+
Dependabot::FileUpdaters::VendorUpdater.new(
|
100
|
+
repo_contents_path: repo_contents_path,
|
101
|
+
vendor_dir: install_state_path
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def pnp_updater
|
106
|
+
Dependabot::FileUpdaters::VendorUpdater.new(
|
107
|
+
repo_contents_path: repo_contents_path,
|
108
|
+
vendor_dir: "./"
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
61
112
|
def filtered_dependency_files
|
62
113
|
@filtered_dependency_files ||=
|
63
114
|
if dependencies.select(&:top_level?).any?
|
@@ -175,6 +226,7 @@ module Dependabot
|
|
175
226
|
YarnLockfileUpdater.new(
|
176
227
|
dependencies: dependencies,
|
177
228
|
dependency_files: dependency_files,
|
229
|
+
repo_contents_path: repo_contents_path,
|
178
230
|
credentials: credentials
|
179
231
|
)
|
180
232
|
end
|
@@ -15,6 +15,100 @@ module Dependabot
|
|
15
15
|
rescue JSON::ParserError
|
16
16
|
6
|
17
17
|
end
|
18
|
+
|
19
|
+
def self.fetch_yarnrc_yml_value(key, default_value)
|
20
|
+
if File.exist?(".yarnrc.yml") && (yarnrc = YAML.load_file(".yarnrc.yml"))
|
21
|
+
yarnrc.fetch(key, default_value)
|
22
|
+
else
|
23
|
+
default_value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.yarn_berry?(yarn_lock)
|
28
|
+
yaml = YAML.safe_load(yarn_lock.content)
|
29
|
+
yaml.key?("__metadata")
|
30
|
+
rescue StandardError
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.yarn_major_version
|
35
|
+
output = SharedHelpers.run_shell_command("yarn --version")
|
36
|
+
Version.new(output).major
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.yarn_zero_install?
|
40
|
+
File.exist?(".pnp.cjs")
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.yarn_berry_args
|
44
|
+
if yarn_major_version == 2
|
45
|
+
""
|
46
|
+
elsif yarn_major_version >= 3 && yarn_zero_install?
|
47
|
+
"--mode=skip-build"
|
48
|
+
else
|
49
|
+
"--mode=update-lockfile"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.setup_yarn_berry
|
54
|
+
# Always disable immutable installs so yarn's CI detection doesn't prevent updates.
|
55
|
+
SharedHelpers.run_shell_command("yarn config set enableImmutableInstalls false")
|
56
|
+
# We never want to execute postinstall scripts, either set this config or mode=skip-build must be set
|
57
|
+
if yarn_major_version == 2 || !yarn_zero_install?
|
58
|
+
SharedHelpers.run_shell_command("yarn config set enableScripts false")
|
59
|
+
end
|
60
|
+
if (http_proxy = ENV.fetch("HTTP_PROXY", false))
|
61
|
+
SharedHelpers.run_shell_command("yarn config set httpProxy #{http_proxy}")
|
62
|
+
end
|
63
|
+
if (https_proxy = ENV.fetch("HTTPS_PROXY", false))
|
64
|
+
SharedHelpers.run_shell_command("yarn config set httpsProxy #{https_proxy}")
|
65
|
+
end
|
66
|
+
return unless (ca_file_path = ENV.fetch("NODE_EXTRA_CA_CERTS", false))
|
67
|
+
|
68
|
+
if yarn_major_version >= 4
|
69
|
+
SharedHelpers.run_shell_command("yarn config set httpsCaFilePath #{ca_file_path}")
|
70
|
+
else
|
71
|
+
SharedHelpers.run_shell_command("yarn config set caFilePath #{ca_file_path}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Run any number of yarn commands while ensuring that `enableScripts` is
|
76
|
+
# set to false. Yarn commands should _not_ be ran outside of this helper
|
77
|
+
# to ensure that postinstall scripts are never executed, as they could
|
78
|
+
# contain malicious code.
|
79
|
+
def self.run_yarn_commands(*commands)
|
80
|
+
setup_yarn_berry
|
81
|
+
commands.each { |cmd| SharedHelpers.run_shell_command(cmd) }
|
82
|
+
end
|
83
|
+
|
84
|
+
# Run a single yarn command returning stdout/stderr
|
85
|
+
def self.run_yarn_command(command)
|
86
|
+
setup_yarn_berry
|
87
|
+
SharedHelpers.run_shell_command(command)
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.dependencies_with_all_versions_metadata(dependency_set)
|
91
|
+
working_set = Dependabot::NpmAndYarn::FileParser::DependencySet.new
|
92
|
+
dependencies = []
|
93
|
+
|
94
|
+
names = dependency_set.dependencies.map(&:name)
|
95
|
+
names.each do |name|
|
96
|
+
all_versions = dependency_set.all_versions_for_name(name)
|
97
|
+
all_versions.each do |dep|
|
98
|
+
metadata_versions = dep.metadata.fetch(:all_versions, [])
|
99
|
+
if metadata_versions.any?
|
100
|
+
metadata_versions.each { |a| working_set << a }
|
101
|
+
else
|
102
|
+
working_set << dep
|
103
|
+
end
|
104
|
+
end
|
105
|
+
dependency = working_set.dependency_for_name(name)
|
106
|
+
dependency.metadata[:all_versions] = working_set.all_versions_for_name(name)
|
107
|
+
dependencies << dependency
|
108
|
+
end
|
109
|
+
|
110
|
+
dependencies
|
111
|
+
end
|
18
112
|
end
|
19
113
|
end
|
20
114
|
end
|
@@ -18,7 +18,7 @@ module Dependabot
|
|
18
18
|
[a-z0-9\-\_\.\!\~\*\'\(\)]+ # URL-safe characters
|
19
19
|
)
|
20
20
|
\z # end of string
|
21
|
-
}xi
|
21
|
+
}xi # multi-line/case-insensitive
|
22
22
|
|
23
23
|
TYPES_PACKAGE_NAME_REGEX = %r{
|
24
24
|
\A # beginning of string
|
@@ -26,7 +26,7 @@ module Dependabot
|
|
26
26
|
((?<scope>.+)__)? # capture scope
|
27
27
|
(?<name>.+) # capture name
|
28
28
|
\z # end of string
|
29
|
-
}xi
|
29
|
+
}xi # multi-line/case-insensitive
|
30
30
|
|
31
31
|
class InvalidPackageName < StandardError; end
|
32
32
|
|
@@ -6,8 +6,8 @@ require "dependabot/npm_and_yarn/version"
|
|
6
6
|
module Dependabot
|
7
7
|
module NpmAndYarn
|
8
8
|
class Requirement < Gem::Requirement
|
9
|
-
AND_SEPARATOR = /(?<=[a-zA-Z0-9*])\s+(?:&+\s+)?(?!\s*[|-])
|
10
|
-
OR_SEPARATOR = /(?<=[a-zA-Z0-9*])\s
|
9
|
+
AND_SEPARATOR = /(?<=[a-zA-Z0-9*])\s+(?:&+\s+)?(?!\s*[|-])/
|
10
|
+
OR_SEPARATOR = /(?<=[a-zA-Z0-9*])\s*\|+/
|
11
11
|
LATEST_REQUIREMENT = "latest"
|
12
12
|
|
13
13
|
# Override the version pattern to allow a 'v' prefix
|
@@ -15,7 +15,7 @@ module Dependabot
|
|
15
15
|
version_pattern = "v?#{NpmAndYarn::Version::VERSION_PATTERN}"
|
16
16
|
|
17
17
|
PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{version_pattern})\\s*"
|
18
|
-
PATTERN = /\A#{PATTERN_RAW}\z
|
18
|
+
PATTERN = /\A#{PATTERN_RAW}\z/
|
19
19
|
|
20
20
|
def self.parse(obj)
|
21
21
|
return ["=", nil] if obj.is_a?(String) && obj.strip == LATEST_REQUIREMENT
|
@@ -16,7 +16,12 @@ module Dependabot
|
|
16
16
|
def write_temporary_dependency_files
|
17
17
|
write_lock_files
|
18
18
|
|
19
|
-
|
19
|
+
if Helpers.yarn_berry?(yarn_locks.first)
|
20
|
+
File.write(".yarnrc.yml", yarnrc_yml_content) if yarnrc_yml_file
|
21
|
+
else
|
22
|
+
File.write(".npmrc", npmrc_content) unless Helpers.yarn_berry?(yarn_locks.first)
|
23
|
+
File.write(".yarnrc", yarnrc_content) if yarnrc_specifies_private_reg?
|
24
|
+
end
|
20
25
|
|
21
26
|
package_files.each do |file|
|
22
27
|
path = file.name
|
@@ -69,6 +74,24 @@ module Dependabot
|
|
69
74
|
end
|
70
75
|
end
|
71
76
|
|
77
|
+
def yarnrc_specifies_private_reg?
|
78
|
+
return false unless yarnrc_file
|
79
|
+
|
80
|
+
regex = UpdateChecker::RegistryFinder::YARN_GLOBAL_REGISTRY_REGEX
|
81
|
+
yarnrc_global_registry =
|
82
|
+
yarnrc_file.content.
|
83
|
+
lines.find { |line| line.match?(regex) }&.
|
84
|
+
match(regex)&.
|
85
|
+
named_captures&.
|
86
|
+
fetch("registry")
|
87
|
+
|
88
|
+
return false unless yarnrc_global_registry
|
89
|
+
|
90
|
+
UpdateChecker::RegistryFinder::CENTRAL_REGISTRIES.none? do |r|
|
91
|
+
r.include?(URI(yarnrc_global_registry).host)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
72
95
|
# Duplicated in NpmLockfileUpdater
|
73
96
|
# Remove the dependency we want to update from the lockfile and let
|
74
97
|
# yarn find the latest resolvable version and fix the lockfile
|
@@ -88,6 +111,25 @@ module Dependabot
|
|
88
111
|
dependency_files: dependency_files
|
89
112
|
).npmrc_content
|
90
113
|
end
|
114
|
+
|
115
|
+
def yarnrc_file
|
116
|
+
dependency_files.find { |f| f.name == ".yarnrc" }
|
117
|
+
end
|
118
|
+
|
119
|
+
def yarnrc_content
|
120
|
+
NpmAndYarn::FileUpdater::NpmrcBuilder.new(
|
121
|
+
credentials: credentials,
|
122
|
+
dependency_files: dependency_files
|
123
|
+
).yarnrc_content
|
124
|
+
end
|
125
|
+
|
126
|
+
def yarnrc_yml_file
|
127
|
+
dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") }
|
128
|
+
end
|
129
|
+
|
130
|
+
def yarnrc_yml_content
|
131
|
+
yarnrc_yml_file.content
|
132
|
+
end
|
91
133
|
end
|
92
134
|
end
|
93
135
|
end
|
@@ -130,10 +130,10 @@ module Dependabot
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def filter_lower_versions(versions_array)
|
133
|
-
return versions_array unless dependency.
|
133
|
+
return versions_array unless dependency.numeric_version
|
134
134
|
|
135
135
|
versions_array.
|
136
|
-
select { |version, _| version >
|
136
|
+
select { |version, _| version > dependency.numeric_version }
|
137
137
|
end
|
138
138
|
|
139
139
|
def version_from_dist_tags
|
@@ -159,13 +159,10 @@ module Dependabot
|
|
159
159
|
wants_latest_dist_tag?(latest) ? latest : nil
|
160
160
|
end
|
161
161
|
|
162
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
163
162
|
def related_to_current_pre?(version)
|
164
|
-
current_version = dependency.
|
165
|
-
if current_version &&
|
166
|
-
|
167
|
-
version_class.new(current_version).prerelease? &&
|
168
|
-
version_class.new(current_version).release == version.release
|
163
|
+
current_version = dependency.numeric_version
|
164
|
+
if current_version&.prerelease? &&
|
165
|
+
current_version&.release == version.release
|
169
166
|
return true
|
170
167
|
end
|
171
168
|
|
@@ -181,7 +178,6 @@ module Dependabot
|
|
181
178
|
false
|
182
179
|
end
|
183
180
|
end
|
184
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
185
181
|
|
186
182
|
def specified_dist_tag_requirement?
|
187
183
|
dependency.requirements.any? do |req|
|
@@ -204,10 +200,9 @@ module Dependabot
|
|
204
200
|
end
|
205
201
|
|
206
202
|
def current_version_greater_than?(version)
|
207
|
-
return false unless dependency.
|
208
|
-
return false unless version_class.correct?(dependency.version)
|
203
|
+
return false unless dependency.numeric_version
|
209
204
|
|
210
|
-
|
205
|
+
dependency.numeric_version > version
|
211
206
|
end
|
212
207
|
|
213
208
|
def current_requirement_greater_than?(version)
|
@@ -292,7 +287,6 @@ module Dependabot
|
|
292
287
|
url: dependency_url,
|
293
288
|
headers: registry_auth_headers
|
294
289
|
)
|
295
|
-
|
296
290
|
return response unless response.status == 500
|
297
291
|
return response unless registry_auth_headers["Authorization"]
|
298
292
|
|
@@ -371,7 +365,8 @@ module Dependabot
|
|
371
365
|
dependency: dependency,
|
372
366
|
credentials: credentials,
|
373
367
|
npmrc_file: npmrc_file,
|
374
|
-
yarnrc_file: yarnrc_file
|
368
|
+
yarnrc_file: yarnrc_file,
|
369
|
+
yarnrc_yml_file: yarnrc_yml_file
|
375
370
|
)
|
376
371
|
end
|
377
372
|
|
@@ -395,6 +390,10 @@ module Dependabot
|
|
395
390
|
dependency_files.find { |f| f.name.end_with?(".yarnrc") }
|
396
391
|
end
|
397
392
|
|
393
|
+
def yarnrc_yml_file
|
394
|
+
dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") }
|
395
|
+
end
|
396
|
+
|
398
397
|
# TODO: Remove need for me
|
399
398
|
def git_dependency?
|
400
399
|
# ignored_version/raise_on_ignored are irrelevant.
|
@@ -8,8 +8,10 @@ module Dependabot
|
|
8
8
|
module NpmAndYarn
|
9
9
|
class UpdateChecker
|
10
10
|
class LibraryDetector
|
11
|
-
def initialize(package_json_file:)
|
11
|
+
def initialize(package_json_file:, credentials:, dependency_files:)
|
12
12
|
@package_json_file = package_json_file
|
13
|
+
@credentials = credentials
|
14
|
+
@dependency_files = dependency_files
|
13
15
|
end
|
14
16
|
|
15
17
|
def library?
|
@@ -20,7 +22,7 @@ module Dependabot
|
|
20
22
|
|
21
23
|
private
|
22
24
|
|
23
|
-
attr_reader :package_json_file
|
25
|
+
attr_reader :package_json_file, :credentials, :dependency_files
|
24
26
|
|
25
27
|
def package_json_may_be_for_library?
|
26
28
|
return false unless project_name
|
@@ -36,7 +38,8 @@ module Dependabot
|
|
36
38
|
return false unless project_description
|
37
39
|
|
38
40
|
# Check if the project is listed on npm. If it is, it's a library
|
39
|
-
|
41
|
+
url = "#{registry.chomp('/')}/#{escaped_project_name}"
|
42
|
+
@project_npm_response ||= Dependabot::RegistryClient.get(url: url)
|
40
43
|
return false unless @project_npm_response.status == 200
|
41
44
|
|
42
45
|
@project_npm_response.body.force_encoding("UTF-8").encode.
|
@@ -56,6 +59,16 @@ module Dependabot
|
|
56
59
|
def parsed_package_json
|
57
60
|
@parsed_package_json ||= JSON.parse(package_json_file.content)
|
58
61
|
end
|
62
|
+
|
63
|
+
def registry
|
64
|
+
NpmAndYarn::UpdateChecker::RegistryFinder.new(
|
65
|
+
dependency: nil,
|
66
|
+
credentials: credentials,
|
67
|
+
npmrc_file: dependency_files.find { |f| f.name.end_with?(".npmrc") },
|
68
|
+
yarnrc_file: dependency_files.find { |f| f.name.end_with?(".yarnrc") },
|
69
|
+
yarnrc_yml_file: dependency_files.find { |f| f.name.end_with?(".yarnrc.yml") }
|
70
|
+
).registry_from_rc(project_name)
|
71
|
+
end
|
59
72
|
end
|
60
73
|
end
|
61
74
|
end
|