pr-checkmate 3.2.0 → 3.2.2
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/cjs/core/checks/dependencies/grype-scan.d.ts +8 -0
- package/dist/cjs/core/checks/dependencies/grype-scan.js +18 -4
- package/dist/cjs/interfaces/index.d.ts +14 -0
- package/dist/esm/core/checks/dependencies/grype-scan.d.ts +8 -0
- package/dist/esm/core/checks/dependencies/grype-scan.js +18 -5
- package/dist/esm/interfaces/index.d.ts +14 -0
- package/package.json +1 -1
- package/pr-checkmate.schema.json +20 -0
- package/src/config/pr-checkmate.schema.json +20 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GrypeScanEnvOverrides, PRCheckMateConfig } from '../../../interfaces/index.js';
|
|
1
2
|
import { Check } from '../../types.js';
|
|
2
3
|
/**
|
|
3
4
|
* Dependency vulnerability scan via Anchore's `grype`. Non-blocking and ON by
|
|
@@ -19,4 +20,11 @@ import { Check } from '../../types.js';
|
|
|
19
20
|
* installed `node_modules` is minutes of work whose every finding this check then
|
|
20
21
|
* throws away as third-party.
|
|
21
22
|
*/
|
|
23
|
+
/**
|
|
24
|
+
* The effective grypeScan settings for this run: the top-level values, with the
|
|
25
|
+
* `ci` or `local` block layered on top depending on where we are running. Only
|
|
26
|
+
* keys actually set in the block win, so `local: { enabled: false }` leaves the
|
|
27
|
+
* severity and ignore list alone.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveGrypeScan(config: PRCheckMateConfig['grypeScan'], env?: NodeJS.ProcessEnv): GrypeScanEnvOverrides;
|
|
22
30
|
export declare const grypeScanCheck: Check;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.grypeScanCheck = void 0;
|
|
4
|
+
exports.resolveGrypeScan = resolveGrypeScan;
|
|
4
5
|
const execa_js_1 = require("../../../utils/execa.js");
|
|
5
6
|
const index_js_1 = require("../../../utils/index.js");
|
|
6
7
|
const types_js_1 = require("../../types.js");
|
|
@@ -43,17 +44,30 @@ function severityRank(severity) {
|
|
|
43
44
|
* installed `node_modules` is minutes of work whose every finding this check then
|
|
44
45
|
* throws away as third-party.
|
|
45
46
|
*/
|
|
47
|
+
/**
|
|
48
|
+
* The effective grypeScan settings for this run: the top-level values, with the
|
|
49
|
+
* `ci` or `local` block layered on top depending on where we are running. Only
|
|
50
|
+
* keys actually set in the block win, so `local: { enabled: false }` leaves the
|
|
51
|
+
* severity and ignore list alone.
|
|
52
|
+
*/
|
|
53
|
+
function resolveGrypeScan(config, env = process.env) {
|
|
54
|
+
const { ci, local, ...base } = config ?? {};
|
|
55
|
+
const overrides = ((0, index_js_1.isCiEnvironment)(env) ? ci : local) ?? {};
|
|
56
|
+
const defined = Object.fromEntries(Object.entries(overrides).filter(([, value]) => value !== undefined));
|
|
57
|
+
return { ...base, ...defined };
|
|
58
|
+
}
|
|
46
59
|
exports.grypeScanCheck = {
|
|
47
60
|
name: 'Grype Scan',
|
|
48
61
|
phase: 'informational',
|
|
49
62
|
weight: 'heavy',
|
|
50
63
|
applies(ctx) {
|
|
51
|
-
return ctx.config.grypeScan
|
|
64
|
+
return resolveGrypeScan(ctx.config.grypeScan).enabled !== false;
|
|
52
65
|
},
|
|
53
66
|
async run(ctx) {
|
|
54
|
-
const
|
|
67
|
+
const settings = resolveGrypeScan(ctx.config.grypeScan);
|
|
68
|
+
const minSeverity = (settings.minSeverity ?? 'medium').toLowerCase();
|
|
55
69
|
const minRank = severityRank(minSeverity);
|
|
56
|
-
const ignore = (
|
|
70
|
+
const ignore = (settings.ignore ?? []).map(s => s.toLowerCase());
|
|
57
71
|
// Never walk `ignoreDirs` — the same contract every other check honours, and
|
|
58
72
|
// here it is the difference between a usable check and an unusable one. A bare
|
|
59
73
|
// `grype dir:.` catalogs every file under `node_modules`, which on this repo took
|
|
@@ -61,7 +75,7 @@ exports.grypeScanCheck = {
|
|
|
61
75
|
// findings: grype resolves package versions from the lockfile, and installed
|
|
62
76
|
// third-party code is not something the client could fix anyway (see below).
|
|
63
77
|
const excludes = (ctx.config.ignoreDirs ?? []).flatMap(dir => ['--exclude', `**/${dir}/**`]);
|
|
64
|
-
const timeout =
|
|
78
|
+
const timeout = settings.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
65
79
|
const result = await (0, execa_js_1.execa)('grype', ['dir:.', '-o', 'json', '-q', ...excludes], {
|
|
66
80
|
cwd: ctx.cwd,
|
|
67
81
|
reject: false,
|
|
@@ -369,6 +369,13 @@ export interface PRCheckMateConfig {
|
|
|
369
369
|
* can never stall a commit.
|
|
370
370
|
*/
|
|
371
371
|
timeoutMs?: number;
|
|
372
|
+
/**
|
|
373
|
+
* Overrides applied only on a CI build (see `isCiEnvironment`). Any key set here wins
|
|
374
|
+
* over the top-level value, so CI can keep the scan while local runs turn it off.
|
|
375
|
+
*/
|
|
376
|
+
ci?: GrypeScanEnvOverrides;
|
|
377
|
+
/** Same as `ci`, applied only outside CI (a developer's machine, `be-commit`, hooks). */
|
|
378
|
+
local?: GrypeScanEnvOverrides;
|
|
372
379
|
};
|
|
373
380
|
bannedImports?: Array<{
|
|
374
381
|
name: string;
|
|
@@ -430,3 +437,10 @@ export interface PRCheckMateConfig {
|
|
|
430
437
|
}
|
|
431
438
|
export type { CheckStatus, CheckResult } from '../utils/result-collector.js';
|
|
432
439
|
export type { Language } from '../utils/detect-language.js';
|
|
440
|
+
/** Per-environment overrides for `grypeScan`: the subset of its settings that may differ by environment. */
|
|
441
|
+
export interface GrypeScanEnvOverrides {
|
|
442
|
+
enabled?: boolean;
|
|
443
|
+
minSeverity?: 'negligible' | 'low' | 'medium' | 'high' | 'critical';
|
|
444
|
+
ignore?: string[];
|
|
445
|
+
timeoutMs?: number;
|
|
446
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GrypeScanEnvOverrides, PRCheckMateConfig } from '../../../interfaces/index.js';
|
|
1
2
|
import { Check } from '../../types.js';
|
|
2
3
|
/**
|
|
3
4
|
* Dependency vulnerability scan via Anchore's `grype`. Non-blocking and ON by
|
|
@@ -19,4 +20,11 @@ import { Check } from '../../types.js';
|
|
|
19
20
|
* installed `node_modules` is minutes of work whose every finding this check then
|
|
20
21
|
* throws away as third-party.
|
|
21
22
|
*/
|
|
23
|
+
/**
|
|
24
|
+
* The effective grypeScan settings for this run: the top-level values, with the
|
|
25
|
+
* `ci` or `local` block layered on top depending on where we are running. Only
|
|
26
|
+
* keys actually set in the block win, so `local: { enabled: false }` leaves the
|
|
27
|
+
* severity and ignore list alone.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveGrypeScan(config: PRCheckMateConfig['grypeScan'], env?: NodeJS.ProcessEnv): GrypeScanEnvOverrides;
|
|
22
30
|
export declare const grypeScanCheck: Check;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execa } from '../../../utils/execa.js';
|
|
2
|
-
import { collectDirectDeps, logger, normalizeName } from '../../../utils/index.js';
|
|
2
|
+
import { collectDirectDeps, isCiEnvironment, logger, normalizeName, } from '../../../utils/index.js';
|
|
3
3
|
import { pass, skip, warn } from '../../types.js';
|
|
4
4
|
import { notInstalled } from '../tool-install.js';
|
|
5
5
|
const SEVERITY_ORDER = ['negligible', 'low', 'medium', 'high', 'critical'];
|
|
@@ -40,17 +40,30 @@ function severityRank(severity) {
|
|
|
40
40
|
* installed `node_modules` is minutes of work whose every finding this check then
|
|
41
41
|
* throws away as third-party.
|
|
42
42
|
*/
|
|
43
|
+
/**
|
|
44
|
+
* The effective grypeScan settings for this run: the top-level values, with the
|
|
45
|
+
* `ci` or `local` block layered on top depending on where we are running. Only
|
|
46
|
+
* keys actually set in the block win, so `local: { enabled: false }` leaves the
|
|
47
|
+
* severity and ignore list alone.
|
|
48
|
+
*/
|
|
49
|
+
export function resolveGrypeScan(config, env = process.env) {
|
|
50
|
+
const { ci, local, ...base } = config ?? {};
|
|
51
|
+
const overrides = (isCiEnvironment(env) ? ci : local) ?? {};
|
|
52
|
+
const defined = Object.fromEntries(Object.entries(overrides).filter(([, value]) => value !== undefined));
|
|
53
|
+
return { ...base, ...defined };
|
|
54
|
+
}
|
|
43
55
|
export const grypeScanCheck = {
|
|
44
56
|
name: 'Grype Scan',
|
|
45
57
|
phase: 'informational',
|
|
46
58
|
weight: 'heavy',
|
|
47
59
|
applies(ctx) {
|
|
48
|
-
return ctx.config.grypeScan
|
|
60
|
+
return resolveGrypeScan(ctx.config.grypeScan).enabled !== false;
|
|
49
61
|
},
|
|
50
62
|
async run(ctx) {
|
|
51
|
-
const
|
|
63
|
+
const settings = resolveGrypeScan(ctx.config.grypeScan);
|
|
64
|
+
const minSeverity = (settings.minSeverity ?? 'medium').toLowerCase();
|
|
52
65
|
const minRank = severityRank(minSeverity);
|
|
53
|
-
const ignore = (
|
|
66
|
+
const ignore = (settings.ignore ?? []).map(s => s.toLowerCase());
|
|
54
67
|
// Never walk `ignoreDirs` — the same contract every other check honours, and
|
|
55
68
|
// here it is the difference between a usable check and an unusable one. A bare
|
|
56
69
|
// `grype dir:.` catalogs every file under `node_modules`, which on this repo took
|
|
@@ -58,7 +71,7 @@ export const grypeScanCheck = {
|
|
|
58
71
|
// findings: grype resolves package versions from the lockfile, and installed
|
|
59
72
|
// third-party code is not something the client could fix anyway (see below).
|
|
60
73
|
const excludes = (ctx.config.ignoreDirs ?? []).flatMap(dir => ['--exclude', `**/${dir}/**`]);
|
|
61
|
-
const timeout =
|
|
74
|
+
const timeout = settings.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
62
75
|
const result = await execa('grype', ['dir:.', '-o', 'json', '-q', ...excludes], {
|
|
63
76
|
cwd: ctx.cwd,
|
|
64
77
|
reject: false,
|
|
@@ -369,6 +369,13 @@ export interface PRCheckMateConfig {
|
|
|
369
369
|
* can never stall a commit.
|
|
370
370
|
*/
|
|
371
371
|
timeoutMs?: number;
|
|
372
|
+
/**
|
|
373
|
+
* Overrides applied only on a CI build (see `isCiEnvironment`). Any key set here wins
|
|
374
|
+
* over the top-level value, so CI can keep the scan while local runs turn it off.
|
|
375
|
+
*/
|
|
376
|
+
ci?: GrypeScanEnvOverrides;
|
|
377
|
+
/** Same as `ci`, applied only outside CI (a developer's machine, `be-commit`, hooks). */
|
|
378
|
+
local?: GrypeScanEnvOverrides;
|
|
372
379
|
};
|
|
373
380
|
bannedImports?: Array<{
|
|
374
381
|
name: string;
|
|
@@ -430,3 +437,10 @@ export interface PRCheckMateConfig {
|
|
|
430
437
|
}
|
|
431
438
|
export type { CheckStatus, CheckResult } from '../utils/result-collector.js';
|
|
432
439
|
export type { Language } from '../utils/detect-language.js';
|
|
440
|
+
/** Per-environment overrides for `grypeScan`: the subset of its settings that may differ by environment. */
|
|
441
|
+
export interface GrypeScanEnvOverrides {
|
|
442
|
+
enabled?: boolean;
|
|
443
|
+
minSeverity?: 'negligible' | 'low' | 'medium' | 'high' | 'critical';
|
|
444
|
+
ignore?: string[];
|
|
445
|
+
timeoutMs?: number;
|
|
446
|
+
}
|
package/package.json
CHANGED
package/pr-checkmate.schema.json
CHANGED
|
@@ -221,6 +221,14 @@
|
|
|
221
221
|
"timeoutMs": {
|
|
222
222
|
"type": "number",
|
|
223
223
|
"default": 120000
|
|
224
|
+
},
|
|
225
|
+
"ci": {
|
|
226
|
+
"$ref": "#/$defs/grypeScanEnvOverrides",
|
|
227
|
+
"description": "Overrides applied only on a CI build."
|
|
228
|
+
},
|
|
229
|
+
"local": {
|
|
230
|
+
"$ref": "#/$defs/grypeScanEnvOverrides",
|
|
231
|
+
"description": "Overrides applied only outside CI (developer machine, local commits)."
|
|
224
232
|
}
|
|
225
233
|
},
|
|
226
234
|
"description": "Direct-dependency vulnerability scan via grype."
|
|
@@ -1067,6 +1075,18 @@
|
|
|
1067
1075
|
}
|
|
1068
1076
|
},
|
|
1069
1077
|
"$defs": {
|
|
1078
|
+
"grypeScanEnvOverrides": {
|
|
1079
|
+
"type": "object",
|
|
1080
|
+
"properties": {
|
|
1081
|
+
"enabled": { "type": "boolean" },
|
|
1082
|
+
"minSeverity": {
|
|
1083
|
+
"type": "string",
|
|
1084
|
+
"enum": ["negligible", "low", "medium", "high", "critical"]
|
|
1085
|
+
},
|
|
1086
|
+
"ignore": { "type": "array", "items": { "type": "string" } },
|
|
1087
|
+
"timeoutMs": { "type": "number" }
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1070
1090
|
"toggle": {
|
|
1071
1091
|
"type": "object",
|
|
1072
1092
|
"properties": {
|
|
@@ -221,6 +221,14 @@
|
|
|
221
221
|
"timeoutMs": {
|
|
222
222
|
"type": "number",
|
|
223
223
|
"default": 120000
|
|
224
|
+
},
|
|
225
|
+
"ci": {
|
|
226
|
+
"$ref": "#/$defs/grypeScanEnvOverrides",
|
|
227
|
+
"description": "Overrides applied only on a CI build."
|
|
228
|
+
},
|
|
229
|
+
"local": {
|
|
230
|
+
"$ref": "#/$defs/grypeScanEnvOverrides",
|
|
231
|
+
"description": "Overrides applied only outside CI (developer machine, local commits)."
|
|
224
232
|
}
|
|
225
233
|
},
|
|
226
234
|
"description": "Direct-dependency vulnerability scan via grype."
|
|
@@ -1067,6 +1075,18 @@
|
|
|
1067
1075
|
}
|
|
1068
1076
|
},
|
|
1069
1077
|
"$defs": {
|
|
1078
|
+
"grypeScanEnvOverrides": {
|
|
1079
|
+
"type": "object",
|
|
1080
|
+
"properties": {
|
|
1081
|
+
"enabled": { "type": "boolean" },
|
|
1082
|
+
"minSeverity": {
|
|
1083
|
+
"type": "string",
|
|
1084
|
+
"enum": ["negligible", "low", "medium", "high", "critical"]
|
|
1085
|
+
},
|
|
1086
|
+
"ignore": { "type": "array", "items": { "type": "string" } },
|
|
1087
|
+
"timeoutMs": { "type": "number" }
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1070
1090
|
"toggle": {
|
|
1071
1091
|
"type": "object",
|
|
1072
1092
|
"properties": {
|