@openrewrite/recipes-nodejs 0.37.0-20251224-170410 → 0.37.0-20260102-170441
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.
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -24
- package/dist/index.js.map +1 -1
- package/dist/resources/advisories-npm.csv +17 -2
- package/dist/security/dependency-vulnerability-check.d.ts +29 -8
- package/dist/security/dependency-vulnerability-check.d.ts.map +1 -1
- package/dist/security/dependency-vulnerability-check.js +579 -102
- package/dist/security/dependency-vulnerability-check.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +29 -25
- package/src/security/dependency-vulnerability-check.ts +1049 -178
|
@@ -53,13 +53,15 @@ exports.extractVersionPrefix = extractVersionPrefix;
|
|
|
53
53
|
exports.applyVersionPrefix = applyVersionPrefix;
|
|
54
54
|
const rewrite_1 = require("@openrewrite/rewrite");
|
|
55
55
|
const json_1 = require("@openrewrite/rewrite/json");
|
|
56
|
-
const rewrite_2 = require("@openrewrite/rewrite");
|
|
57
56
|
const text_1 = require("@openrewrite/rewrite/text");
|
|
58
57
|
const yaml_1 = require("@openrewrite/rewrite/yaml");
|
|
59
58
|
const javascript_1 = require("@openrewrite/rewrite/javascript");
|
|
60
59
|
const semver = __importStar(require("semver"));
|
|
61
60
|
const path = __importStar(require("path"));
|
|
62
61
|
const vulnerability_1 = require("./vulnerability");
|
|
62
|
+
const ALL_DEPENDENCY_SCOPES = [
|
|
63
|
+
'dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'
|
|
64
|
+
];
|
|
63
65
|
class VulnerabilityReportRow {
|
|
64
66
|
constructor(sourcePath, cve, packageName, version, fixedVersion, lastAffectedVersion, upgradeable, summary, severity, depth, cwes, isDirect, dependencyPath) {
|
|
65
67
|
this.sourcePath = sourcePath;
|
|
@@ -156,8 +158,9 @@ __decorate([
|
|
|
156
158
|
})
|
|
157
159
|
], VulnerabilityReportRow.prototype, "dependencyPath", void 0);
|
|
158
160
|
class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
159
|
-
constructor() {
|
|
160
|
-
|
|
161
|
+
constructor(options) {
|
|
162
|
+
var _a, _b, _c;
|
|
163
|
+
super(options);
|
|
161
164
|
this.name = "org.openrewrite.node.dependency-vulnerability-check";
|
|
162
165
|
this.displayName = "Find and fix vulnerable npm dependencies";
|
|
163
166
|
this.description = "This software composition analysis (SCA) tool detects and upgrades dependencies with publicly " +
|
|
@@ -166,30 +169,31 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
166
169
|
"If a minor or major upgrade is required to reach the fixed version, this can be controlled using the `maximumUpgradeDelta` option. " +
|
|
167
170
|
"Vulnerability information comes from the GitHub Security Advisory Database.";
|
|
168
171
|
this.vulnerabilityReport = new rewrite_1.DataTable("org.openrewrite.nodejs.table.VulnerabilityReport", "Vulnerability Report", "Lists all vulnerabilities found in project dependencies.", VulnerabilityReportRow);
|
|
172
|
+
(_a = this.maximumUpgradeDelta) !== null && _a !== void 0 ? _a : (this.maximumUpgradeDelta = 'patch');
|
|
173
|
+
(_b = this.minimumSeverity) !== null && _b !== void 0 ? _b : (this.minimumSeverity = vulnerability_1.Severity.LOW);
|
|
174
|
+
(_c = this.fixDeclaredVersions) !== null && _c !== void 0 ? _c : (this.fixDeclaredVersions = false);
|
|
175
|
+
if (options === null || options === void 0 ? void 0 : options.minimumSeverity) {
|
|
176
|
+
this.minimumSeverity = (0, vulnerability_1.parseSeverity)(options.minimumSeverity);
|
|
177
|
+
}
|
|
178
|
+
if (this.cvePattern) {
|
|
179
|
+
try {
|
|
180
|
+
this.cvePatternRegex = new RegExp(this.cvePattern);
|
|
181
|
+
}
|
|
182
|
+
catch (_d) {
|
|
183
|
+
}
|
|
184
|
+
}
|
|
169
185
|
}
|
|
170
186
|
initialValue(_ctx) {
|
|
171
|
-
return Object.assign(Object.assign({}, (0, javascript_1.createDependencyRecipeAccumulator)()), { db: vulnerability_1.VulnerabilityDatabase.load(), vulnerableByProject: new Map(), fixesByProject: new Map() });
|
|
172
|
-
}
|
|
173
|
-
getMinimumSeverity() {
|
|
174
|
-
return this.minimumSeverity ? (0, vulnerability_1.parseSeverity)(this.minimumSeverity) : vulnerability_1.Severity.LOW;
|
|
175
|
-
}
|
|
176
|
-
getMaximumUpgradeDelta() {
|
|
177
|
-
return this.maximumUpgradeDelta || 'patch';
|
|
187
|
+
return Object.assign(Object.assign({}, (0, javascript_1.createDependencyRecipeAccumulator)()), { db: vulnerability_1.VulnerabilityDatabase.load(), vulnerableByProject: new Map(), fixesByProject: new Map(), originalLockFiles: new Map(), allPackageJsonContents: new Map(), workspaceRoots: new Map(), modifiedWorkspaceMemberContents: new Map(), workspaceDetectionComplete: false });
|
|
178
188
|
}
|
|
179
189
|
isReportOnly() {
|
|
180
|
-
return this.
|
|
190
|
+
return this.maximumUpgradeDelta === 'none';
|
|
181
191
|
}
|
|
182
192
|
matchesCvePattern(vulnerability) {
|
|
183
|
-
if (!this.
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
try {
|
|
187
|
-
const regex = new RegExp(this.cvePattern);
|
|
188
|
-
return regex.test(vulnerability.cve);
|
|
189
|
-
}
|
|
190
|
-
catch (_a) {
|
|
193
|
+
if (!this.cvePatternRegex) {
|
|
191
194
|
return true;
|
|
192
195
|
}
|
|
196
|
+
return this.cvePatternRegex.test(vulnerability.cve);
|
|
193
197
|
}
|
|
194
198
|
isVersionAffected(version, vulnerability) {
|
|
195
199
|
try {
|
|
@@ -230,7 +234,7 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
230
234
|
const current = semver.parse(currentVersion);
|
|
231
235
|
if (!current)
|
|
232
236
|
return false;
|
|
233
|
-
const delta = this.
|
|
237
|
+
const delta = this.maximumUpgradeDelta;
|
|
234
238
|
if (vulnerability.fixedVersion) {
|
|
235
239
|
const fixed = semver.parse(vulnerability.fixedVersion);
|
|
236
240
|
if (!fixed)
|
|
@@ -274,6 +278,17 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
274
278
|
}
|
|
275
279
|
return undefined;
|
|
276
280
|
}
|
|
281
|
+
getVersionPrefixForDelta() {
|
|
282
|
+
switch (this.maximumUpgradeDelta) {
|
|
283
|
+
case 'patch':
|
|
284
|
+
return '~';
|
|
285
|
+
case 'minor':
|
|
286
|
+
case 'major':
|
|
287
|
+
return '^';
|
|
288
|
+
default:
|
|
289
|
+
return '';
|
|
290
|
+
}
|
|
291
|
+
}
|
|
277
292
|
renderPath(scope, path) {
|
|
278
293
|
const parts = [];
|
|
279
294
|
if (scope) {
|
|
@@ -292,7 +307,7 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
292
307
|
const currentPath = [...path, { name: resolved.name, version: resolved.version }];
|
|
293
308
|
const vulns = db.getVulnerabilities(resolved.name);
|
|
294
309
|
for (const vuln of vulns) {
|
|
295
|
-
if ((0, vulnerability_1.severityOrdinal)(vuln.severity) < (0, vulnerability_1.severityOrdinal)(this.
|
|
310
|
+
if ((0, vulnerability_1.severityOrdinal)(vuln.severity) < (0, vulnerability_1.severityOrdinal)(this.minimumSeverity)) {
|
|
296
311
|
continue;
|
|
297
312
|
}
|
|
298
313
|
if (!this.matchesCvePattern(vuln)) {
|
|
@@ -323,30 +338,171 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
323
338
|
}
|
|
324
339
|
}
|
|
325
340
|
}
|
|
326
|
-
|
|
341
|
+
findPreventiveFixes(marker, scopes, db) {
|
|
342
|
+
const fixes = [];
|
|
343
|
+
for (const scope of scopes) {
|
|
344
|
+
const deps = marker[scope] || [];
|
|
345
|
+
for (const dep of deps) {
|
|
346
|
+
if (!dep.resolved)
|
|
347
|
+
continue;
|
|
348
|
+
const declaredMinVersion = this.extractMinimumVersion(dep.versionConstraint);
|
|
349
|
+
if (!declaredMinVersion)
|
|
350
|
+
continue;
|
|
351
|
+
if (declaredMinVersion === dep.resolved.version)
|
|
352
|
+
continue;
|
|
353
|
+
const vulns = db.getVulnerabilities(dep.name);
|
|
354
|
+
const affectedCves = [];
|
|
355
|
+
let highestFixVersion;
|
|
356
|
+
for (const vuln of vulns) {
|
|
357
|
+
if ((0, vulnerability_1.severityOrdinal)(vuln.severity) < (0, vulnerability_1.severityOrdinal)(this.minimumSeverity)) {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (!this.matchesCvePattern(vuln)) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (this.isVersionAffected(declaredMinVersion, vuln) &&
|
|
364
|
+
!this.isVersionAffected(dep.resolved.version, vuln)) {
|
|
365
|
+
affectedCves.push(vuln.cve);
|
|
366
|
+
const fixVersion = vuln.fixedVersion;
|
|
367
|
+
if (fixVersion && (!highestFixVersion || semver.gt(fixVersion, highestFixVersion))) {
|
|
368
|
+
highestFixVersion = fixVersion;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (affectedCves.length > 0 && highestFixVersion) {
|
|
373
|
+
if (this.isUpgradeWithinDelta(declaredMinVersion, highestFixVersion)) {
|
|
374
|
+
const majorVersion = semver.major(declaredMinVersion);
|
|
375
|
+
fixes.push({
|
|
376
|
+
packageName: dep.name,
|
|
377
|
+
newVersion: highestFixVersion,
|
|
378
|
+
scope,
|
|
379
|
+
isTransitive: false,
|
|
380
|
+
cves: affectedCves,
|
|
381
|
+
originalMajorVersion: majorVersion
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return fixes;
|
|
388
|
+
}
|
|
389
|
+
isUpgradeWithinDelta(fromVersion, toVersion) {
|
|
390
|
+
if (this.isReportOnly()) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
return this.isVersionWithinDelta(fromVersion, toVersion);
|
|
394
|
+
}
|
|
395
|
+
extractMinimumVersion(constraint) {
|
|
396
|
+
if (!constraint)
|
|
397
|
+
return undefined;
|
|
398
|
+
if (semver.valid(constraint)) {
|
|
399
|
+
return constraint;
|
|
400
|
+
}
|
|
401
|
+
const match = constraint.match(/^[~^>=<]*\s*(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/);
|
|
402
|
+
if (match && semver.valid(match[1])) {
|
|
403
|
+
return match[1];
|
|
404
|
+
}
|
|
405
|
+
const coerced = semver.coerce(constraint);
|
|
406
|
+
return coerced === null || coerced === void 0 ? void 0 : coerced.version;
|
|
407
|
+
}
|
|
408
|
+
findHighestSafeVersion(packageName, originalVersion, initialFixVersion, db, visited = new Set()) {
|
|
409
|
+
if (visited.has(initialFixVersion)) {
|
|
410
|
+
return initialFixVersion;
|
|
411
|
+
}
|
|
412
|
+
visited.add(initialFixVersion);
|
|
413
|
+
const vulnsInFixVersion = db.getVulnerabilities(packageName)
|
|
414
|
+
.filter(v => this.isVersionAffected(initialFixVersion, v));
|
|
415
|
+
if (vulnsInFixVersion.length === 0) {
|
|
416
|
+
return initialFixVersion;
|
|
417
|
+
}
|
|
418
|
+
let highestFixVersion = initialFixVersion;
|
|
419
|
+
for (const vuln of vulnsInFixVersion) {
|
|
420
|
+
const fixVersion = this.getUpgradeVersion(vuln);
|
|
421
|
+
if (fixVersion && semver.valid(fixVersion)) {
|
|
422
|
+
if (this.isVersionWithinDelta(originalVersion, fixVersion)) {
|
|
423
|
+
if (semver.gt(fixVersion, highestFixVersion)) {
|
|
424
|
+
highestFixVersion = fixVersion;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (highestFixVersion !== initialFixVersion) {
|
|
430
|
+
return this.findHighestSafeVersion(packageName, originalVersion, highestFixVersion, db, visited);
|
|
431
|
+
}
|
|
432
|
+
return initialFixVersion;
|
|
433
|
+
}
|
|
434
|
+
isVersionWithinDelta(originalVersion, targetVersion) {
|
|
435
|
+
try {
|
|
436
|
+
const original = semver.parse(originalVersion);
|
|
437
|
+
const target = semver.parse(targetVersion);
|
|
438
|
+
if (!original || !target)
|
|
439
|
+
return false;
|
|
440
|
+
switch (this.maximumUpgradeDelta) {
|
|
441
|
+
case 'patch':
|
|
442
|
+
return original.major === target.major && original.minor === target.minor;
|
|
443
|
+
case 'minor':
|
|
444
|
+
return original.major === target.major;
|
|
445
|
+
case 'major':
|
|
446
|
+
return true;
|
|
447
|
+
case 'none':
|
|
448
|
+
return false;
|
|
449
|
+
default:
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
catch (_a) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
computeFixes(vulnerabilities, db) {
|
|
458
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
327
459
|
if (this.isReportOnly()) {
|
|
328
460
|
return [];
|
|
329
461
|
}
|
|
330
|
-
const
|
|
462
|
+
const byPackageAndMajor = new Map();
|
|
331
463
|
for (const vuln of vulnerabilities) {
|
|
332
|
-
const
|
|
464
|
+
const parsed = semver.parse(vuln.resolved.version);
|
|
465
|
+
const major = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.major) !== null && _a !== void 0 ? _a : 0;
|
|
466
|
+
const key = `${vuln.resolved.name}@${major}`;
|
|
467
|
+
const existing = byPackageAndMajor.get(key) || [];
|
|
333
468
|
existing.push(vuln);
|
|
334
|
-
|
|
469
|
+
byPackageAndMajor.set(key, existing);
|
|
470
|
+
}
|
|
471
|
+
const majorVersionsByPackage = new Map();
|
|
472
|
+
for (const vuln of vulnerabilities) {
|
|
473
|
+
const parsed = semver.parse(vuln.resolved.version);
|
|
474
|
+
const major = (_b = parsed === null || parsed === void 0 ? void 0 : parsed.major) !== null && _b !== void 0 ? _b : 0;
|
|
475
|
+
const existing = majorVersionsByPackage.get(vuln.resolved.name) || new Set();
|
|
476
|
+
existing.add(major);
|
|
477
|
+
majorVersionsByPackage.set(vuln.resolved.name, existing);
|
|
335
478
|
}
|
|
336
479
|
const fixes = [];
|
|
337
|
-
for (const [
|
|
480
|
+
for (const [key, vulns] of byPackageAndMajor) {
|
|
481
|
+
const packageName = vulns[0].resolved.name;
|
|
482
|
+
const originalMajor = (_d = (_c = semver.parse(vulns[0].resolved.version)) === null || _c === void 0 ? void 0 : _c.major) !== null && _d !== void 0 ? _d : 0;
|
|
483
|
+
const hasMultipleMajorVersions = ((_f = (_e = majorVersionsByPackage.get(packageName)) === null || _e === void 0 ? void 0 : _e.size) !== null && _f !== void 0 ? _f : 0) > 1;
|
|
338
484
|
let highestFixVersion;
|
|
339
485
|
const cves = [];
|
|
340
486
|
let isTransitive = true;
|
|
341
487
|
let scope;
|
|
488
|
+
let originalVersion;
|
|
342
489
|
for (const vuln of vulns) {
|
|
490
|
+
if (!originalVersion) {
|
|
491
|
+
originalVersion = vuln.resolved.version;
|
|
492
|
+
}
|
|
343
493
|
if (!this.isUpgradeableWithinDelta(vuln.resolved.version, vuln.vulnerability)) {
|
|
344
494
|
continue;
|
|
345
495
|
}
|
|
346
496
|
const fixVersion = this.getUpgradeVersion(vuln.vulnerability);
|
|
347
497
|
if (fixVersion) {
|
|
348
|
-
|
|
349
|
-
|
|
498
|
+
const fixMajor = (_g = semver.parse(fixVersion)) === null || _g === void 0 ? void 0 : _g.major;
|
|
499
|
+
const shouldConsiderFix = hasMultipleMajorVersions
|
|
500
|
+
? fixMajor === originalMajor
|
|
501
|
+
: true;
|
|
502
|
+
if (shouldConsiderFix) {
|
|
503
|
+
if (!highestFixVersion || semver.gt(fixVersion, highestFixVersion)) {
|
|
504
|
+
highestFixVersion = fixVersion;
|
|
505
|
+
}
|
|
350
506
|
}
|
|
351
507
|
}
|
|
352
508
|
cves.push(vuln.vulnerability.cve);
|
|
@@ -355,13 +511,15 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
355
511
|
scope = vuln.scope;
|
|
356
512
|
}
|
|
357
513
|
}
|
|
358
|
-
if (highestFixVersion && cves.length > 0) {
|
|
514
|
+
if (highestFixVersion && cves.length > 0 && originalVersion) {
|
|
515
|
+
const safeVersion = this.findHighestSafeVersion(packageName, originalVersion, highestFixVersion, db);
|
|
359
516
|
fixes.push({
|
|
360
517
|
packageName,
|
|
361
|
-
newVersion: highestFixVersion,
|
|
518
|
+
newVersion: safeVersion || highestFixVersion,
|
|
362
519
|
isTransitive,
|
|
363
520
|
cves,
|
|
364
|
-
scope
|
|
521
|
+
scope,
|
|
522
|
+
originalMajorVersion: originalMajor
|
|
365
523
|
});
|
|
366
524
|
}
|
|
367
525
|
}
|
|
@@ -370,22 +528,47 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
370
528
|
scanner(acc) {
|
|
371
529
|
return __awaiter(this, void 0, void 0, function* () {
|
|
372
530
|
const recipe = this;
|
|
373
|
-
|
|
374
|
-
|
|
531
|
+
const LOCK_FILE_NAMES = ['pnpm-lock.yaml', 'yarn.lock', 'package-lock.json', 'bun.lock'];
|
|
532
|
+
return new class extends rewrite_1.TreeVisitor {
|
|
533
|
+
accept(tree, ctx) {
|
|
375
534
|
return __awaiter(this, void 0, void 0, function* () {
|
|
376
|
-
|
|
535
|
+
if ((0, json_1.isJson)(tree) && tree.kind === json_1.Json.Kind.Document) {
|
|
536
|
+
return this.handleJsonDocument(tree, ctx);
|
|
537
|
+
}
|
|
538
|
+
if ((0, yaml_1.isYaml)(tree) && (0, yaml_1.isDocuments)(tree)) {
|
|
539
|
+
return this.handleYamlDocument(tree, ctx);
|
|
540
|
+
}
|
|
541
|
+
if ((0, text_1.isPlainText)(tree)) {
|
|
542
|
+
return this.handlePlainTextDocument(tree, ctx);
|
|
543
|
+
}
|
|
544
|
+
return tree;
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
handleJsonDocument(doc, _ctx) {
|
|
548
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
549
|
+
var _a, _b;
|
|
550
|
+
const basename = path.basename(doc.sourcePath);
|
|
551
|
+
if (LOCK_FILE_NAMES.includes(basename)) {
|
|
552
|
+
acc.originalLockFiles.set(doc.sourcePath, yield rewrite_1.TreePrinters.print(doc));
|
|
553
|
+
return doc;
|
|
554
|
+
}
|
|
377
555
|
if (!doc.sourcePath.endsWith('package.json')) {
|
|
378
556
|
return doc;
|
|
379
557
|
}
|
|
558
|
+
const packageJsonContent = yield rewrite_1.TreePrinters.print(doc);
|
|
559
|
+
acc.allPackageJsonContents.set(doc.sourcePath, packageJsonContent);
|
|
380
560
|
const marker = (0, javascript_1.findNodeResolutionResult)(doc);
|
|
381
561
|
if (!marker) {
|
|
382
562
|
return doc;
|
|
383
563
|
}
|
|
564
|
+
if (marker.workspacePackagePaths && marker.workspacePackagePaths.length > 0) {
|
|
565
|
+
acc.workspaceRoots.set(doc.sourcePath, [...marker.workspacePackagePaths]);
|
|
566
|
+
}
|
|
384
567
|
const vulnerabilities = [];
|
|
385
568
|
const visited = new Set();
|
|
386
569
|
const scopesToCheck = recipe.scope
|
|
387
570
|
? [recipe.scope]
|
|
388
|
-
:
|
|
571
|
+
: ALL_DEPENDENCY_SCOPES;
|
|
389
572
|
for (const scope of scopesToCheck) {
|
|
390
573
|
const deps = marker[scope] || [];
|
|
391
574
|
for (const dep of deps) {
|
|
@@ -394,37 +577,81 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
394
577
|
}
|
|
395
578
|
}
|
|
396
579
|
}
|
|
580
|
+
const pm = (_a = marker.packageManager) !== null && _a !== void 0 ? _a : "Npm";
|
|
581
|
+
const configFiles = {};
|
|
582
|
+
const projectNpmrc = (_b = marker.npmrcConfigs) === null || _b === void 0 ? void 0 : _b.find(c => c.scope === "Project");
|
|
583
|
+
if (projectNpmrc) {
|
|
584
|
+
const lines = Object.entries(projectNpmrc.properties)
|
|
585
|
+
.map(([key, value]) => `${key}=${value}`);
|
|
586
|
+
configFiles['.npmrc'] = lines.join('\n');
|
|
587
|
+
}
|
|
588
|
+
const storedContent = acc.allPackageJsonContents.get(doc.sourcePath);
|
|
589
|
+
let isWorkspaceRoot = false;
|
|
590
|
+
if (storedContent) {
|
|
591
|
+
try {
|
|
592
|
+
isWorkspaceRoot = JSON.parse(storedContent).workspaces !== undefined;
|
|
593
|
+
}
|
|
594
|
+
catch (_c) {
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
let fixes = [];
|
|
397
598
|
if (vulnerabilities.length > 0) {
|
|
398
599
|
acc.vulnerableByProject.set(doc.sourcePath, vulnerabilities);
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
600
|
+
fixes = recipe.computeFixes(vulnerabilities, acc.db);
|
|
601
|
+
}
|
|
602
|
+
if (recipe.fixDeclaredVersions) {
|
|
603
|
+
const preventiveFixes = recipe.findPreventiveFixes(marker, scopesToCheck, acc.db);
|
|
604
|
+
const existingPackages = new Set(fixes.map(f => `${f.packageName}@${f.scope}`));
|
|
605
|
+
for (const fix of preventiveFixes) {
|
|
606
|
+
const key = `${fix.packageName}@${fix.scope}`;
|
|
607
|
+
if (!existingPackages.has(key)) {
|
|
608
|
+
fixes.push(fix);
|
|
609
|
+
existingPackages.add(key);
|
|
610
|
+
}
|
|
410
611
|
}
|
|
411
612
|
}
|
|
613
|
+
if (fixes.length > 0) {
|
|
614
|
+
acc.fixesByProject.set(doc.sourcePath, fixes);
|
|
615
|
+
acc.projectsToUpdate.set(doc.sourcePath, {
|
|
616
|
+
packageJsonPath: doc.sourcePath,
|
|
617
|
+
originalPackageJson: yield rewrite_1.TreePrinters.print(doc),
|
|
618
|
+
packageManager: pm,
|
|
619
|
+
configFiles: Object.keys(configFiles).length > 0 ? configFiles : undefined
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
else if (isWorkspaceRoot && !acc.projectsToUpdate.has(doc.sourcePath)) {
|
|
623
|
+
acc.projectsToUpdate.set(doc.sourcePath, {
|
|
624
|
+
packageJsonPath: doc.sourcePath,
|
|
625
|
+
originalPackageJson: yield rewrite_1.TreePrinters.print(doc),
|
|
626
|
+
packageManager: pm,
|
|
627
|
+
configFiles: Object.keys(configFiles).length > 0 ? configFiles : undefined
|
|
628
|
+
});
|
|
629
|
+
}
|
|
412
630
|
return doc;
|
|
413
631
|
});
|
|
414
632
|
}
|
|
415
|
-
|
|
633
|
+
handleYamlDocument(docs, _ctx) {
|
|
416
634
|
return __awaiter(this, void 0, void 0, function* () {
|
|
417
|
-
|
|
635
|
+
const basename = path.basename(docs.sourcePath);
|
|
636
|
+
if (LOCK_FILE_NAMES.includes(basename)) {
|
|
637
|
+
acc.originalLockFiles.set(docs.sourcePath, yield rewrite_1.TreePrinters.print(docs));
|
|
638
|
+
}
|
|
639
|
+
return docs;
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
handlePlainTextDocument(text, _ctx) {
|
|
643
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
644
|
+
const basename = path.basename(text.sourcePath);
|
|
645
|
+
if (LOCK_FILE_NAMES.includes(basename)) {
|
|
646
|
+
acc.originalLockFiles.set(text.sourcePath, yield rewrite_1.TreePrinters.print(text));
|
|
647
|
+
}
|
|
648
|
+
return text;
|
|
418
649
|
});
|
|
419
650
|
}
|
|
420
651
|
};
|
|
421
652
|
});
|
|
422
653
|
}
|
|
423
|
-
|
|
424
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
425
|
-
return [];
|
|
426
|
-
});
|
|
427
|
-
}
|
|
654
|
+
;
|
|
428
655
|
editorWithData(acc) {
|
|
429
656
|
return __awaiter(this, void 0, void 0, function* () {
|
|
430
657
|
const recipe = this;
|
|
@@ -498,14 +725,65 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
498
725
|
handlePackageJson(doc, ctx) {
|
|
499
726
|
return __awaiter(this, void 0, void 0, function* () {
|
|
500
727
|
const vulnerabilities = acc.vulnerableByProject.get(doc.sourcePath);
|
|
501
|
-
if (
|
|
728
|
+
if (vulnerabilities && vulnerabilities.length > 0) {
|
|
729
|
+
for (const vuln of vulnerabilities) {
|
|
730
|
+
const upgradeable = recipe.isUpgradeableWithinDelta(vuln.resolved.version, vuln.vulnerability);
|
|
731
|
+
recipe.vulnerabilityReport.insertRow(ctx, new VulnerabilityReportRow(doc.sourcePath, vuln.vulnerability.cve, vuln.resolved.name, vuln.resolved.version, vuln.vulnerability.fixedVersion || '', vuln.vulnerability.lastAffectedVersion || '', upgradeable, vuln.vulnerability.summary, vuln.vulnerability.severity, vuln.depth, vuln.vulnerability.cwes, vuln.isDirect, recipe.renderPath(vuln.scope, vuln.path)));
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
if (recipe.isReportOnly()) {
|
|
502
735
|
return doc;
|
|
503
736
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
737
|
+
if (!acc.workspaceDetectionComplete) {
|
|
738
|
+
this.detectWorkspacesFromContents();
|
|
739
|
+
acc.workspaceDetectionComplete = true;
|
|
507
740
|
}
|
|
508
|
-
|
|
741
|
+
const preModifiedContent = acc.modifiedWorkspaceMemberContents.get(doc.sourcePath)
|
|
742
|
+
|| acc.updatedPackageJsons.get(doc.sourcePath);
|
|
743
|
+
if (preModifiedContent) {
|
|
744
|
+
return this.applyModifiedContent(doc, preModifiedContent);
|
|
745
|
+
}
|
|
746
|
+
const isWorkspaceRoot = acc.workspaceRoots.has(doc.sourcePath);
|
|
747
|
+
const workspaceRootPath = this.findWorkspaceRootFor(doc.sourcePath);
|
|
748
|
+
const isWorkspaceMember = workspaceRootPath !== undefined;
|
|
749
|
+
if (isWorkspaceMember && !isWorkspaceRoot) {
|
|
750
|
+
const needsProcessing = this.workspaceNeedsProcessing(workspaceRootPath);
|
|
751
|
+
if (needsProcessing && !acc.processedProjects.has(workspaceRootPath)) {
|
|
752
|
+
const rootUpdateInfo = acc.projectsToUpdate.get(workspaceRootPath);
|
|
753
|
+
if (rootUpdateInfo) {
|
|
754
|
+
const failureMessage = yield (0, javascript_1.runInstallIfNeeded)(workspaceRootPath, acc, () => recipe.runWorkspacePackageManagerInstall(acc, workspaceRootPath, rootUpdateInfo));
|
|
755
|
+
if (failureMessage) {
|
|
756
|
+
return (0, rewrite_1.markupWarn)(doc, `Failed to fix vulnerabilities in workspace`, failureMessage);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
const modifiedContent = acc.modifiedWorkspaceMemberContents.get(doc.sourcePath);
|
|
761
|
+
if (modifiedContent) {
|
|
762
|
+
return this.applyModifiedContent(doc, modifiedContent);
|
|
763
|
+
}
|
|
764
|
+
return doc;
|
|
765
|
+
}
|
|
766
|
+
if (isWorkspaceRoot) {
|
|
767
|
+
const updateInfo = acc.projectsToUpdate.get(doc.sourcePath);
|
|
768
|
+
if (!updateInfo) {
|
|
769
|
+
return doc;
|
|
770
|
+
}
|
|
771
|
+
const needsProcessing = this.workspaceNeedsProcessing(doc.sourcePath);
|
|
772
|
+
if (!needsProcessing) {
|
|
773
|
+
return doc;
|
|
774
|
+
}
|
|
775
|
+
const failureMessage = yield (0, javascript_1.runInstallIfNeeded)(doc.sourcePath, acc, () => recipe.runWorkspacePackageManagerInstall(acc, doc.sourcePath, updateInfo));
|
|
776
|
+
if (failureMessage) {
|
|
777
|
+
return (0, rewrite_1.markupWarn)(doc, `Failed to fix vulnerabilities in ${doc.sourcePath}`, failureMessage);
|
|
778
|
+
}
|
|
779
|
+
const rootFixes = acc.fixesByProject.get(doc.sourcePath) || [];
|
|
780
|
+
if (rootFixes.length > 0) {
|
|
781
|
+
const modifiedContent = acc.updatedPackageJsons.get(doc.sourcePath);
|
|
782
|
+
if (modifiedContent) {
|
|
783
|
+
const result = yield this.applyModifiedContent(doc, modifiedContent);
|
|
784
|
+
return (0, javascript_1.updateNodeResolutionMarker)(result, updateInfo, acc);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
509
787
|
return doc;
|
|
510
788
|
}
|
|
511
789
|
const fixes = acc.fixesByProject.get(doc.sourcePath);
|
|
@@ -517,28 +795,159 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
517
795
|
if (failureMessage) {
|
|
518
796
|
return (0, rewrite_1.markupWarn)(doc, `Failed to fix vulnerabilities in ${doc.sourcePath}`, failureMessage);
|
|
519
797
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const visitor = new UpdateVersionVisitor(fix.packageName, fix.newVersion, fix.scope);
|
|
524
|
-
result = (yield visitor.visit(result, undefined));
|
|
525
|
-
}
|
|
798
|
+
const modifiedPackageJson = acc.updatedPackageJsons.get(doc.sourcePath);
|
|
799
|
+
if (!modifiedPackageJson) {
|
|
800
|
+
return doc;
|
|
526
801
|
}
|
|
802
|
+
const result = yield this.applyModifiedContent(doc, modifiedPackageJson);
|
|
527
803
|
return (0, javascript_1.updateNodeResolutionMarker)(result, updateInfo, acc);
|
|
528
804
|
});
|
|
529
805
|
}
|
|
806
|
+
findWorkspaceRootFor(packageJsonPath) {
|
|
807
|
+
for (const [rootPath, memberPaths] of acc.workspaceRoots) {
|
|
808
|
+
if (memberPaths.includes(packageJsonPath)) {
|
|
809
|
+
return rootPath;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
return undefined;
|
|
813
|
+
}
|
|
814
|
+
workspaceNeedsProcessing(rootPath) {
|
|
815
|
+
if (acc.fixesByProject.has(rootPath)) {
|
|
816
|
+
return true;
|
|
817
|
+
}
|
|
818
|
+
const memberPaths = acc.workspaceRoots.get(rootPath) || [];
|
|
819
|
+
for (const memberPath of memberPaths) {
|
|
820
|
+
if (acc.fixesByProject.has(memberPath)) {
|
|
821
|
+
return true;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
detectWorkspacesFromContents() {
|
|
827
|
+
for (const [pkgPath, content] of acc.allPackageJsonContents) {
|
|
828
|
+
if (acc.workspaceRoots.has(pkgPath)) {
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
try {
|
|
832
|
+
const pkgJson = JSON.parse(content);
|
|
833
|
+
if (!pkgJson.workspaces) {
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
const patterns = Array.isArray(pkgJson.workspaces)
|
|
837
|
+
? pkgJson.workspaces
|
|
838
|
+
: pkgJson.workspaces.packages || [];
|
|
839
|
+
if (patterns.length === 0) {
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
const rootDir = path.dirname(pkgPath);
|
|
843
|
+
const memberPaths = [];
|
|
844
|
+
for (const [otherPath] of acc.allPackageJsonContents) {
|
|
845
|
+
if (otherPath === pkgPath)
|
|
846
|
+
continue;
|
|
847
|
+
const relativePath = rootDir === '.'
|
|
848
|
+
? otherPath
|
|
849
|
+
: otherPath.startsWith(rootDir + '/')
|
|
850
|
+
? otherPath.slice(rootDir.length + 1)
|
|
851
|
+
: null;
|
|
852
|
+
if (relativePath && this.matchesWorkspacePattern(relativePath, patterns)) {
|
|
853
|
+
memberPaths.push(otherPath);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (memberPaths.length > 0) {
|
|
857
|
+
acc.workspaceRoots.set(pkgPath, memberPaths);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
catch (_a) {
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
matchesWorkspacePattern(relativePath, patterns) {
|
|
865
|
+
for (const pattern of patterns) {
|
|
866
|
+
if (pattern.endsWith('/*')) {
|
|
867
|
+
const baseDir = pattern.slice(0, -2);
|
|
868
|
+
const pathParts = relativePath.split('/');
|
|
869
|
+
if (pathParts.length === 3 &&
|
|
870
|
+
pathParts[0] === baseDir &&
|
|
871
|
+
pathParts[2] === 'package.json') {
|
|
872
|
+
return true;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
else if (!pattern.includes('*')) {
|
|
876
|
+
if (relativePath === `${pattern}/package.json`) {
|
|
877
|
+
return true;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
applyModifiedContent(doc, content) {
|
|
884
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
885
|
+
const parsedModified = yield new json_1.JsonParser({}).parseOne({
|
|
886
|
+
text: content,
|
|
887
|
+
sourcePath: doc.sourcePath
|
|
888
|
+
});
|
|
889
|
+
return Object.assign(Object.assign({}, doc), { value: parsedModified.value, eof: parsedModified.eof });
|
|
890
|
+
});
|
|
891
|
+
}
|
|
530
892
|
};
|
|
531
893
|
});
|
|
532
894
|
}
|
|
533
895
|
runPackageManagerInstall(acc, updateInfo, fixes) {
|
|
534
896
|
return __awaiter(this, void 0, void 0, function* () {
|
|
535
|
-
const modifiedPackageJson = this.createModifiedPackageJson(updateInfo.originalPackageJson, fixes);
|
|
536
|
-
const result = yield (0, javascript_1.runInstallInTempDir)(updateInfo.
|
|
897
|
+
const modifiedPackageJson = this.createModifiedPackageJson(updateInfo.originalPackageJson, fixes, updateInfo.packageManager);
|
|
898
|
+
const result = yield (0, javascript_1.runInstallInTempDir)(updateInfo.packageManager, modifiedPackageJson, {
|
|
899
|
+
configFiles: updateInfo.configFiles
|
|
900
|
+
});
|
|
537
901
|
(0, javascript_1.storeInstallResult)(result, acc, updateInfo, modifiedPackageJson);
|
|
538
902
|
});
|
|
539
903
|
}
|
|
540
|
-
|
|
541
|
-
|
|
904
|
+
runWorkspacePackageManagerInstall(acc, rootPath, rootUpdateInfo) {
|
|
905
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
906
|
+
const memberPaths = acc.workspaceRoots.get(rootPath) || [];
|
|
907
|
+
const pm = rootUpdateInfo.packageManager;
|
|
908
|
+
const allTransitiveFixes = [];
|
|
909
|
+
const rootFixes = acc.fixesByProject.get(rootPath) || [];
|
|
910
|
+
const rootDirectFixes = rootFixes.filter(f => !f.isTransitive);
|
|
911
|
+
const rootTransitiveFixes = rootFixes.filter(f => f.isTransitive);
|
|
912
|
+
allTransitiveFixes.push(...rootTransitiveFixes);
|
|
913
|
+
const memberDirectFixes = new Map();
|
|
914
|
+
for (const memberPath of memberPaths) {
|
|
915
|
+
const memberFixes = acc.fixesByProject.get(memberPath) || [];
|
|
916
|
+
const directFixes = memberFixes.filter(f => !f.isTransitive);
|
|
917
|
+
const transitiveFixes = memberFixes.filter(f => f.isTransitive);
|
|
918
|
+
if (directFixes.length > 0) {
|
|
919
|
+
memberDirectFixes.set(memberPath, directFixes);
|
|
920
|
+
}
|
|
921
|
+
allTransitiveFixes.push(...transitiveFixes);
|
|
922
|
+
}
|
|
923
|
+
const rootOriginalContent = acc.allPackageJsonContents.get(rootPath) || rootUpdateInfo.originalPackageJson;
|
|
924
|
+
const modifiedRootPackageJson = this.createModifiedPackageJson(rootOriginalContent, [...rootDirectFixes, ...allTransitiveFixes], pm);
|
|
925
|
+
const workspacePackages = {};
|
|
926
|
+
for (const memberPath of memberPaths) {
|
|
927
|
+
const originalContent = acc.allPackageJsonContents.get(memberPath);
|
|
928
|
+
if (!originalContent) {
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
const directFixes = memberDirectFixes.get(memberPath);
|
|
932
|
+
let modifiedContent;
|
|
933
|
+
if (directFixes && directFixes.length > 0) {
|
|
934
|
+
modifiedContent = this.createModifiedPackageJsonDirectOnly(originalContent, directFixes);
|
|
935
|
+
acc.modifiedWorkspaceMemberContents.set(memberPath, modifiedContent);
|
|
936
|
+
}
|
|
937
|
+
else {
|
|
938
|
+
modifiedContent = originalContent;
|
|
939
|
+
}
|
|
940
|
+
workspacePackages[memberPath] = modifiedContent;
|
|
941
|
+
}
|
|
942
|
+
const result = yield (0, javascript_1.runWorkspaceInstallInTempDir)(pm, modifiedRootPackageJson, {
|
|
943
|
+
configFiles: rootUpdateInfo.configFiles,
|
|
944
|
+
workspacePackages
|
|
945
|
+
});
|
|
946
|
+
(0, javascript_1.storeInstallResult)(result, acc, rootUpdateInfo, modifiedRootPackageJson);
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
createModifiedPackageJsonDirectOnly(originalContent, fixes) {
|
|
950
|
+
let packageJson = JSON.parse(originalContent);
|
|
542
951
|
for (const fix of fixes) {
|
|
543
952
|
if (!fix.isTransitive && fix.scope) {
|
|
544
953
|
if (packageJson[fix.scope] && packageJson[fix.scope][fix.packageName]) {
|
|
@@ -549,6 +958,75 @@ class DependencyVulnerabilityCheck extends rewrite_1.ScanningRecipe {
|
|
|
549
958
|
}
|
|
550
959
|
return JSON.stringify(packageJson, null, 2);
|
|
551
960
|
}
|
|
961
|
+
createModifiedPackageJson(originalContent, fixes, packageManager) {
|
|
962
|
+
var _a, _b, _c;
|
|
963
|
+
let packageJson = JSON.parse(originalContent);
|
|
964
|
+
const fixesByPackage = new Map();
|
|
965
|
+
for (const fix of fixes) {
|
|
966
|
+
const existing = fixesByPackage.get(fix.packageName) || [];
|
|
967
|
+
existing.push(fix);
|
|
968
|
+
fixesByPackage.set(fix.packageName, existing);
|
|
969
|
+
}
|
|
970
|
+
for (const fix of fixes) {
|
|
971
|
+
if (!fix.isTransitive && fix.scope) {
|
|
972
|
+
if (packageJson[fix.scope] && packageJson[fix.scope][fix.packageName]) {
|
|
973
|
+
const originalVersion = packageJson[fix.scope][fix.packageName];
|
|
974
|
+
packageJson[fix.scope][fix.packageName] = applyVersionPrefix(originalVersion, fix.newVersion);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
else if (fix.isTransitive) {
|
|
978
|
+
const directDepScope = findDirectDependencyScope(packageJson, fix.packageName);
|
|
979
|
+
if (directDepScope) {
|
|
980
|
+
const directVersion = packageJson[directDepScope][fix.packageName];
|
|
981
|
+
const directMajor = semver.major(semver.coerce(directVersion) || '0.0.0');
|
|
982
|
+
if (fix.originalMajorVersion !== undefined && directMajor !== fix.originalMajorVersion) {
|
|
983
|
+
const isYarn = packageManager === "YarnClassic" ||
|
|
984
|
+
packageManager === "YarnBerry";
|
|
985
|
+
if (!isYarn) {
|
|
986
|
+
const versionSpecificKey = `${fix.packageName}@^${fix.originalMajorVersion}`;
|
|
987
|
+
packageJson = (0, javascript_1.applyOverrideToPackageJson)(packageJson, packageManager, versionSpecificKey, fix.newVersion);
|
|
988
|
+
}
|
|
989
|
+
else {
|
|
990
|
+
}
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
packageJson[directDepScope][fix.packageName] = applyVersionPrefix(directVersion, fix.newVersion);
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
const packageFixes = fixesByPackage.get(fix.packageName) || [];
|
|
997
|
+
const hasMultipleMajorVersions = packageFixes.length > 1 &&
|
|
998
|
+
new Set(packageFixes.map(f => f.originalMajorVersion)).size > 1;
|
|
999
|
+
const existingOverrides = getOverridesFromPackageJson(packageJson, packageManager);
|
|
1000
|
+
const hasExistingVersionSpecificOverrides = existingOverrides &&
|
|
1001
|
+
Object.keys(existingOverrides).some(key => key.startsWith(`${fix.packageName}@`));
|
|
1002
|
+
const isYarn = packageManager === "YarnClassic" ||
|
|
1003
|
+
packageManager === "YarnBerry";
|
|
1004
|
+
const useVersionSpecificOverride = !isYarn &&
|
|
1005
|
+
(hasMultipleMajorVersions || hasExistingVersionSpecificOverrides) &&
|
|
1006
|
+
fix.originalMajorVersion !== undefined;
|
|
1007
|
+
if (useVersionSpecificOverride) {
|
|
1008
|
+
const versionSpecificKey = `${fix.packageName}@^${fix.originalMajorVersion}`;
|
|
1009
|
+
packageJson = (0, javascript_1.applyOverrideToPackageJson)(packageJson, packageManager, versionSpecificKey, fix.newVersion);
|
|
1010
|
+
}
|
|
1011
|
+
else {
|
|
1012
|
+
packageJson = (0, javascript_1.applyOverrideToPackageJson)(packageJson, packageManager, fix.packageName, fix.newVersion);
|
|
1013
|
+
}
|
|
1014
|
+
if (packageManager === "Pnpm") {
|
|
1015
|
+
if (!packageJson.devDependencies) {
|
|
1016
|
+
packageJson.devDependencies = {};
|
|
1017
|
+
}
|
|
1018
|
+
if (!((_a = packageJson.dependencies) === null || _a === void 0 ? void 0 : _a[fix.packageName]) &&
|
|
1019
|
+
!packageJson.devDependencies[fix.packageName] &&
|
|
1020
|
+
!((_b = packageJson.peerDependencies) === null || _b === void 0 ? void 0 : _b[fix.packageName]) &&
|
|
1021
|
+
!((_c = packageJson.optionalDependencies) === null || _c === void 0 ? void 0 : _c[fix.packageName])) {
|
|
1022
|
+
const prefix = this.getVersionPrefixForDelta();
|
|
1023
|
+
packageJson.devDependencies[fix.packageName] = prefix + fix.newVersion;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
return JSON.stringify(packageJson, null, 2);
|
|
1029
|
+
}
|
|
552
1030
|
}
|
|
553
1031
|
exports.DependencyVulnerabilityCheck = DependencyVulnerabilityCheck;
|
|
554
1032
|
__decorate([
|
|
@@ -606,6 +1084,18 @@ __decorate([
|
|
|
606
1084
|
example: "CVE-2023-.*"
|
|
607
1085
|
})
|
|
608
1086
|
], DependencyVulnerabilityCheck.prototype, "cvePattern", void 0);
|
|
1087
|
+
__decorate([
|
|
1088
|
+
(0, rewrite_1.Option)({
|
|
1089
|
+
displayName: "Fix declared versions",
|
|
1090
|
+
description: "When enabled, also upgrades version specifiers declared in package.json that specify vulnerable versions, " +
|
|
1091
|
+
"even if the lock file already resolves to a safe version. This is a preventive measure to ensure that " +
|
|
1092
|
+
"future installs (e.g., on a different machine or after lock file changes) won't install vulnerable versions. " +
|
|
1093
|
+
"These preventive upgrades are NOT reported in the vulnerability data table since there's no actual vulnerability. " +
|
|
1094
|
+
"Default is false.",
|
|
1095
|
+
required: false,
|
|
1096
|
+
example: "true"
|
|
1097
|
+
})
|
|
1098
|
+
], DependencyVulnerabilityCheck.prototype, "fixDeclaredVersions", void 0);
|
|
609
1099
|
function extractVersionPrefix(versionString) {
|
|
610
1100
|
const match = versionString.match(/^([~^]|>=?|<=?|=)?(.*)$/);
|
|
611
1101
|
if (match) {
|
|
@@ -620,41 +1110,28 @@ function applyVersionPrefix(originalVersion, newVersion) {
|
|
|
620
1110
|
const { prefix } = extractVersionPrefix(originalVersion);
|
|
621
1111
|
return prefix + newVersion;
|
|
622
1112
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
this.targetScope = targetScope;
|
|
630
|
-
}
|
|
631
|
-
visitMember(member, p) {
|
|
632
|
-
const _super = Object.create(null, {
|
|
633
|
-
visitMember: { get: () => super.visitMember }
|
|
634
|
-
});
|
|
635
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
636
|
-
const keyName = (0, json_1.getMemberKeyName)(member);
|
|
637
|
-
if (keyName === this.targetScope) {
|
|
638
|
-
this.inTargetScope = true;
|
|
639
|
-
const result = yield _super.visitMember.call(this, member, p);
|
|
640
|
-
this.inTargetScope = false;
|
|
641
|
-
return result;
|
|
642
|
-
}
|
|
643
|
-
if (this.inTargetScope && keyName === this.packageName) {
|
|
644
|
-
return this.updateVersion(member);
|
|
645
|
-
}
|
|
646
|
-
return _super.visitMember.call(this, member, p);
|
|
647
|
-
});
|
|
1113
|
+
function findDirectDependencyScope(packageJson, packageName) {
|
|
1114
|
+
var _a;
|
|
1115
|
+
for (const scope of ALL_DEPENDENCY_SCOPES) {
|
|
1116
|
+
if ((_a = packageJson[scope]) === null || _a === void 0 ? void 0 : _a[packageName]) {
|
|
1117
|
+
return scope;
|
|
1118
|
+
}
|
|
648
1119
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
1120
|
+
return undefined;
|
|
1121
|
+
}
|
|
1122
|
+
function getOverridesFromPackageJson(packageJson, packageManager) {
|
|
1123
|
+
var _a;
|
|
1124
|
+
switch (packageManager) {
|
|
1125
|
+
case "Npm":
|
|
1126
|
+
case "Bun":
|
|
1127
|
+
return packageJson.overrides;
|
|
1128
|
+
case "Pnpm":
|
|
1129
|
+
return (_a = packageJson.pnpm) === null || _a === void 0 ? void 0 : _a.overrides;
|
|
1130
|
+
case "YarnClassic":
|
|
1131
|
+
case "YarnBerry":
|
|
1132
|
+
return packageJson.resolutions;
|
|
1133
|
+
default:
|
|
1134
|
+
return undefined;
|
|
658
1135
|
}
|
|
659
1136
|
}
|
|
660
1137
|
//# sourceMappingURL=dependency-vulnerability-check.js.map
|