dependabot-npm_and_yarn 0.385.0 → 0.386.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/npm/vulnerability-auditor.ts +9 -3
- data/helpers/test/npm/fixtures/vulnerability-auditor/workspace-transitive-dependency/package-lock.json +62 -0
- data/helpers/test/npm/fixtures/vulnerability-auditor/workspace-transitive-dependency/package.json +8 -0
- data/helpers/test/npm/fixtures/vulnerability-auditor/workspace-transitive-dependency/packages/app/package.json +8 -0
- data/helpers/test/npm/fixtures/vulnerability-auditor/workspace-transitive-dependency/packages/lib/package.json +7 -0
- data/helpers/test/npm/vulnerability-auditor.test.ts +40 -0
- data/lib/dependabot/npm_and_yarn/helpers.rb +76 -19
- data/lib/dependabot/npm_and_yarn/metadata_finder.rb +31 -21
- data/lib/dependabot/npm_and_yarn/registry_helper.rb +1 -0
- metadata +8 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eed1a15784e78d8843afd8b8e043e63bf1c3f9af24945e5980244dbdbc20012b
|
|
4
|
+
data.tar.gz: 44a369d54a689ae0ec9388bee4a79fedb992ce301f20037cbfd8668f3b430d2b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 734cdc4cb55dd3b1361fc128f9590b891ccd6f6d45e67872f71ff9cb5ab5826eb4c9ec4814f09e4e4e046b642b2756366f06fdfd1dba5f3c5e2d8ade6617558a
|
|
7
|
+
data.tar.gz: 2449823cbdc0f90c27463aa6c04729a5427728ad9747404968ef7007d295f061b7436ed0bff9307dee43897c0c87d1b21d1e8a6426a43193755d54ccfa7348b1
|
|
@@ -123,7 +123,7 @@ export async function findVulnerableDependencies(
|
|
|
123
123
|
|
|
124
124
|
const { server, url: auditRegistryUrl } = await startAuditServer(advisories);
|
|
125
125
|
|
|
126
|
-
const
|
|
126
|
+
const arboristOptions = {
|
|
127
127
|
path: directory,
|
|
128
128
|
auditRegistry: auditRegistryUrl,
|
|
129
129
|
noProxy: "127.0.0.1",
|
|
@@ -133,7 +133,8 @@ export async function findVulnerableDependencies(
|
|
|
133
133
|
ignoreScripts: true,
|
|
134
134
|
...registryOpts,
|
|
135
135
|
...registryCreds,
|
|
136
|
-
}
|
|
136
|
+
};
|
|
137
|
+
const arb = new Arborist(arboristOptions);
|
|
137
138
|
|
|
138
139
|
try {
|
|
139
140
|
const name = advisories[0].dependency_name;
|
|
@@ -218,7 +219,12 @@ export async function findVulnerableDependencies(
|
|
|
218
219
|
|
|
219
220
|
response.top_level_ancestors = [...topLevelAncestors].sort();
|
|
220
221
|
|
|
221
|
-
|
|
222
|
+
// Compute the fix tree with a fresh Arborist instance: walking the audit
|
|
223
|
+
// report above (Vuln#isVulnerable in buildDependencyChains) mutates
|
|
224
|
+
// vuln.nodes, and a polluted node set corrupts the fix calculation for
|
|
225
|
+
// workspace repos, leaving the vulnerable version in place.
|
|
226
|
+
const fixArb = new Arborist(arboristOptions);
|
|
227
|
+
const fixTree = await fixArb.audit({
|
|
222
228
|
fix: true,
|
|
223
229
|
});
|
|
224
230
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "test-workspace-transitive-dependency",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "test-workspace-transitive-dependency",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"workspaces": [
|
|
11
|
+
"packages/*"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"node_modules/@dependabot-fixtures/npm-intermediate-dependency": {
|
|
15
|
+
"version": "0.0.2",
|
|
16
|
+
"resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-intermediate-dependency/-/npm-intermediate-dependency-0.0.2.tgz",
|
|
17
|
+
"integrity": "sha512-xj/Xn9vf3zO9b4XQXAWysDyMARCajkyceOqcdIdg9blkz6JPzB5e3ShGH+rAo0TBy+DN7WrFBMt1xxwdqezRLg==",
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@dependabot-fixtures/npm-transitive-dependency": "^1.0.0"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"node_modules/@dependabot-fixtures/npm-parent-dependency": {
|
|
24
|
+
"version": "2.0.1",
|
|
25
|
+
"resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-parent-dependency/-/npm-parent-dependency-2.0.1.tgz",
|
|
26
|
+
"integrity": "sha512-iKNiUvswqiwhJLmP6yJv45anOm43uEuKm90LK70bhwdMMbTg2XzK7TqPv5UzmHQHCxUE8zTy82piqDf/Uqui3Q==",
|
|
27
|
+
"license": "ISC",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@dependabot-fixtures/npm-intermediate-dependency": "^0.0.1"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"node_modules/@dependabot-fixtures/npm-transitive-dependency": {
|
|
33
|
+
"version": "1.0.0",
|
|
34
|
+
"resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-transitive-dependency/-/npm-transitive-dependency-1.0.0.tgz",
|
|
35
|
+
"integrity": "sha512-nFbzQH0TRgdzSA2/FH6MPnxZDpD+5Bgz00aD5Edgbc1wY/k8VC9s7lnk22dBTgJLwoY7MgbrnAf9rAvN08hHVg==",
|
|
36
|
+
"license": "ISC"
|
|
37
|
+
},
|
|
38
|
+
"node_modules/app": {
|
|
39
|
+
"resolved": "packages/app",
|
|
40
|
+
"link": true
|
|
41
|
+
},
|
|
42
|
+
"node_modules/lib": {
|
|
43
|
+
"resolved": "packages/lib",
|
|
44
|
+
"link": true
|
|
45
|
+
},
|
|
46
|
+
"packages/app": {
|
|
47
|
+
"name": "app",
|
|
48
|
+
"version": "1.0.0",
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"lib": "*",
|
|
51
|
+
"@dependabot-fixtures/npm-parent-dependency": "^2.0.1"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"packages/lib": {
|
|
55
|
+
"name": "lib",
|
|
56
|
+
"version": "1.0.0",
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@dependabot-fixtures/npm-parent-dependency": "^2.0.1"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -120,6 +120,46 @@ describe("findVulnerableDependencies", () => {
|
|
|
120
120
|
]);
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
+
it("fixes a deep transitive dependency reachable only via workspace packages", async () => {
|
|
124
|
+
helpers.copyDependenciesTree(
|
|
125
|
+
"vulnerability-auditor/workspace-transitive-dependency",
|
|
126
|
+
tempDir
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const advisories = [
|
|
130
|
+
{
|
|
131
|
+
dependency_name: "@dependabot-fixtures/npm-transitive-dependency",
|
|
132
|
+
affected_versions: ["< 1.0.1"],
|
|
133
|
+
},
|
|
134
|
+
];
|
|
135
|
+
const actual = await findVulnerableDependencies(tempDir, advisories);
|
|
136
|
+
|
|
137
|
+
// The vulnerable dependency sits three levels below the workspace packages
|
|
138
|
+
// (app/lib -> npm-parent-dependency -> npm-intermediate-dependency ->
|
|
139
|
+
// npm-transitive-dependency) and isn't required by the workspace root at
|
|
140
|
+
// all — mirroring the Turborepo layout from issue #14984. The fix is a
|
|
141
|
+
// lockfile-only in-range bump of the dependency itself, so the audit must
|
|
142
|
+
// report it as fixable with a non-vulnerable target version even though
|
|
143
|
+
// all top-level ancestors are workspace packages.
|
|
144
|
+
expect(actual.dependency_name).toBe(
|
|
145
|
+
"@dependabot-fixtures/npm-transitive-dependency"
|
|
146
|
+
);
|
|
147
|
+
expect(actual.current_version).toBe("1.0.0");
|
|
148
|
+
expect(actual.fix_available).toBe(true);
|
|
149
|
+
expect(actual.target_version).toBe("1.0.1");
|
|
150
|
+
|
|
151
|
+
expect(actual.top_level_ancestors).toEqual(["app", "lib"]);
|
|
152
|
+
|
|
153
|
+
expect(actual.fix_updates).toEqual([
|
|
154
|
+
{
|
|
155
|
+
dependency_name: "@dependabot-fixtures/npm-transitive-dependency",
|
|
156
|
+
current_version: "1.0.0",
|
|
157
|
+
target_version: "1.0.1",
|
|
158
|
+
top_level_ancestors: ["app", "lib"],
|
|
159
|
+
},
|
|
160
|
+
]);
|
|
161
|
+
});
|
|
162
|
+
|
|
123
163
|
it("returns empty fix updates when package-lock.json is outdated", async () => {
|
|
124
164
|
helpers.copyDependencies(
|
|
125
165
|
"vulnerability-auditor/outdated-package-lock",
|
|
@@ -68,6 +68,7 @@ module Dependabot
|
|
|
68
68
|
|
|
69
69
|
# corepack supported package managers
|
|
70
70
|
SUPPORTED_COREPACK_PACKAGE_MANAGERS = %w(npm yarn pnpm).freeze
|
|
71
|
+
COREPACK_SIGNATURE_METADATA_ERROR = "No compatible signature found in package metadata"
|
|
71
72
|
|
|
72
73
|
sig { params(lockfile: T.nilable(DependencyFile)).returns(Integer) }
|
|
73
74
|
def self.npm_version_numeric(lockfile)
|
|
@@ -564,28 +565,33 @@ module Dependabot
|
|
|
564
565
|
output_observer: nil,
|
|
565
566
|
env: nil
|
|
566
567
|
)
|
|
567
|
-
full_command = "corepack #{name} #{command}"
|
|
568
|
-
|
|
568
|
+
full_command = T.let("corepack #{name} #{command}", String)
|
|
569
|
+
command_fingerprint = T.let("corepack #{name} #{fingerprint || command}", String)
|
|
569
570
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
).strip
|
|
577
|
-
else
|
|
578
|
-
Dependabot::SharedHelpers.run_shell_command(
|
|
579
|
-
full_command,
|
|
580
|
-
fingerprint: fingerprint,
|
|
581
|
-
env: env
|
|
582
|
-
)
|
|
583
|
-
end.strip
|
|
571
|
+
run_corepack_shell_command(
|
|
572
|
+
full_command,
|
|
573
|
+
fingerprint: command_fingerprint,
|
|
574
|
+
output_observer: output_observer,
|
|
575
|
+
env: env
|
|
576
|
+
)
|
|
584
577
|
rescue StandardError => e
|
|
585
578
|
Dependabot.logger.error("Error running package manager command: #{full_command}, Error: #{e.message}")
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
579
|
+
|
|
580
|
+
raise_registry_error_if_not_found(e)
|
|
581
|
+
|
|
582
|
+
if retry_without_signature_verification?(error: e, env: env)
|
|
583
|
+
retry_env = T.must(env).merge(RegistryHelper::COREPACK_INTEGRITY_KEYS_ENV => "")
|
|
584
|
+
Dependabot.logger.warn(
|
|
585
|
+
"Corepack signature verification failed against the configured private registry. " \
|
|
586
|
+
"Retrying once with COREPACK_INTEGRITY_KEYS disabled for this command only."
|
|
587
|
+
)
|
|
588
|
+
|
|
589
|
+
return run_corepack_shell_command(
|
|
590
|
+
T.must(full_command),
|
|
591
|
+
fingerprint: T.must(command_fingerprint),
|
|
592
|
+
output_observer: output_observer,
|
|
593
|
+
env: retry_env
|
|
594
|
+
)
|
|
589
595
|
end
|
|
590
596
|
|
|
591
597
|
raise
|
|
@@ -620,6 +626,57 @@ module Dependabot
|
|
|
620
626
|
registry_helper.find_corepack_env_variables
|
|
621
627
|
end
|
|
622
628
|
|
|
629
|
+
sig do
|
|
630
|
+
params(
|
|
631
|
+
full_command: String,
|
|
632
|
+
fingerprint: String,
|
|
633
|
+
output_observer: CommandHelpers::OutputObserver,
|
|
634
|
+
env: T.nilable(T::Hash[String, String])
|
|
635
|
+
).returns(String)
|
|
636
|
+
end
|
|
637
|
+
def self.run_corepack_shell_command(full_command, fingerprint:, output_observer:, env: nil)
|
|
638
|
+
if output_observer
|
|
639
|
+
return Dependabot::SharedHelpers.run_shell_command(
|
|
640
|
+
full_command,
|
|
641
|
+
fingerprint: fingerprint,
|
|
642
|
+
output_observer: output_observer,
|
|
643
|
+
env: env
|
|
644
|
+
).strip
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
Dependabot::SharedHelpers.run_shell_command(
|
|
648
|
+
full_command,
|
|
649
|
+
fingerprint: fingerprint,
|
|
650
|
+
env: env
|
|
651
|
+
).strip
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
sig { params(error: StandardError).void }
|
|
655
|
+
def self.raise_registry_error_if_not_found(error)
|
|
656
|
+
if error.message.match?(/Response Code.*:.*404.*\(Not Found\)/) &&
|
|
657
|
+
error.message.include?("The remote server failed to provide the requested resource")
|
|
658
|
+
raise RegistryError.new(404, "The remote server failed to provide the requested resource")
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
sig { params(error: StandardError, env: T.nilable(T::Hash[String, String])).returns(T::Boolean) }
|
|
663
|
+
def self.retry_without_signature_verification?(error:, env:)
|
|
664
|
+
return false unless env
|
|
665
|
+
|
|
666
|
+
registry = env[RegistryHelper::COREPACK_NPM_REGISTRY_ENV]
|
|
667
|
+
return false unless registry
|
|
668
|
+
return false if default_npm_registry?(registry)
|
|
669
|
+
return false unless error.message.include?(COREPACK_SIGNATURE_METADATA_ERROR)
|
|
670
|
+
|
|
671
|
+
!env.key?(RegistryHelper::COREPACK_INTEGRITY_KEYS_ENV)
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
sig { params(registry: String).returns(T::Boolean) }
|
|
675
|
+
def self.default_npm_registry?(registry)
|
|
676
|
+
normalized_registry = RegistryHelper.normalize_registry_url(registry)
|
|
677
|
+
normalized_registry == RegistryHelper::DEFAULT_NPM_REGISTRY
|
|
678
|
+
end
|
|
679
|
+
|
|
623
680
|
private_class_method :run_single_yarn_command
|
|
624
681
|
|
|
625
682
|
sig { params(pnpm_lock: DependencyFile).returns(T.nilable(String)) }
|
|
@@ -175,27 +175,37 @@ module Dependabot
|
|
|
175
175
|
|
|
176
176
|
sig { returns(T.nilable(Dependabot::Source)) }
|
|
177
177
|
def find_source_from_registry
|
|
178
|
-
# Attempt to use
|
|
179
|
-
# array can be slow (if it's large)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
178
|
+
# Attempt to use the latest version listing first, as fetching the
|
|
179
|
+
# entire listing array can be slow (if it's large)
|
|
180
|
+
latest_source = source_from_listing(latest_version_listing)
|
|
181
|
+
return latest_source if latest_source
|
|
182
|
+
|
|
183
|
+
seen_urls = T.let(Set.new, T::Set[String])
|
|
184
|
+
all_version_listings.each do |_, listing|
|
|
185
|
+
listing_source = source_from_listing(listing, seen_urls)
|
|
186
|
+
return listing_source if listing_source
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
nil
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
sig do
|
|
193
|
+
params(
|
|
194
|
+
listing: T::Hash[String, T.untyped],
|
|
195
|
+
seen_urls: T.nilable(T::Set[String])
|
|
196
|
+
).returns(T.nilable(Dependabot::Source))
|
|
197
|
+
end
|
|
198
|
+
def source_from_listing(listing, seen_urls = nil)
|
|
199
|
+
[listing["repository"], listing["homepage"], listing["bugs"]].each do |details|
|
|
200
|
+
url = get_url(details)
|
|
201
|
+
next unless url
|
|
202
|
+
next if seen_urls && !seen_urls.add?(url)
|
|
203
|
+
|
|
204
|
+
source = get_source(details)
|
|
205
|
+
return source if source
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
nil
|
|
199
209
|
end
|
|
200
210
|
|
|
201
211
|
sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.untyped])) }
|
|
@@ -23,6 +23,7 @@ module Dependabot
|
|
|
23
23
|
COREPACK_NPM_REGISTRY_ENV = "COREPACK_NPM_REGISTRY" # For Corepack
|
|
24
24
|
NPM_CONFIG_REGISTRY_ENV = "npm_config_registry" # For npm
|
|
25
25
|
COREPACK_NPM_TOKEN_ENV = "COREPACK_NPM_TOKEN"
|
|
26
|
+
COREPACK_INTEGRITY_KEYS_ENV = "COREPACK_INTEGRITY_KEYS"
|
|
26
27
|
|
|
27
28
|
# Default npm registry - no need to set env vars for this
|
|
28
29
|
DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-npm_and_yarn
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.386.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.386.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.386.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -286,6 +286,10 @@ files:
|
|
|
286
286
|
- helpers/test/npm/fixtures/vulnerability-auditor/workspace-link-node/package-lock.json
|
|
287
287
|
- helpers/test/npm/fixtures/vulnerability-auditor/workspace-link-node/package.json
|
|
288
288
|
- helpers/test/npm/fixtures/vulnerability-auditor/workspace-link-node/packages/app/package.json
|
|
289
|
+
- helpers/test/npm/fixtures/vulnerability-auditor/workspace-transitive-dependency/package-lock.json
|
|
290
|
+
- helpers/test/npm/fixtures/vulnerability-auditor/workspace-transitive-dependency/package.json
|
|
291
|
+
- helpers/test/npm/fixtures/vulnerability-auditor/workspace-transitive-dependency/packages/app/package.json
|
|
292
|
+
- helpers/test/npm/fixtures/vulnerability-auditor/workspace-transitive-dependency/packages/lib/package.json
|
|
289
293
|
- helpers/test/npm/helpers.ts
|
|
290
294
|
- helpers/test/npm/vulnerability-auditor.test.ts
|
|
291
295
|
- helpers/test/npm6/conflicting-dependency-parser.test.ts
|
|
@@ -377,7 +381,7 @@ licenses:
|
|
|
377
381
|
- MIT
|
|
378
382
|
metadata:
|
|
379
383
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
380
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
384
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.386.0
|
|
381
385
|
rdoc_options: []
|
|
382
386
|
require_paths:
|
|
383
387
|
- lib
|