npm-audit-report-cli 1.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/README.md +180 -0
- package/action.yml +38 -0
- package/dist/chunk-L2D2NQGH.js +574 -0
- package/dist/cli.cjs +760 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +197 -0
- package/dist/index.cjs +613 -0
- package/dist/index.d.cts +54 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +23 -0
- package/package.json +60 -0
package/dist/cli.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ParseError,
|
|
4
|
+
format,
|
|
5
|
+
parse,
|
|
6
|
+
shouldFail
|
|
7
|
+
} from "./chunk-L2D2NQGH.js";
|
|
8
|
+
|
|
9
|
+
// src/cli.ts
|
|
10
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
11
|
+
var VERSION = "1.0.0";
|
|
12
|
+
var VALID_FORMATS = ["markdown", "html", "sarif", "annotations"];
|
|
13
|
+
var VALID_SEVERITIES = ["critical", "high", "moderate", "low", "info"];
|
|
14
|
+
var VALID_FAIL_ON = ["critical", "high", "moderate", "low", "info", "none"];
|
|
15
|
+
function printHelp() {
|
|
16
|
+
const help = `audit-report v${VERSION}
|
|
17
|
+
|
|
18
|
+
Convert npm audit JSON to Markdown, HTML, SARIF, or GitHub annotations.
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
npm audit --json | audit-report [options]
|
|
22
|
+
audit-report --file audit.json [options]
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
-f, --format <fmt> Output format: markdown|html|sarif|annotations (default: markdown)
|
|
26
|
+
-o, --output <path> Write to file instead of stdout
|
|
27
|
+
-s, --severity <sev> Minimum severity to include: critical|high|moderate|low|info (default: low)
|
|
28
|
+
--fail-on <sev> Exit 1 if findings at/above this severity: critical|high|moderate|low|info|none (default: high)
|
|
29
|
+
--file <path> Read audit JSON from file (default: stdin)
|
|
30
|
+
--title <text> Report title (default: "npm audit report")
|
|
31
|
+
--template <path> Custom markdown template (reserved; not yet implemented)
|
|
32
|
+
--no-color Disable colored output (no-op)
|
|
33
|
+
-q, --quiet Suppress non-essential stderr output
|
|
34
|
+
-v, --version Print version and exit
|
|
35
|
+
-h, --help Print this help and exit
|
|
36
|
+
|
|
37
|
+
Exit codes:
|
|
38
|
+
0 success, no findings at/above --fail-on threshold
|
|
39
|
+
1 findings at/above --fail-on threshold
|
|
40
|
+
2 invalid input (bad JSON, unrecognized schema)
|
|
41
|
+
3 --file not found
|
|
42
|
+
`;
|
|
43
|
+
process.stdout.write(help);
|
|
44
|
+
}
|
|
45
|
+
function isFormat(s) {
|
|
46
|
+
return VALID_FORMATS.includes(s);
|
|
47
|
+
}
|
|
48
|
+
function isSeverity(s) {
|
|
49
|
+
return VALID_SEVERITIES.includes(s);
|
|
50
|
+
}
|
|
51
|
+
function isFailOn(s) {
|
|
52
|
+
return VALID_FAIL_ON.includes(s);
|
|
53
|
+
}
|
|
54
|
+
function fail(msg, code) {
|
|
55
|
+
process.stderr.write(`audit-report: ${msg}
|
|
56
|
+
`);
|
|
57
|
+
process.exit(code);
|
|
58
|
+
}
|
|
59
|
+
function parseArgs(argv) {
|
|
60
|
+
const args = {
|
|
61
|
+
format: "markdown",
|
|
62
|
+
severity: "low",
|
|
63
|
+
failOn: "high",
|
|
64
|
+
title: "npm audit report",
|
|
65
|
+
quiet: false
|
|
66
|
+
};
|
|
67
|
+
const take = (i, flag) => {
|
|
68
|
+
const v = argv[i + 1];
|
|
69
|
+
if (v === void 0 || v.startsWith("-")) fail(`missing value for ${flag}`, 2);
|
|
70
|
+
return v;
|
|
71
|
+
};
|
|
72
|
+
for (let i = 0; i < argv.length; i++) {
|
|
73
|
+
const a = argv[i];
|
|
74
|
+
if (a === void 0) continue;
|
|
75
|
+
switch (a) {
|
|
76
|
+
case "-h":
|
|
77
|
+
case "--help":
|
|
78
|
+
printHelp();
|
|
79
|
+
process.exit(0);
|
|
80
|
+
break;
|
|
81
|
+
case "-v":
|
|
82
|
+
case "--version":
|
|
83
|
+
process.stdout.write(`${VERSION}
|
|
84
|
+
`);
|
|
85
|
+
process.exit(0);
|
|
86
|
+
break;
|
|
87
|
+
case "-f":
|
|
88
|
+
case "--format": {
|
|
89
|
+
const v = take(i, a);
|
|
90
|
+
if (!isFormat(v)) fail(`invalid format: ${v}`, 2);
|
|
91
|
+
args.format = v;
|
|
92
|
+
i++;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case "-o":
|
|
96
|
+
case "--output":
|
|
97
|
+
args.output = take(i, a);
|
|
98
|
+
i++;
|
|
99
|
+
break;
|
|
100
|
+
case "-s":
|
|
101
|
+
case "--severity": {
|
|
102
|
+
const v = take(i, a);
|
|
103
|
+
if (!isSeverity(v)) fail(`invalid severity: ${v}`, 2);
|
|
104
|
+
args.severity = v;
|
|
105
|
+
i++;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case "--fail-on": {
|
|
109
|
+
const v = take(i, a);
|
|
110
|
+
if (!isFailOn(v)) fail(`invalid fail-on: ${v}`, 2);
|
|
111
|
+
args.failOn = v;
|
|
112
|
+
i++;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case "--file":
|
|
116
|
+
args.file = take(i, a);
|
|
117
|
+
i++;
|
|
118
|
+
break;
|
|
119
|
+
case "--title":
|
|
120
|
+
args.title = take(i, a);
|
|
121
|
+
i++;
|
|
122
|
+
break;
|
|
123
|
+
case "--template":
|
|
124
|
+
args.template = take(i, a);
|
|
125
|
+
i++;
|
|
126
|
+
break;
|
|
127
|
+
case "--no-color":
|
|
128
|
+
break;
|
|
129
|
+
case "-q":
|
|
130
|
+
case "--quiet":
|
|
131
|
+
args.quiet = true;
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
fail(`unknown argument: ${a}`, 2);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return args;
|
|
138
|
+
}
|
|
139
|
+
async function readStdin() {
|
|
140
|
+
const chunks = [];
|
|
141
|
+
for await (const chunk of process.stdin) {
|
|
142
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
143
|
+
}
|
|
144
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
145
|
+
}
|
|
146
|
+
async function main() {
|
|
147
|
+
const args = parseArgs(process.argv.slice(2));
|
|
148
|
+
let input;
|
|
149
|
+
if (args.file) {
|
|
150
|
+
if (!existsSync(args.file)) fail(`file not found: ${args.file}`, 3);
|
|
151
|
+
try {
|
|
152
|
+
input = readFileSync(args.file, "utf8");
|
|
153
|
+
} catch (e) {
|
|
154
|
+
fail(`could not read file: ${args.file}`, 3);
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
if (process.stdin.isTTY) {
|
|
158
|
+
fail(
|
|
159
|
+
"no input. Pipe `npm audit --json` to this command or use --file <path>. Run with --help for usage.",
|
|
160
|
+
1
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
input = await readStdin();
|
|
164
|
+
}
|
|
165
|
+
let report;
|
|
166
|
+
try {
|
|
167
|
+
report = parse(input);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
const msg = e instanceof ParseError ? e.message : "failed to parse input";
|
|
170
|
+
fail(msg, 2);
|
|
171
|
+
}
|
|
172
|
+
if (args.template && !args.quiet) {
|
|
173
|
+
process.stderr.write("audit-report: --template is reserved for future use and is being ignored\n");
|
|
174
|
+
}
|
|
175
|
+
const opts = {
|
|
176
|
+
format: args.format,
|
|
177
|
+
severity: args.severity,
|
|
178
|
+
failOn: args.failOn,
|
|
179
|
+
title: args.title
|
|
180
|
+
};
|
|
181
|
+
const output = format(report, opts);
|
|
182
|
+
if (args.output) {
|
|
183
|
+
writeFileSync(args.output, output, "utf8");
|
|
184
|
+
} else {
|
|
185
|
+
process.stdout.write(output);
|
|
186
|
+
if (!output.endsWith("\n")) process.stdout.write("\n");
|
|
187
|
+
}
|
|
188
|
+
if (shouldFail(report, args.failOn)) {
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
process.exit(0);
|
|
192
|
+
}
|
|
193
|
+
main().catch((e) => {
|
|
194
|
+
process.stderr.write(`audit-report: ${e instanceof Error ? e.message : String(e)}
|
|
195
|
+
`);
|
|
196
|
+
process.exit(2);
|
|
197
|
+
});
|