v11y-check 0.19.6 → 0.19.8
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/.meta/changelog.json +44 -0
- package/.readyup/kits/default.js +7 -7
- package/.readyup/manifest.json +6 -6
- package/CHANGELOG.md +17 -0
- package/dist/esm/bin/route.js +26 -26
- package/dist/esm/cli.js +41 -41
- package/dist/esm/config.js +7 -7
- package/dist/esm/format-actions.js +11 -11
- package/dist/esm/format-check.d.ts +4 -4
- package/dist/esm/format-check.js +32 -32
- package/dist/esm/format-summary.js +9 -9
- package/dist/esm/format-time.js +28 -28
- package/dist/esm/format-verbose.js +44 -41
- package/dist/esm/generate.js +7 -7
- package/dist/esm/init/initCommand.d.ts +3 -3
- package/dist/esm/init/initCommand.js +5 -5
- package/dist/esm/init/scaffold.d.ts +8 -8
- package/dist/esm/init/scaffold.js +12 -9
- package/dist/esm/init/updateTemplatesCommand.d.ts +2 -2
- package/dist/esm/init/updateTemplatesCommand.js +4 -4
- package/dist/esm/run-audit.d.ts +4 -4
- package/dist/esm/run-audit.js +33 -33
- package/dist/esm/sync.js +16 -16
- package/dist/esm/types.d.ts +1 -1
- package/package.json +7 -7
package/.meta/changelog.json
CHANGED
|
@@ -1,4 +1,48 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.19.8",
|
|
4
|
+
"date": "2026-10-28",
|
|
5
|
+
"sections": [
|
|
6
|
+
{
|
|
7
|
+
"title": "🧪 Tests",
|
|
8
|
+
"audience": "dev",
|
|
9
|
+
"items": [
|
|
10
|
+
{
|
|
11
|
+
"description": "Renames the values and helpers declared in v11y-check's tests and `src/test-utils` to follow the naming conventions, which require a value's name to end with its kind, a helper's name to lead with a verb, and abbreviations to be spelled out. (#1131)",
|
|
12
|
+
"hash": "bd0c26180b5d692ee2845eeea4a92a357027d7de",
|
|
13
|
+
"entry": 1
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"description": "Replaces the `setupLoadConfig` and `setupTempDir` helpers, repeated in the `cli.audit`, `cli.check`, and `cli.sync` tests, with `buildLoadConfigResult` and `callWithFakeTempDir` in `src/test-utils/cli-fixtures.ts`. (#1131)",
|
|
17
|
+
"hash": "bd0c26180b5d692ee2845eeea4a92a357027d7de",
|
|
18
|
+
"entry": 2
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"version": "0.19.7",
|
|
26
|
+
"date": "2026-10-27",
|
|
27
|
+
"sections": [
|
|
28
|
+
{
|
|
29
|
+
"title": "♻️ Refactoring",
|
|
30
|
+
"audience": "dev",
|
|
31
|
+
"items": [
|
|
32
|
+
{
|
|
33
|
+
"description": "Apply the naming conventions to nmr-core's identifiers (#1125)",
|
|
34
|
+
"body": "Renames the identifiers in nmr-core to follow the naming conventions, including the exported option keys of `updateManagedFile` and `writeFileWithCheck`, which change from `dryRun` and `overwrite` to `isDryRun` and `shouldOverwrite`, and the constant `GIT_OUTPUT_LIMIT`, which becomes `GIT_OUTPUT_LIMIT_BYTES`. Updates the call sites in nmr, release-kit, and v11y-check to the new names.",
|
|
35
|
+
"hash": "2cb60f628512ed6ec2273a219a7b6c71aa35b1bf"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"description": "Renames the identifiers in `v11y-check`'s source and its readyup kit to the naming conventions, including the exported `CommandOptions.json` (now `isJson`) and the kit check `noLegacyAuditCiDirectory` (now `hasNoLegacyAuditCiDirectory`), and leaves the CLI flags and the JSON output keys as they were. (#1127)",
|
|
39
|
+
"hash": "b306cefc52c6e2a4625b99aad62c71799e5e9fd5",
|
|
40
|
+
"entry": 1
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
},
|
|
2
46
|
{
|
|
3
47
|
"version": "0.19.6",
|
|
4
48
|
"date": "2026-10-24",
|
package/.readyup/kits/default.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @noformat -- @generated. Do not edit. Compiled by rdy. */
|
|
2
2
|
/* eslint-disable */
|
|
3
|
-
export const __readyupVersion = "0.
|
|
3
|
+
export const __readyupVersion = "0.44.0";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
// .readyup/kits/default.ts
|
|
@@ -40,7 +40,7 @@ var default_default = defineRdyKit({
|
|
|
40
40
|
name: "audit-ci configs are under .config/audit-ci/",
|
|
41
41
|
severity: "warn",
|
|
42
42
|
quiet: true,
|
|
43
|
-
check:
|
|
43
|
+
check: hasNoLegacyAuditCiDirectory,
|
|
44
44
|
fix: "Move audit-ci configs from .audit-ci/ to .config/audit-ci/ and update references"
|
|
45
45
|
},
|
|
46
46
|
// -- Audit workflow --
|
|
@@ -63,17 +63,17 @@ var default_default = defineRdyKit({
|
|
|
63
63
|
]
|
|
64
64
|
});
|
|
65
65
|
function getMinVersion() {
|
|
66
|
-
const
|
|
67
|
-
if (typeof
|
|
66
|
+
const pickedFields = { "version": "0.19.8" };
|
|
67
|
+
if (typeof pickedFields["version"] !== "string") {
|
|
68
68
|
throw new TypeError("v11y-check/package.json: 'version' must be a string");
|
|
69
69
|
}
|
|
70
|
-
return
|
|
70
|
+
return pickedFields["version"];
|
|
71
71
|
}
|
|
72
|
-
function
|
|
72
|
+
function hasNoLegacyAuditCiDirectory() {
|
|
73
73
|
return !existsSync(join(process.cwd(), ".audit-ci"));
|
|
74
74
|
}
|
|
75
75
|
export {
|
|
76
76
|
AUDIT_WORKFLOW_HASH,
|
|
77
77
|
default_default as default,
|
|
78
|
-
|
|
78
|
+
hasNoLegacyAuditCiDirectory
|
|
79
79
|
};
|
package/.readyup/manifest.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"checklist": "v11y-check",
|
|
8
8
|
"checks": [
|
|
9
9
|
"v11y-check in devDependencies",
|
|
10
|
-
"v11y-check >= 0.19.
|
|
10
|
+
"v11y-check >= 0.19.8",
|
|
11
11
|
"audit-ci configs are under .config/audit-ci/",
|
|
12
12
|
"audit.yaml workflow exists",
|
|
13
13
|
"audit.yaml matches template"
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"esbuildVersion": "0.28.2",
|
|
21
21
|
"inputs": [
|
|
22
22
|
{
|
|
23
|
-
"hash": "
|
|
23
|
+
"hash": "d19aa2e6",
|
|
24
24
|
"kind": "module",
|
|
25
25
|
"path": "kits/default.ts"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
"hash": "
|
|
28
|
+
"hash": "7f64b742",
|
|
29
29
|
"kind": "inline",
|
|
30
30
|
"path": "../package.json",
|
|
31
31
|
"paths": [
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
],
|
|
36
36
|
"name": "default",
|
|
37
37
|
"path": "kits/default.js",
|
|
38
|
-
"readyupVersion": "0.
|
|
38
|
+
"readyupVersion": "0.44.0",
|
|
39
39
|
"source": "kits/default.ts",
|
|
40
|
-
"sourceHash": "
|
|
41
|
-
"targetHash": "
|
|
40
|
+
"sourceHash": "d19aa2e6",
|
|
41
|
+
"targetHash": "cdd8ef79"
|
|
42
42
|
}
|
|
43
43
|
]
|
|
44
44
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.19.8 — 2026-10-28
|
|
6
|
+
|
|
7
|
+
### 🧪 Tests
|
|
8
|
+
|
|
9
|
+
- Renames the values and helpers declared in v11y-check's tests and `src/test-utils` to follow the naming conventions, which require a value's name to end with its kind, a helper's name to lead with a verb, and abbreviations to be spelled out. (#1131)
|
|
10
|
+
- Replaces the `setupLoadConfig` and `setupTempDir` helpers, repeated in the `cli.audit`, `cli.check`, and `cli.sync` tests, with `buildLoadConfigResult` and `callWithFakeTempDir` in `src/test-utils/cli-fixtures.ts`. (#1131)
|
|
11
|
+
|
|
12
|
+
## 0.19.7 — 2026-10-27
|
|
13
|
+
|
|
14
|
+
### ♻️ Refactoring
|
|
15
|
+
|
|
16
|
+
- Apply the naming conventions to nmr-core's identifiers (#1125)
|
|
17
|
+
|
|
18
|
+
Renames the identifiers in nmr-core to follow the naming conventions, including the exported option keys of `updateManagedFile` and `writeFileWithCheck`, which change from `dryRun` and `overwrite` to `isDryRun` and `shouldOverwrite`, and the constant `GIT_OUTPUT_LIMIT`, which becomes `GIT_OUTPUT_LIMIT_BYTES`. Updates the call sites in nmr, release-kit, and v11y-check to the new names.
|
|
19
|
+
|
|
20
|
+
- Renames the identifiers in `v11y-check`'s source and its readyup kit to the naming conventions, including the exported `CommandOptions.json` (now `isJson`) and the kit check `noLegacyAuditCiDirectory` (now `hasNoLegacyAuditCiDirectory`), and leaves the CLI flags and the JSON output keys as they were. (#1127)
|
|
21
|
+
|
|
5
22
|
## 0.19.6 — 2026-10-24
|
|
6
23
|
|
|
7
24
|
### 🧪 Tests
|
package/dist/esm/bin/route.js
CHANGED
|
@@ -80,36 +80,36 @@ Options:
|
|
|
80
80
|
}
|
|
81
81
|
function parseSharedFlags(flags, styles) {
|
|
82
82
|
const flagSchema = {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
configPath: { long: '--config', type: 'string' },
|
|
84
|
+
isDev: { long: '--dev', type: 'boolean' },
|
|
85
|
+
isJson: { long: '--json', type: 'boolean', short: '-j' },
|
|
86
|
+
isProd: { long: '--prod', type: 'boolean' },
|
|
87
87
|
verbose: { long: '--verbose', type: 'boolean', short: '-v' },
|
|
88
88
|
};
|
|
89
|
-
const { flags:
|
|
90
|
-
if (
|
|
89
|
+
const { flags: parsedFlags } = parseArgs(flags, flagSchema);
|
|
90
|
+
if (parsedFlags.isDev && parsedFlags.isProd) {
|
|
91
91
|
throw new Error('Cannot specify both --dev and --prod');
|
|
92
92
|
}
|
|
93
93
|
const scopes = [];
|
|
94
|
-
if (
|
|
94
|
+
if (parsedFlags.isDev)
|
|
95
95
|
scopes.push('dev');
|
|
96
|
-
if (
|
|
96
|
+
if (parsedFlags.isProd)
|
|
97
97
|
scopes.push('prod');
|
|
98
98
|
return {
|
|
99
|
-
configPath:
|
|
100
|
-
|
|
99
|
+
configPath: parsedFlags.configPath,
|
|
100
|
+
isJson: parsedFlags.isJson,
|
|
101
101
|
scopes,
|
|
102
102
|
styles,
|
|
103
|
-
verbose:
|
|
103
|
+
verbose: parsedFlags.verbose,
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
function findTypoMatch(input) {
|
|
107
107
|
if (input.length < MIN_PREFIX_LENGTH || input.startsWith('-')) {
|
|
108
108
|
return undefined;
|
|
109
109
|
}
|
|
110
|
-
for (const
|
|
111
|
-
if (
|
|
112
|
-
return
|
|
110
|
+
for (const subcommand of SUBCOMMANDS) {
|
|
111
|
+
if (subcommand !== input && subcommand.startsWith(input)) {
|
|
112
|
+
return subcommand;
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
return undefined;
|
|
@@ -159,9 +159,9 @@ export async function routeCommand(args) {
|
|
|
159
159
|
}
|
|
160
160
|
return handleSubcommand(args, styles, checkCommand);
|
|
161
161
|
}
|
|
162
|
-
async function handleSubcommand(flags, styles,
|
|
162
|
+
async function handleSubcommand(flags, styles, runSubcommand, showSubcommandHelp = showHelp) {
|
|
163
163
|
if (flags.some((f) => f === '--help' || f === '-h')) {
|
|
164
|
-
|
|
164
|
+
showSubcommandHelp();
|
|
165
165
|
return 0;
|
|
166
166
|
}
|
|
167
167
|
let options;
|
|
@@ -173,7 +173,7 @@ async function handleSubcommand(flags, styles, handler, helpFn = showHelp) {
|
|
|
173
173
|
return 1;
|
|
174
174
|
}
|
|
175
175
|
try {
|
|
176
|
-
return await
|
|
176
|
+
return await runSubcommand(options);
|
|
177
177
|
}
|
|
178
178
|
catch (error) {
|
|
179
179
|
reportError(describeError(error));
|
|
@@ -186,18 +186,18 @@ function handleInit(flags, styles) {
|
|
|
186
186
|
return 0;
|
|
187
187
|
}
|
|
188
188
|
const initFlagSchema = {
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
isDryRun: { long: '--dry-run', type: 'boolean', short: '-n' },
|
|
190
|
+
shouldForce: { long: '--force', type: 'boolean', short: '-f' },
|
|
191
191
|
};
|
|
192
|
-
let
|
|
192
|
+
let parsedArgs;
|
|
193
193
|
try {
|
|
194
|
-
|
|
194
|
+
parsedArgs = parseArgs(flags, initFlagSchema);
|
|
195
195
|
}
|
|
196
196
|
catch (error) {
|
|
197
197
|
reportError(describeError(error));
|
|
198
198
|
return 1;
|
|
199
199
|
}
|
|
200
|
-
return initCommand({
|
|
200
|
+
return initCommand({ isDryRun: parsedArgs.flags.isDryRun, shouldForce: parsedArgs.flags.shouldForce, styles });
|
|
201
201
|
}
|
|
202
202
|
function handleUpdateTemplates(flags, styles) {
|
|
203
203
|
if (flags.some((f) => f === '--help' || f === '-h')) {
|
|
@@ -205,15 +205,15 @@ function handleUpdateTemplates(flags, styles) {
|
|
|
205
205
|
return 0;
|
|
206
206
|
}
|
|
207
207
|
const updateTemplatesFlagSchema = {
|
|
208
|
-
|
|
208
|
+
isDryRun: { long: '--dry-run', type: 'boolean', short: '-n' },
|
|
209
209
|
};
|
|
210
|
-
let
|
|
210
|
+
let parsedArgs;
|
|
211
211
|
try {
|
|
212
|
-
|
|
212
|
+
parsedArgs = parseArgs(flags, updateTemplatesFlagSchema);
|
|
213
213
|
}
|
|
214
214
|
catch (error) {
|
|
215
215
|
reportError(describeError(error));
|
|
216
216
|
return 1;
|
|
217
217
|
}
|
|
218
|
-
return updateTemplatesCommand({
|
|
218
|
+
return updateTemplatesCommand({ isDryRun: parsedArgs.flags.isDryRun, styles });
|
|
219
219
|
}
|
package/dist/esm/cli.js
CHANGED
|
@@ -11,15 +11,15 @@ import { syncAllowlist } from "./sync.js";
|
|
|
11
11
|
import { withTempDir } from "./tmp.js";
|
|
12
12
|
import { AUDIT_SCOPES, isSeverityAtOrAbove, } from "./types.js";
|
|
13
13
|
export async function auditCommand(options) {
|
|
14
|
-
let
|
|
14
|
+
let loadedConfigResult;
|
|
15
15
|
try {
|
|
16
|
-
|
|
16
|
+
loadedConfigResult = await loadConfig(options.configPath);
|
|
17
17
|
}
|
|
18
18
|
catch (error) {
|
|
19
19
|
reportError(describeError(error));
|
|
20
20
|
return 1;
|
|
21
21
|
}
|
|
22
|
-
const { config } =
|
|
22
|
+
const { config } = loadedConfigResult;
|
|
23
23
|
const scopes = options.scopes.length > 0 ? options.scopes : [...AUDIT_SCOPES];
|
|
24
24
|
try {
|
|
25
25
|
return await withTempDir(async (tempDir) => {
|
|
@@ -27,21 +27,21 @@ export async function auditCommand(options) {
|
|
|
27
27
|
const allResults = [];
|
|
28
28
|
for (const scope of scopes) {
|
|
29
29
|
const configPath = await generateAuditCiConfig(config[scope], scope, tempDir);
|
|
30
|
-
const result = runAudit({ configPath,
|
|
30
|
+
const result = runAudit({ configPath, isJson: options.isJson });
|
|
31
31
|
for (const warning of result.warnings) {
|
|
32
32
|
process.stderr.write(`warning: ${warning}\n`);
|
|
33
33
|
}
|
|
34
34
|
if (result.staleEntries.length > 0) {
|
|
35
35
|
process.stderr.write(`warning: stale allowlist entries in ${scope}: ${result.staleEntries.join(', ')}\n`);
|
|
36
36
|
}
|
|
37
|
-
if (options.
|
|
38
|
-
const
|
|
39
|
-
for (const warning of
|
|
37
|
+
if (options.isJson) {
|
|
38
|
+
const parsedOutput = parseAuditCiOutput(result.stdout);
|
|
39
|
+
for (const warning of parsedOutput.warnings) {
|
|
40
40
|
process.stderr.write(`warning: ${warning}\n`);
|
|
41
41
|
}
|
|
42
|
-
for (const
|
|
43
|
-
if (allResults.every((
|
|
44
|
-
allResults.push(
|
|
42
|
+
for (const auditResult of parsedOutput.results) {
|
|
43
|
+
if (allResults.every((existingResult) => existingResult.id !== auditResult.id)) {
|
|
44
|
+
allResults.push(auditResult);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -57,7 +57,7 @@ export async function auditCommand(options) {
|
|
|
57
57
|
exitCode = result.exitCode;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
-
if (options.
|
|
60
|
+
if (options.isJson) {
|
|
61
61
|
process.stdout.write(JSON.stringify(allResults, null, 2) + '\n');
|
|
62
62
|
}
|
|
63
63
|
return exitCode;
|
|
@@ -70,15 +70,15 @@ export async function auditCommand(options) {
|
|
|
70
70
|
}
|
|
71
71
|
const CHECK_SCOPE_ORDER = ['prod', 'dev'];
|
|
72
72
|
export async function checkCommand(options) {
|
|
73
|
-
let
|
|
73
|
+
let loadedConfigResult;
|
|
74
74
|
try {
|
|
75
|
-
|
|
75
|
+
loadedConfigResult = await loadConfig(options.configPath);
|
|
76
76
|
}
|
|
77
77
|
catch (error) {
|
|
78
78
|
reportError(describeError(error));
|
|
79
79
|
return 1;
|
|
80
80
|
}
|
|
81
|
-
const { config } =
|
|
81
|
+
const { config } = loadedConfigResult;
|
|
82
82
|
const requestedScopes = options.scopes.length > 0 ? options.scopes : [...CHECK_SCOPE_ORDER];
|
|
83
83
|
const scopes = CHECK_SCOPE_ORDER.filter((s) => requestedScopes.includes(s));
|
|
84
84
|
try {
|
|
@@ -92,8 +92,8 @@ export async function checkCommand(options) {
|
|
|
92
92
|
const scopeConfig = config[scope];
|
|
93
93
|
const effectiveThreshold = scopeConfig.severityThreshold ?? 'low';
|
|
94
94
|
thresholds[scope] = effectiveThreshold;
|
|
95
|
-
const
|
|
96
|
-
const strippedConfigPath = await generateAuditCiConfig(
|
|
95
|
+
const strippedScopeConfig = { ...scopeConfig, allowlist: [], severityThreshold: 'low' };
|
|
96
|
+
const strippedConfigPath = await generateAuditCiConfig(strippedScopeConfig, scope, tempDir);
|
|
97
97
|
const reportOptions = { configPath: strippedConfigPath };
|
|
98
98
|
if (options.verbose) {
|
|
99
99
|
reportOptions.reportType = 'full';
|
|
@@ -115,7 +115,7 @@ export async function checkCommand(options) {
|
|
|
115
115
|
}
|
|
116
116
|
else if (allowedIds.has(result.id)) {
|
|
117
117
|
const entry = allowlistById.get(result.id);
|
|
118
|
-
scopeResult.allowed.push(
|
|
118
|
+
scopeResult.allowed.push(buildAllowedVulnerability(result, entry));
|
|
119
119
|
}
|
|
120
120
|
else {
|
|
121
121
|
scopeResult.unallowed.push(result);
|
|
@@ -128,10 +128,10 @@ export async function checkCommand(options) {
|
|
|
128
128
|
}
|
|
129
129
|
checkResult[scope] = scopeResult;
|
|
130
130
|
}
|
|
131
|
-
if (options.verbose && !options.
|
|
131
|
+
if (options.verbose && !options.isJson) {
|
|
132
132
|
process.stdout.write(formatCheckVerboseText(checkResult, scopes, options.styles.stdout, undefined, thresholds));
|
|
133
133
|
}
|
|
134
|
-
else if (options.
|
|
134
|
+
else if (options.isJson) {
|
|
135
135
|
process.stdout.write(formatCheckJson(checkResult, scopes));
|
|
136
136
|
}
|
|
137
137
|
else {
|
|
@@ -147,38 +147,38 @@ export async function checkCommand(options) {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
export async function syncCommand(options) {
|
|
150
|
-
let
|
|
150
|
+
let loadedConfigResult;
|
|
151
151
|
try {
|
|
152
|
-
|
|
152
|
+
loadedConfigResult = await loadConfig(options.configPath);
|
|
153
153
|
}
|
|
154
154
|
catch (error) {
|
|
155
155
|
reportError(describeError(error));
|
|
156
156
|
return 1;
|
|
157
157
|
}
|
|
158
|
-
const { configSource } =
|
|
158
|
+
const { configSource } = loadedConfigResult;
|
|
159
159
|
if (configSource === 'defaults') {
|
|
160
|
-
const { configResult } = scaffoldConfig({
|
|
160
|
+
const { configResult } = scaffoldConfig({ isDryRun: false });
|
|
161
161
|
if (configResult.outcome === 'failed') {
|
|
162
162
|
reportError('Failed to create config file');
|
|
163
163
|
return 1;
|
|
164
164
|
}
|
|
165
|
-
|
|
165
|
+
loadedConfigResult = await loadConfig(options.configPath);
|
|
166
166
|
}
|
|
167
|
-
let { config } =
|
|
168
|
-
const { configFilePath } =
|
|
167
|
+
let { config } = loadedConfigResult;
|
|
168
|
+
const { configFilePath } = loadedConfigResult;
|
|
169
169
|
const scopes = options.scopes.length > 0 ? options.scopes : [...AUDIT_SCOPES];
|
|
170
170
|
try {
|
|
171
171
|
return await withTempDir(async (tempDir) => {
|
|
172
172
|
for (const scope of scopes) {
|
|
173
|
-
const
|
|
174
|
-
const strippedConfigPath = await generateAuditCiConfig(
|
|
173
|
+
const strippedScopeConfig = { ...config[scope], allowlist: [] };
|
|
174
|
+
const strippedConfigPath = await generateAuditCiConfig(strippedScopeConfig, scope, tempDir);
|
|
175
175
|
const report = runReport({ configPath: strippedConfigPath });
|
|
176
176
|
for (const warning of report.warnings) {
|
|
177
177
|
process.stderr.write(`warning: ${warning}\n`);
|
|
178
178
|
}
|
|
179
179
|
const { syncResult, updatedConfig } = await syncAllowlist(config, scope, report.results, configFilePath);
|
|
180
180
|
config = updatedConfig;
|
|
181
|
-
if (options.
|
|
181
|
+
if (options.isJson) {
|
|
182
182
|
process.stdout.write(JSON.stringify(syncResult, null, 2) + '\n');
|
|
183
183
|
}
|
|
184
184
|
else {
|
|
@@ -189,8 +189,8 @@ export async function syncCommand(options) {
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
if (configSource === 'defaults') {
|
|
192
|
-
const
|
|
193
|
-
process.stdout.write(`Created config at ${configFilePath} with ${
|
|
192
|
+
const allowedEntryCount = config.dev.allowlist.length + config.prod.allowlist.length;
|
|
193
|
+
process.stdout.write(`Created config at ${configFilePath} with ${allowedEntryCount} allowed entries.\n`);
|
|
194
194
|
}
|
|
195
195
|
return 0;
|
|
196
196
|
});
|
|
@@ -200,26 +200,26 @@ export async function syncCommand(options) {
|
|
|
200
200
|
return 1;
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
function
|
|
204
|
-
const
|
|
203
|
+
function buildAllowedVulnerability(result, entry) {
|
|
204
|
+
const allowedVulnerability = {
|
|
205
205
|
id: result.id,
|
|
206
206
|
path: result.path,
|
|
207
207
|
paths: result.paths,
|
|
208
208
|
url: result.url,
|
|
209
209
|
};
|
|
210
210
|
if (result.ghsaId !== undefined)
|
|
211
|
-
|
|
211
|
+
allowedVulnerability.ghsaId = result.ghsaId;
|
|
212
212
|
if (result.severity !== undefined)
|
|
213
|
-
|
|
213
|
+
allowedVulnerability.severity = result.severity;
|
|
214
214
|
if (result.title !== undefined)
|
|
215
|
-
|
|
215
|
+
allowedVulnerability.title = result.title;
|
|
216
216
|
if (result.description !== undefined)
|
|
217
|
-
|
|
217
|
+
allowedVulnerability.description = result.description;
|
|
218
218
|
if (result.cvss !== undefined)
|
|
219
|
-
|
|
219
|
+
allowedVulnerability.cvss = result.cvss;
|
|
220
220
|
if (entry?.reason !== undefined)
|
|
221
|
-
|
|
221
|
+
allowedVulnerability.reason = entry.reason;
|
|
222
222
|
if (entry?.addedAt !== undefined)
|
|
223
|
-
|
|
224
|
-
return
|
|
223
|
+
allowedVulnerability.addedAt = entry.addedAt;
|
|
224
|
+
return allowedVulnerability;
|
|
225
225
|
}
|
package/dist/esm/config.js
CHANGED
|
@@ -15,24 +15,24 @@ export async function loadConfig(configPath, cwd) {
|
|
|
15
15
|
configSource: 'defaults',
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
-
let
|
|
18
|
+
let rawContent;
|
|
19
19
|
try {
|
|
20
|
-
|
|
20
|
+
rawContent = await readFile(filePath, 'utf8');
|
|
21
21
|
}
|
|
22
22
|
catch {
|
|
23
23
|
throw new Error(`Config file not found: ${filePath}`);
|
|
24
24
|
}
|
|
25
|
-
let
|
|
25
|
+
let parsedConfig;
|
|
26
26
|
try {
|
|
27
|
-
|
|
27
|
+
parsedConfig = JSON.parse(rawContent);
|
|
28
28
|
}
|
|
29
29
|
catch {
|
|
30
30
|
throw new Error(`Config file is not valid JSON: ${filePath}`);
|
|
31
31
|
}
|
|
32
|
-
const result = v11yCheckConfigSchema.safeParse(
|
|
32
|
+
const result = v11yCheckConfigSchema.safeParse(parsedConfig);
|
|
33
33
|
if (!result.success) {
|
|
34
|
-
const
|
|
35
|
-
throw new Error(`Invalid config in ${filePath}:\n${
|
|
34
|
+
const issueText = result.error.issues.map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`).join('\n');
|
|
35
|
+
throw new Error(`Invalid config in ${filePath}:\n${issueText}`);
|
|
36
36
|
}
|
|
37
37
|
return { config: result.data, configDir, configFilePath: filePath, configSource: 'file' };
|
|
38
38
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
1
|
+
const ADD_SYNC_HINT = 'Run `v11y sync` to add the listed vulnerabilities to the allowlist.';
|
|
2
|
+
const REMOVE_SYNC_HINT = 'Run `v11y sync` to remove stale allowlist entries.';
|
|
3
|
+
const ADD_AND_REMOVE_SYNC_HINT = 'Run `v11y sync` to add the listed vulnerabilities to the allowlist and remove stale entries.';
|
|
4
4
|
function buildVerboseFlag(scopes) {
|
|
5
5
|
if (scopes.length === 1) {
|
|
6
6
|
return `--${scopes[0]} --verbose`;
|
|
@@ -9,24 +9,24 @@ function buildVerboseFlag(scopes) {
|
|
|
9
9
|
}
|
|
10
10
|
function selectSyncHint(hasUnallowed, hasStale) {
|
|
11
11
|
if (hasUnallowed && hasStale)
|
|
12
|
-
return
|
|
12
|
+
return ADD_AND_REMOVE_SYNC_HINT;
|
|
13
13
|
if (hasUnallowed)
|
|
14
|
-
return
|
|
15
|
-
return
|
|
14
|
+
return ADD_SYNC_HINT;
|
|
15
|
+
return REMOVE_SYNC_HINT;
|
|
16
16
|
}
|
|
17
17
|
export function formatActionHints(result, scopes) {
|
|
18
18
|
const hasUnallowed = scopes.some((scope) => result[scope].unallowed.length > 0);
|
|
19
19
|
const hasAllowed = scopes.some((scope) => result[scope].allowed.length > 0);
|
|
20
20
|
const hasStale = scopes.some((scope) => result[scope].stale.length > 0);
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
if (!
|
|
21
|
+
const hasVulnerabilities = hasUnallowed || hasAllowed;
|
|
22
|
+
const isSyncNeeded = hasUnallowed || hasStale;
|
|
23
|
+
if (!hasVulnerabilities && !isSyncNeeded)
|
|
24
24
|
return '';
|
|
25
25
|
const bullets = [];
|
|
26
|
-
if (
|
|
26
|
+
if (hasVulnerabilities) {
|
|
27
27
|
bullets.push(` \u{2022} Run \`v11y check ${buildVerboseFlag(scopes)}\` for full report`);
|
|
28
28
|
}
|
|
29
|
-
if (
|
|
29
|
+
if (isSyncNeeded) {
|
|
30
30
|
bullets.push(` \u{2022} ${selectSyncHint(hasUnallowed, hasStale)}`);
|
|
31
31
|
}
|
|
32
32
|
return ` Actions:\n${bullets.join('\n')}`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type OutputStyle } from '@williamthorsen/nmr-core';
|
|
2
2
|
import type { AuditResult, AuditScope, SeverityThreshold } from './types.js';
|
|
3
3
|
/** An audit finding that the allowlist admits, with the entry's reason and date. */
|
|
4
|
-
export interface
|
|
4
|
+
export interface AllowedVulnerability {
|
|
5
5
|
addedAt?: string | undefined;
|
|
6
6
|
cvss?: {
|
|
7
7
|
score?: number;
|
|
@@ -23,7 +23,7 @@ export interface StaleEntry {
|
|
|
23
23
|
}
|
|
24
24
|
/** Check results for a single scope. */
|
|
25
25
|
export interface ScopeCheckResult {
|
|
26
|
-
allowed:
|
|
26
|
+
allowed: AllowedVulnerability[];
|
|
27
27
|
belowThreshold: AuditResult[];
|
|
28
28
|
stale: StaleEntry[];
|
|
29
29
|
unallowed: AuditResult[];
|
|
@@ -34,9 +34,9 @@ export interface CheckResult {
|
|
|
34
34
|
prod: ScopeCheckResult;
|
|
35
35
|
}
|
|
36
36
|
/** Maps a severity string to its indicator in a style: a colored circle when rich, nothing when plain. */
|
|
37
|
-
export declare function
|
|
37
|
+
export declare function getSeverityIndicator(severity: string | undefined, style: OutputStyle): string;
|
|
38
38
|
/** Resolves the best display ID for a vulnerability: GHSA ID if available, otherwise the numeric ID. */
|
|
39
|
-
export declare function
|
|
39
|
+
export declare function resolveDisplayId(vulnerability: {
|
|
40
40
|
ghsaId?: string | undefined;
|
|
41
41
|
id: string;
|
|
42
42
|
}): string;
|