@pnpm/deps.compliance.commands 1000.0.0 → 1100.0.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.
- package/lib/audit/audit.d.ts +3 -2
- package/lib/audit/audit.js +18 -9
- package/lib/audit/fix.d.ts +7 -2
- package/lib/audit/fix.js +27 -7
- package/lib/audit/fixWithUpdate.d.ts +1 -0
- package/lib/audit/fixWithUpdate.js +18 -2
- package/lib/licenses/licensesList.d.ts +2 -2
- package/lib/sbom/sbom.d.ts +2 -2
- package/package.json +34 -32
package/lib/audit/audit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Config, type UniversalOptions } from '@pnpm/config.reader';
|
|
1
|
+
import { type Config, type ConfigContext, type UniversalOptions } from '@pnpm/config.reader';
|
|
2
2
|
import { type AuditReport } from '@pnpm/deps.compliance.audit';
|
|
3
3
|
import { type InstallCommandOptions } from '@pnpm/installing.commands';
|
|
4
4
|
import type { Registries } from '@pnpm/types';
|
|
@@ -7,6 +7,7 @@ export declare function rcOptionsTypes(): Record<string, unknown>;
|
|
|
7
7
|
export declare function cliOptionsTypes(): Record<string, unknown>;
|
|
8
8
|
export declare const shorthands: Record<string, string>;
|
|
9
9
|
export declare const commandNames: string[];
|
|
10
|
+
export declare const recursiveByDefault = true;
|
|
10
11
|
export declare function help(): string;
|
|
11
12
|
export type AuditOptions = Pick<UniversalOptions, 'dir'> & {
|
|
12
13
|
fix?: boolean | 'override' | 'update';
|
|
@@ -16,7 +17,7 @@ export type AuditOptions = Pick<UniversalOptions, 'dir'> & {
|
|
|
16
17
|
registries: Registries;
|
|
17
18
|
ignore?: string[];
|
|
18
19
|
ignoreUnfixable?: boolean;
|
|
19
|
-
} & Pick<Config, 'auditConfig' | 'auditLevel' | 'ca' | 'cert' | 'httpProxy' | 'httpsProxy' | 'key' | 'localAddress' | 'maxSockets' | 'noProxy' | 'strictSsl' | 'fetchRetries' | 'fetchRetryMaxtimeout' | 'fetchRetryMintimeout' | 'fetchRetryFactor' | 'fetchTimeout' | 'production' | 'dev' | 'overrides' | 'optional' | '
|
|
20
|
+
} & Pick<Config, 'auditConfig' | 'auditLevel' | 'minimumReleaseAge' | 'ca' | 'cert' | 'httpProxy' | 'httpsProxy' | 'key' | 'localAddress' | 'maxSockets' | 'noProxy' | 'strictSsl' | 'fetchRetries' | 'fetchRetryMaxtimeout' | 'fetchRetryMintimeout' | 'fetchRetryFactor' | 'fetchTimeout' | 'production' | 'dev' | 'overrides' | 'optional' | 'configByUri' | 'virtualStoreDirMaxLength' | 'workspaceDir'> & Pick<ConfigContext, 'rootProjectManifest' | 'rootProjectManifestDir'> & InstallCommandOptions;
|
|
20
21
|
export declare function handler(opts: AuditOptions): Promise<{
|
|
21
22
|
exitCode: number;
|
|
22
23
|
output: string;
|
package/lib/audit/audit.js
CHANGED
|
@@ -69,6 +69,7 @@ export const shorthands = {
|
|
|
69
69
|
P: '--production',
|
|
70
70
|
};
|
|
71
71
|
export const commandNames = ['audit'];
|
|
72
|
+
export const recursiveByDefault = true;
|
|
72
73
|
export function help() {
|
|
73
74
|
return renderHelp({
|
|
74
75
|
description: 'Checks for known security issues with the installed packages.',
|
|
@@ -135,10 +136,10 @@ export async function handler(opts) {
|
|
|
135
136
|
optionalDependencies: opts.optional !== false,
|
|
136
137
|
};
|
|
137
138
|
let auditReport;
|
|
138
|
-
const getAuthHeader = createGetAuthHeaderByURI(
|
|
139
|
+
const getAuthHeader = createGetAuthHeaderByURI(opts.configByUri, opts.registries?.default);
|
|
139
140
|
try {
|
|
140
141
|
auditReport = await audit(lockfile, getAuthHeader, {
|
|
141
|
-
|
|
142
|
+
dispatcherOptions: {
|
|
142
143
|
ca: opts.ca,
|
|
143
144
|
cert: opts.cert,
|
|
144
145
|
httpProxy: opts.httpProxy,
|
|
@@ -188,26 +189,34 @@ export async function handler(opts) {
|
|
|
188
189
|
}
|
|
189
190
|
if (fixMethod === 'update') {
|
|
190
191
|
const result = await fixWithUpdate(auditReport, { ...opts, include });
|
|
192
|
+
let output = formatFixWithUpdateOutput(result, auditReport);
|
|
193
|
+
if (result.addedAgeExcludes.length > 0) {
|
|
194
|
+
output += `\n${result.addedAgeExcludes.length} entries were added to minimumReleaseAgeExclude to allow installing the patched versions:\n${result.addedAgeExcludes.join('\n')}\n`;
|
|
195
|
+
}
|
|
191
196
|
return {
|
|
192
197
|
exitCode: result.remaining.length > 0 ? 1 : 0,
|
|
193
|
-
output
|
|
198
|
+
output,
|
|
194
199
|
};
|
|
195
200
|
}
|
|
196
201
|
if (fixMethod === 'override') {
|
|
197
|
-
const
|
|
198
|
-
if (Object.values(
|
|
202
|
+
const { vulnOverrides, addedAgeExcludes } = await fix(auditReport, opts);
|
|
203
|
+
if (Object.values(vulnOverrides).length === 0) {
|
|
199
204
|
return {
|
|
200
205
|
exitCode: 0,
|
|
201
206
|
output: 'No fixes were made',
|
|
202
207
|
};
|
|
203
208
|
}
|
|
204
|
-
|
|
205
|
-
exitCode: 0,
|
|
206
|
-
output: `${Object.values(newOverrides).length} overrides were added to package.json to fix vulnerabilities.
|
|
209
|
+
let output = `${Object.values(vulnOverrides).length} overrides were added to pnpm-workspace.yaml to fix vulnerabilities.
|
|
207
210
|
Run "pnpm install" to apply the fixes.
|
|
208
211
|
|
|
209
212
|
The added overrides:
|
|
210
|
-
${JSON.stringify(
|
|
213
|
+
${JSON.stringify(vulnOverrides, null, 2)}`;
|
|
214
|
+
if (addedAgeExcludes.length > 0) {
|
|
215
|
+
output += `\n\n${addedAgeExcludes.length} entries were added to minimumReleaseAgeExclude to allow installing the patched versions:\n${addedAgeExcludes.join('\n')}`;
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
exitCode: 0,
|
|
219
|
+
output,
|
|
211
220
|
};
|
|
212
221
|
}
|
|
213
222
|
if (opts.ignore !== undefined || opts.ignoreUnfixable) {
|
package/lib/audit/fix.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
import type { AuditReport } from '@pnpm/deps.compliance.audit';
|
|
1
|
+
import type { AuditAdvisory, AuditReport } from '@pnpm/deps.compliance.audit';
|
|
2
2
|
import type { AuditOptions } from './audit.js';
|
|
3
|
-
export
|
|
3
|
+
export interface FixResult {
|
|
4
|
+
vulnOverrides: Record<string, string>;
|
|
5
|
+
addedAgeExcludes: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function fix(auditReport: AuditReport, opts: AuditOptions): Promise<FixResult>;
|
|
8
|
+
export declare function createMinimumReleaseAgeExcludes(advisories: AuditAdvisory[]): string[];
|
package/lib/audit/fix.js
CHANGED
|
@@ -1,26 +1,46 @@
|
|
|
1
1
|
import { writeSettings } from '@pnpm/config.writer';
|
|
2
2
|
import { difference } from 'ramda';
|
|
3
|
+
import semver from 'semver';
|
|
3
4
|
export async function fix(auditReport, opts) {
|
|
4
|
-
const
|
|
5
|
+
const fixableAdvisories = getFixableAdvisories(Object.values(auditReport.advisories), opts.auditConfig?.ignoreCves);
|
|
6
|
+
const vulnOverrides = createOverrides(fixableAdvisories);
|
|
5
7
|
if (Object.values(vulnOverrides).length === 0)
|
|
6
|
-
return vulnOverrides;
|
|
8
|
+
return { vulnOverrides, addedAgeExcludes: [] };
|
|
9
|
+
const addedAgeExcludes = opts.minimumReleaseAge ? createMinimumReleaseAgeExcludes(fixableAdvisories) : [];
|
|
7
10
|
await writeSettings({
|
|
8
11
|
updatedOverrides: vulnOverrides,
|
|
12
|
+
addedMinimumReleaseAgeExcludes: addedAgeExcludes.length > 0 ? addedAgeExcludes : undefined,
|
|
9
13
|
rootProjectManifest: opts.rootProjectManifest,
|
|
10
14
|
rootProjectManifestDir: opts.rootProjectManifestDir,
|
|
11
15
|
workspaceDir: opts.workspaceDir ?? opts.rootProjectManifestDir,
|
|
12
16
|
});
|
|
13
|
-
return vulnOverrides;
|
|
17
|
+
return { vulnOverrides, addedAgeExcludes };
|
|
14
18
|
}
|
|
15
|
-
function
|
|
19
|
+
function getFixableAdvisories(advisories, ignoreCves) {
|
|
16
20
|
if (ignoreCves) {
|
|
17
21
|
advisories = advisories.filter(({ cves }) => difference(cves, ignoreCves).length > 0);
|
|
18
22
|
}
|
|
19
|
-
return
|
|
20
|
-
.filter(({ vulnerable_versions: vulnerableVersions, patched_versions: patchedVersions }) => vulnerableVersions !== '>=0.0.0' && patchedVersions !== '<0.0.0')
|
|
21
|
-
|
|
23
|
+
return advisories
|
|
24
|
+
.filter(({ vulnerable_versions: vulnerableVersions, patched_versions: patchedVersions }) => vulnerableVersions !== '>=0.0.0' && patchedVersions !== '<0.0.0');
|
|
25
|
+
}
|
|
26
|
+
function createOverrides(advisories) {
|
|
27
|
+
return Object.fromEntries(advisories.map((advisory) => [
|
|
22
28
|
`${advisory.module_name}@${advisory.vulnerable_versions}`,
|
|
23
29
|
advisory.patched_versions,
|
|
24
30
|
]));
|
|
25
31
|
}
|
|
32
|
+
export function createMinimumReleaseAgeExcludes(advisories) {
|
|
33
|
+
const excludes = new Set();
|
|
34
|
+
for (const advisory of advisories) {
|
|
35
|
+
if (advisory.patched_versions === '<0.0.0')
|
|
36
|
+
continue;
|
|
37
|
+
if (advisory.vulnerable_versions === '>=0.0.0' || advisory.vulnerable_versions === '*')
|
|
38
|
+
continue;
|
|
39
|
+
const minVersion = semver.minVersion(advisory.patched_versions);
|
|
40
|
+
if (minVersion) {
|
|
41
|
+
excludes.add(`${advisory.module_name}@${minVersion.version}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return Array.from(excludes);
|
|
45
|
+
}
|
|
26
46
|
//# sourceMappingURL=fix.js.map
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { writeSettings } from '@pnpm/config.writer';
|
|
1
2
|
import { WANTED_LOCKFILE } from '@pnpm/constants';
|
|
2
3
|
import { PnpmError } from '@pnpm/error';
|
|
3
4
|
import { update } from '@pnpm/installing.commands';
|
|
4
5
|
import { readWantedLockfile } from '@pnpm/lockfile.fs';
|
|
5
6
|
import semver from 'semver';
|
|
7
|
+
import { createMinimumReleaseAgeExcludes } from './fix.js';
|
|
6
8
|
import { lockfileToPackages } from './lockfileToPackages.js';
|
|
7
9
|
export async function fixWithUpdate(auditReport, opts) {
|
|
8
10
|
const vulnerabilitiesByPackage = new Map();
|
|
@@ -58,8 +60,22 @@ export async function fixWithUpdate(auditReport, opts) {
|
|
|
58
60
|
return allVulnerabilities;
|
|
59
61
|
},
|
|
60
62
|
};
|
|
63
|
+
// Add minimum patched versions to minimumReleaseAgeExclude so the resolver
|
|
64
|
+
// can install them even when minimumReleaseAge would otherwise block them.
|
|
65
|
+
const addedAgeExcludes = opts.minimumReleaseAge ? createMinimumReleaseAgeExcludes(Object.values(auditReport.advisories)) : [];
|
|
66
|
+
const updateOpts = { ...opts };
|
|
67
|
+
if (addedAgeExcludes.length > 0) {
|
|
68
|
+
const existing = updateOpts.minimumReleaseAgeExclude ?? [];
|
|
69
|
+
updateOpts.minimumReleaseAgeExclude = [...existing, ...addedAgeExcludes];
|
|
70
|
+
await writeSettings({
|
|
71
|
+
addedMinimumReleaseAgeExcludes: addedAgeExcludes,
|
|
72
|
+
rootProjectManifest: opts.rootProjectManifest,
|
|
73
|
+
rootProjectManifestDir: opts.rootProjectManifestDir,
|
|
74
|
+
workspaceDir: opts.workspaceDir ?? opts.rootProjectManifestDir,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
61
77
|
await update.handler({
|
|
62
|
-
...
|
|
78
|
+
...updateOpts,
|
|
63
79
|
packageVulnerabilityAudit,
|
|
64
80
|
}, []);
|
|
65
81
|
const lockfileDir = opts.lockfileDir ?? opts.dir;
|
|
@@ -105,6 +121,6 @@ export async function fixWithUpdate(auditReport, opts) {
|
|
|
105
121
|
fixed.push(...unfixableIds);
|
|
106
122
|
}
|
|
107
123
|
}
|
|
108
|
-
return { fixed, remaining };
|
|
124
|
+
return { fixed, remaining, addedAgeExcludes };
|
|
109
125
|
}
|
|
110
126
|
//# sourceMappingURL=fixWithUpdate.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { Config } from '@pnpm/config.reader';
|
|
1
|
+
import type { Config, ConfigContext } from '@pnpm/config.reader';
|
|
2
2
|
import type { LicensesCommandResult } from './LicensesCommandResult.js';
|
|
3
3
|
export type LicensesCommandOptions = {
|
|
4
4
|
compatible?: boolean;
|
|
5
5
|
long?: boolean;
|
|
6
6
|
recursive?: boolean;
|
|
7
7
|
json?: boolean;
|
|
8
|
-
} & Pick<Config, 'dev' | 'dir' | 'lockfileDir' | 'registries' | 'optional' | 'production' | 'storeDir' | 'virtualStoreDir' | 'modulesDir' | 'pnpmHomeDir' | '
|
|
8
|
+
} & Pick<Config, 'dev' | 'dir' | 'lockfileDir' | 'registries' | 'optional' | 'production' | 'storeDir' | 'virtualStoreDir' | 'modulesDir' | 'pnpmHomeDir' | 'supportedArchitectures' | 'virtualStoreDirMaxLength'> & Pick<ConfigContext, 'selectedProjectsGraph' | 'rootProjectManifest' | 'rootProjectManifestDir'> & Partial<Pick<Config, 'userConfig'>>;
|
|
9
9
|
export declare function licensesList(opts: LicensesCommandOptions): Promise<LicensesCommandResult>;
|
package/lib/sbom/sbom.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { type Config } from '@pnpm/config.reader';
|
|
1
|
+
import { type Config, type ConfigContext } from '@pnpm/config.reader';
|
|
2
2
|
export type SbomCommandOptions = {
|
|
3
3
|
sbomFormat?: string;
|
|
4
4
|
sbomType?: string;
|
|
5
5
|
lockfileOnly?: boolean;
|
|
6
6
|
sbomAuthors?: string;
|
|
7
7
|
sbomSupplier?: string;
|
|
8
|
-
} & Pick<Config, 'dev' | 'dir' | 'lockfileDir' | 'registries' | 'optional' | 'production' | 'storeDir' | 'virtualStoreDir' | 'modulesDir' | 'pnpmHomeDir' | '
|
|
8
|
+
} & Pick<Config, 'dev' | 'dir' | 'lockfileDir' | 'registries' | 'optional' | 'production' | 'storeDir' | 'virtualStoreDir' | 'modulesDir' | 'pnpmHomeDir' | 'virtualStoreDirMaxLength'> & Pick<ConfigContext, 'selectedProjectsGraph' | 'rootProjectManifest' | 'rootProjectManifestDir'> & Partial<Pick<Config, 'userConfig'>>;
|
|
9
9
|
export declare function rcOptionsTypes(): Record<string, unknown>;
|
|
10
10
|
export declare const cliOptionsTypes: () => Record<string, unknown>;
|
|
11
11
|
export declare const shorthands: Record<string, string>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/deps.compliance.commands",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1100.0.0",
|
|
4
4
|
"description": "pnpm commands for audit, licenses, and sbom",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -33,41 +33,43 @@
|
|
|
33
33
|
"ramda": "npm:@pnpm/ramda@0.28.1",
|
|
34
34
|
"render-help": "^2.0.0",
|
|
35
35
|
"semver": "^7.7.2",
|
|
36
|
-
"@pnpm/cli.command": "
|
|
37
|
-
"@pnpm/cli.common-cli-options-help": "
|
|
38
|
-
"@pnpm/cli.
|
|
39
|
-
"@pnpm/config.
|
|
40
|
-
"@pnpm/
|
|
41
|
-
"@pnpm/
|
|
42
|
-
"@pnpm/deps.compliance.
|
|
43
|
-
"@pnpm/
|
|
44
|
-
"@pnpm/deps.compliance.sbom": "
|
|
45
|
-
"@pnpm/error": "
|
|
46
|
-
"@pnpm/installing.commands": "
|
|
47
|
-
"@pnpm/lockfile.fs": "
|
|
48
|
-
"@pnpm/
|
|
49
|
-
"@pnpm/lockfile.utils": "
|
|
50
|
-
"@pnpm/lockfile.
|
|
51
|
-
"@pnpm/
|
|
52
|
-
"@pnpm/
|
|
53
|
-
"@pnpm/
|
|
54
|
-
"@pnpm/
|
|
55
|
-
"@pnpm/workspace.project-manifest-reader": "
|
|
36
|
+
"@pnpm/cli.command": "1100.0.0",
|
|
37
|
+
"@pnpm/cli.common-cli-options-help": "1100.0.0",
|
|
38
|
+
"@pnpm/cli.meta": "1100.0.0",
|
|
39
|
+
"@pnpm/config.writer": "1100.0.0",
|
|
40
|
+
"@pnpm/constants": "1100.0.0",
|
|
41
|
+
"@pnpm/deps.compliance.audit": "1100.0.0",
|
|
42
|
+
"@pnpm/deps.compliance.license-scanner": "1100.0.0",
|
|
43
|
+
"@pnpm/config.reader": "1100.0.0",
|
|
44
|
+
"@pnpm/deps.compliance.sbom": "1100.0.0",
|
|
45
|
+
"@pnpm/error": "1100.0.0",
|
|
46
|
+
"@pnpm/installing.commands": "1100.0.0",
|
|
47
|
+
"@pnpm/lockfile.fs": "1100.0.0",
|
|
48
|
+
"@pnpm/lockfile.types": "1100.0.0",
|
|
49
|
+
"@pnpm/lockfile.utils": "1100.0.0",
|
|
50
|
+
"@pnpm/lockfile.walker": "1100.0.0",
|
|
51
|
+
"@pnpm/cli.utils": "1100.0.0",
|
|
52
|
+
"@pnpm/store.path": "1100.0.0",
|
|
53
|
+
"@pnpm/network.auth-header": "1100.0.0",
|
|
54
|
+
"@pnpm/types": "1100.0.0",
|
|
55
|
+
"@pnpm/workspace.project-manifest-reader": "1100.0.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@pnpm/registry-mock": "
|
|
59
|
-
"@types/ramda": "0.
|
|
58
|
+
"@pnpm/registry-mock": "6.0.0",
|
|
59
|
+
"@types/ramda": "0.31.1",
|
|
60
60
|
"@types/semver": "7.7.1",
|
|
61
61
|
"@types/zkochan__table": "npm:@types/table@6.0.0",
|
|
62
62
|
"load-json-file": "^7.0.1",
|
|
63
63
|
"nock": "13.3.4",
|
|
64
64
|
"read-yaml-file": "^3.0.0",
|
|
65
65
|
"tempy": "3.0.0",
|
|
66
|
-
"@pnpm/deps.compliance.commands": "
|
|
67
|
-
"@pnpm/
|
|
68
|
-
"@pnpm/
|
|
69
|
-
"@pnpm/
|
|
70
|
-
"@pnpm/
|
|
66
|
+
"@pnpm/deps.compliance.commands": "1100.0.0",
|
|
67
|
+
"@pnpm/prepare": "1100.0.0",
|
|
68
|
+
"@pnpm/pkg-manifest.reader": "1100.0.0",
|
|
69
|
+
"@pnpm/testing.command-defaults": "1100.0.0",
|
|
70
|
+
"@pnpm/testing.mock-agent": "1100.0.0",
|
|
71
|
+
"@pnpm/workspace.projects-filter": "1100.0.0",
|
|
72
|
+
"@pnpm/test-fixtures": "1100.0.0"
|
|
71
73
|
},
|
|
72
74
|
"engines": {
|
|
73
75
|
"node": ">=22.13"
|
|
@@ -77,9 +79,9 @@
|
|
|
77
79
|
},
|
|
78
80
|
"scripts": {
|
|
79
81
|
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
"
|
|
82
|
+
"test": "pn compile && pn .test",
|
|
83
|
+
"compile": "tsgo --build && pn lint --fix",
|
|
84
|
+
"update-responses": "node test/audit/utils/responses/update.ts",
|
|
85
|
+
".test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
|
|
84
86
|
}
|
|
85
87
|
}
|