@vertaaux/cli 0.3.3 → 0.5.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/CHANGELOG.md +97 -0
- package/MIGRATION.md +239 -0
- package/README.md +34 -16
- package/dist/app/interactive-app.d.ts +101 -0
- package/dist/app/interactive-app.d.ts.map +1 -0
- package/dist/app/interactive-app.js +309 -0
- package/dist/app/layout/canvas.d.ts +23 -0
- package/dist/app/layout/canvas.d.ts.map +1 -0
- package/dist/app/layout/canvas.js +36 -0
- package/dist/app/layout/footer.d.ts +31 -0
- package/dist/app/layout/footer.d.ts.map +1 -0
- package/dist/app/layout/footer.js +41 -0
- package/dist/app/layout/header.d.ts +20 -0
- package/dist/app/layout/header.d.ts.map +1 -0
- package/dist/app/layout/header.js +27 -0
- package/dist/app/menu/categories.d.ts +20 -0
- package/dist/app/menu/categories.d.ts.map +1 -0
- package/dist/app/menu/categories.js +181 -0
- package/dist/app/menu/filter.d.ts +17 -0
- package/dist/app/menu/filter.d.ts.map +1 -0
- package/dist/app/menu/filter.js +33 -0
- package/dist/app/menu/menu-view.d.ts +35 -0
- package/dist/app/menu/menu-view.d.ts.map +1 -0
- package/dist/app/menu/menu-view.js +230 -0
- package/dist/app/menu/recent.d.ts +24 -0
- package/dist/app/menu/recent.d.ts.map +1 -0
- package/dist/app/menu/recent.js +49 -0
- package/dist/app/types.d.ts +43 -0
- package/dist/app/types.d.ts.map +1 -0
- package/dist/app/types.js +7 -0
- package/dist/app/views/command-runner.d.ts +36 -0
- package/dist/app/views/command-runner.d.ts.map +1 -0
- package/dist/app/views/command-runner.js +372 -0
- package/dist/app/views/help-overlay.d.ts +21 -0
- package/dist/app/views/help-overlay.d.ts.map +1 -0
- package/dist/app/views/help-overlay.js +45 -0
- package/dist/auth/ci-token.d.ts +14 -2
- package/dist/auth/ci-token.d.ts.map +1 -1
- package/dist/auth/ci-token.js +15 -30
- package/dist/auth/device-flow.d.ts +2 -1
- package/dist/auth/device-flow.d.ts.map +1 -1
- package/dist/auth/device-flow.js +13 -10
- package/dist/auth/token-store.d.ts.map +1 -1
- package/dist/auth/token-store.js +12 -2
- package/dist/baseline/diff.d.ts +2 -2
- package/dist/baseline/diff.d.ts.map +1 -1
- package/dist/baseline/diff.js +15 -34
- package/dist/commands/a11y.d.ts +9 -0
- package/dist/commands/a11y.d.ts.map +1 -0
- package/dist/commands/a11y.js +76 -0
- package/dist/commands/audit/artifacts.d.ts +27 -0
- package/dist/commands/audit/artifacts.d.ts.map +1 -0
- package/dist/commands/audit/artifacts.js +158 -0
- package/dist/commands/audit/ci-detection.d.ts +18 -0
- package/dist/commands/audit/ci-detection.d.ts.map +1 -0
- package/dist/commands/audit/ci-detection.js +71 -0
- package/dist/commands/audit/explain.d.ts +11 -0
- package/dist/commands/audit/explain.d.ts.map +1 -0
- package/dist/commands/audit/explain.js +45 -0
- package/dist/commands/audit/filters.d.ts +17 -0
- package/dist/commands/audit/filters.d.ts.map +1 -0
- package/dist/commands/audit/filters.js +40 -0
- package/dist/commands/audit/index.d.ts +18 -0
- package/dist/commands/audit/index.d.ts.map +1 -0
- package/dist/commands/audit/index.js +564 -0
- package/dist/commands/audit/output.d.ts +32 -0
- package/dist/commands/audit/output.d.ts.map +1 -0
- package/dist/commands/audit/output.js +130 -0
- package/dist/commands/audit/policy.d.ts +19 -0
- package/dist/commands/audit/policy.d.ts.map +1 -0
- package/dist/commands/audit/policy.js +102 -0
- package/dist/commands/audit/scoring.d.ts +23 -0
- package/dist/commands/audit/scoring.d.ts.map +1 -0
- package/dist/commands/audit/scoring.js +70 -0
- package/dist/commands/audit/types.d.ts +88 -0
- package/dist/commands/audit/types.d.ts.map +1 -0
- package/dist/commands/audit/types.js +8 -0
- package/dist/commands/audit.d.ts +2 -60
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +2 -1038
- package/dist/commands/baseline.d.ts +1 -0
- package/dist/commands/baseline.d.ts.map +1 -1
- package/dist/commands/baseline.js +205 -121
- package/dist/commands/comment.d.ts +22 -0
- package/dist/commands/comment.d.ts.map +1 -1
- package/dist/commands/comment.js +122 -58
- package/dist/commands/compare.d.ts +17 -0
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +287 -180
- package/dist/commands/diff.d.ts +5 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +168 -141
- package/dist/commands/doc.d.ts +10 -0
- package/dist/commands/doc.d.ts.map +1 -1
- package/dist/commands/doc.js +134 -76
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +164 -17
- package/dist/commands/download.d.ts +10 -0
- package/dist/commands/download.d.ts.map +1 -1
- package/dist/commands/download.js +169 -112
- package/dist/commands/explain.d.ts +5 -0
- package/dist/commands/explain.d.ts.map +1 -1
- package/dist/commands/explain.js +241 -155
- package/dist/commands/fix-all.d.ts +25 -0
- package/dist/commands/fix-all.d.ts.map +1 -0
- package/dist/commands/fix-all.js +206 -0
- package/dist/commands/fix-plan.d.ts +9 -0
- package/dist/commands/fix-plan.d.ts.map +1 -1
- package/dist/commands/fix-plan.js +152 -89
- package/dist/commands/fix.d.ts +17 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +111 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +94 -42
- package/dist/commands/login.d.ts +18 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +268 -95
- package/dist/commands/patch-review.d.ts +11 -0
- package/dist/commands/patch-review.d.ts.map +1 -1
- package/dist/commands/patch-review.js +159 -97
- package/dist/commands/policy.d.ts +31 -0
- package/dist/commands/policy.d.ts.map +1 -1
- package/dist/commands/policy.js +269 -124
- package/dist/commands/release-notes.d.ts +10 -0
- package/dist/commands/release-notes.d.ts.map +1 -1
- package/dist/commands/release-notes.js +127 -73
- package/dist/commands/scan.d.ts +13 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +133 -0
- package/dist/commands/status.d.ts +9 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/suggest.d.ts +10 -0
- package/dist/commands/suggest.d.ts.map +1 -1
- package/dist/commands/suggest.js +153 -82
- package/dist/commands/triage.d.ts +35 -0
- package/dist/commands/triage.d.ts.map +1 -1
- package/dist/commands/triage.js +206 -81
- package/dist/commands/upload.d.ts +9 -0
- package/dist/commands/upload.d.ts.map +1 -1
- package/dist/commands/upload.js +140 -101
- package/dist/commands/verify.d.ts +13 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +118 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +125 -990
- package/dist/interactive/fix-wizard.d.ts +3 -0
- package/dist/interactive/fix-wizard.d.ts.map +1 -1
- package/dist/interactive/fix-wizard.js +130 -112
- package/dist/interactive/init-wizard.d.ts +3 -1
- package/dist/interactive/init-wizard.d.ts.map +1 -1
- package/dist/interactive/init-wizard.js +207 -138
- package/dist/interactive/prompts.d.ts +7 -3
- package/dist/interactive/prompts.d.ts.map +1 -1
- package/dist/interactive/prompts.js +44 -23
- package/dist/output/envelope.d.ts +2 -0
- package/dist/output/envelope.d.ts.map +1 -1
- package/dist/output/envelope.js +18 -2
- package/dist/output/factory.d.ts +9 -1
- package/dist/output/factory.d.ts.map +1 -1
- package/dist/output/html.d.ts +2 -1
- package/dist/output/html.d.ts.map +1 -1
- package/dist/output/html.js +3 -2
- package/dist/output/human.d.ts +9 -1
- package/dist/output/human.d.ts.map +1 -1
- package/dist/output/human.js +17 -2
- package/dist/output/json.d.ts +2 -1
- package/dist/output/json.d.ts.map +1 -1
- package/dist/output/junit.d.ts +2 -1
- package/dist/output/junit.d.ts.map +1 -1
- package/dist/output/sarif.d.ts +2 -1
- package/dist/output/sarif.d.ts.map +1 -1
- package/dist/types.d.ts +74 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/ui/banner.d.ts +34 -0
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +97 -5
- package/dist/ui/diagnostics.d.ts +9 -4
- package/dist/ui/diagnostics.d.ts.map +1 -1
- package/dist/ui/diagnostics.js +32 -82
- package/dist/ui/strings.d.ts +373 -0
- package/dist/ui/strings.d.ts.map +1 -0
- package/dist/ui/strings.js +499 -0
- package/dist/ui/table.d.ts +0 -2
- package/dist/ui/table.d.ts.map +1 -1
- package/dist/ui/table.js +3 -4
- package/dist/utils/api-client.d.ts +46 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +170 -0
- package/dist/utils/client.d.ts +29 -18
- package/dist/utils/client.d.ts.map +1 -1
- package/dist/utils/client.js +102 -12
- package/dist/utils/formatters.d.ts +38 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +277 -0
- package/dist/utils/local-capture.d.ts +25 -0
- package/dist/utils/local-capture.d.ts.map +1 -0
- package/dist/utils/local-capture.js +57 -0
- package/dist/utils/url-classify.d.ts +18 -0
- package/dist/utils/url-classify.d.ts.map +1 -0
- package/dist/utils/url-classify.js +106 -0
- package/node_modules/@vertaaux/tui/dist/index.cjs +713 -20
- package/node_modules/@vertaaux/tui/dist/index.cjs.map +1 -1
- package/node_modules/@vertaaux/tui/dist/index.d.cts +361 -4
- package/node_modules/@vertaaux/tui/dist/index.d.ts +361 -4
- package/node_modules/@vertaaux/tui/dist/index.js +689 -21
- package/node_modules/@vertaaux/tui/dist/index.js.map +1 -1
- package/package.json +13 -5
- package/dist/commands/client.d.ts +0 -14
- package/dist/commands/client.d.ts.map +0 -1
- package/dist/commands/client.js +0 -362
- package/dist/commands/drift.d.ts +0 -15
- package/dist/commands/drift.d.ts.map +0 -1
- package/dist/commands/drift.js +0 -309
- package/dist/commands/protect.d.ts +0 -16
- package/dist/commands/protect.d.ts.map +0 -1
- package/dist/commands/protect.js +0 -323
- package/dist/commands/report.d.ts +0 -15
- package/dist/commands/report.d.ts.map +0 -1
- package/dist/commands/report.js +0 -214
- package/dist/policy/sync.d.ts +0 -67
- package/dist/policy/sync.d.ts.map +0 -1
- package/dist/policy/sync.js +0 -147
package/dist/auth/token-store.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Tokens are stored in ~/.vertaaux/credentials.json with restrictive permissions.
|
|
5
5
|
* This is separate from project config - tokens are user-scoped, not project-scoped.
|
|
6
6
|
*/
|
|
7
|
-
import { readFile, writeFile, mkdir, unlink } from "fs/promises";
|
|
8
|
-
import { existsSync } from "fs";
|
|
7
|
+
import { readFile, writeFile, mkdir, unlink, chmod } from "fs/promises";
|
|
8
|
+
import { existsSync, lstatSync } from "fs";
|
|
9
9
|
import { homedir } from "os";
|
|
10
10
|
import { join, dirname } from "path";
|
|
11
11
|
/**
|
|
@@ -26,6 +26,10 @@ export function getCredentialsPath() {
|
|
|
26
26
|
export async function saveToken(token) {
|
|
27
27
|
const credPath = getCredentialsPath();
|
|
28
28
|
const dir = dirname(credPath);
|
|
29
|
+
// SECVAL-1: Refuse to write if credentials path is a symlink
|
|
30
|
+
if (existsSync(credPath) && lstatSync(credPath).isSymbolicLink()) {
|
|
31
|
+
throw new Error(`Security error: ${credPath} is a symlink. Refusing to write credentials.`);
|
|
32
|
+
}
|
|
29
33
|
// Create directory if needed
|
|
30
34
|
if (!existsSync(dir)) {
|
|
31
35
|
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
@@ -33,6 +37,8 @@ export async function saveToken(token) {
|
|
|
33
37
|
// Write token with restrictive permissions
|
|
34
38
|
const content = JSON.stringify(token, null, 2);
|
|
35
39
|
await writeFile(credPath, content + "\n", { encoding: "utf-8", mode: 0o600 });
|
|
40
|
+
// SECVAL-2: Ensure restrictive permissions after write
|
|
41
|
+
await chmod(credPath, 0o600);
|
|
36
42
|
}
|
|
37
43
|
/**
|
|
38
44
|
* Load token data from credentials file.
|
|
@@ -44,6 +50,10 @@ export async function loadToken() {
|
|
|
44
50
|
if (!existsSync(credPath)) {
|
|
45
51
|
return null;
|
|
46
52
|
}
|
|
53
|
+
// SECVAL-1: Refuse to read if credentials path is a symlink
|
|
54
|
+
if (lstatSync(credPath).isSymbolicLink()) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
47
57
|
try {
|
|
48
58
|
const content = await readFile(credPath, "utf-8");
|
|
49
59
|
return JSON.parse(content);
|
package/dist/baseline/diff.d.ts
CHANGED
|
@@ -38,8 +38,8 @@ export declare function computeDiff(currentIssues: Issue[], baseline: BaselineFi
|
|
|
38
38
|
* Format diff result for human-readable output.
|
|
39
39
|
*
|
|
40
40
|
* Uses colors:
|
|
41
|
-
* - New issues: red
|
|
42
|
-
* - Fixed issues: green
|
|
41
|
+
* - New issues: red (tokens.error)
|
|
42
|
+
* - Fixed issues: green (tokens.success)
|
|
43
43
|
* - Still present: dim
|
|
44
44
|
*
|
|
45
45
|
* @param diff - Diff result to format
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/baseline/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAuB,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,iCAAiC;IACjC,GAAG,EAAE,KAAK,EAAE,CAAC;IACb,8CAA8C;IAC9C,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qCAAqC;IACrC,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,qBAAqB;IACrB,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,aAAa,EAAE,KAAK,EAAE,EACtB,QAAQ,EAAE,YAAY,GACrB,UAAU,CA2CZ;
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/baseline/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAuB,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,iCAAiC;IACjC,GAAG,EAAE,KAAK,EAAE,CAAC;IACb,8CAA8C;IAC9C,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qCAAqC;IACrC,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,qBAAqB;IACrB,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,aAAa,EAAE,KAAK,EAAE,EACtB,QAAQ,EAAE,YAAY,GACrB,UAAU,CA2CZ;AAuBD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,UAAQ,GAAG,MAAM,CAsCzE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEvD"}
|
package/dist/baseline/diff.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - Fixed: Issues in baseline but not in current
|
|
8
8
|
* - Present: Issues in both current and baseline
|
|
9
9
|
*/
|
|
10
|
-
import
|
|
10
|
+
import { boldColor, dim, tokens, text } from "@vertaaux/tui";
|
|
11
11
|
import { generateFingerprint } from "./hash.js";
|
|
12
12
|
/**
|
|
13
13
|
* Compute diff between current issues and baseline.
|
|
@@ -60,25 +60,6 @@ export function computeDiff(currentIssues, baseline) {
|
|
|
60
60
|
function getRuleId(issue) {
|
|
61
61
|
return issue.ruleId || issue.rule_id || issue.id || "unknown";
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Format severity badge for display.
|
|
65
|
-
*/
|
|
66
|
-
function formatSeverityBadge(severity) {
|
|
67
|
-
const upper = (severity || "info").toUpperCase();
|
|
68
|
-
switch (upper) {
|
|
69
|
-
case "ERROR":
|
|
70
|
-
case "CRITICAL":
|
|
71
|
-
return chalk.red(`[${upper}]`);
|
|
72
|
-
case "WARNING":
|
|
73
|
-
case "SERIOUS":
|
|
74
|
-
return chalk.yellow(`[${upper}]`);
|
|
75
|
-
case "INFO":
|
|
76
|
-
case "MINOR":
|
|
77
|
-
return chalk.blue(`[${upper}]`);
|
|
78
|
-
default:
|
|
79
|
-
return chalk.gray(`[${upper}]`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
63
|
/**
|
|
83
64
|
* Format issue line for display.
|
|
84
65
|
*/
|
|
@@ -88,14 +69,14 @@ function formatIssueLine(issue) {
|
|
|
88
69
|
? issue.description
|
|
89
70
|
: issue.description || issue.title || "";
|
|
90
71
|
const severity = issue.severity || "info";
|
|
91
|
-
return
|
|
72
|
+
return `[${text.severityBadge(severity)}] ${ruleId}: ${description}`;
|
|
92
73
|
}
|
|
93
74
|
/**
|
|
94
75
|
* Format diff result for human-readable output.
|
|
95
76
|
*
|
|
96
77
|
* Uses colors:
|
|
97
|
-
* - New issues: red
|
|
98
|
-
* - Fixed issues: green
|
|
78
|
+
* - New issues: red (tokens.error)
|
|
79
|
+
* - Fixed issues: green (tokens.success)
|
|
99
80
|
* - Still present: dim
|
|
100
81
|
*
|
|
101
82
|
* @param diff - Diff result to format
|
|
@@ -104,10 +85,10 @@ function formatIssueLine(issue) {
|
|
|
104
85
|
*/
|
|
105
86
|
export function formatDiffHuman(diff, verbose = false) {
|
|
106
87
|
const lines = [];
|
|
107
|
-
// New issues section (red)
|
|
108
|
-
lines.push(
|
|
88
|
+
// New issues section (red bold)
|
|
89
|
+
lines.push(boldColor(`NEW ISSUES (${diff.summary.newCount})`, tokens.error));
|
|
109
90
|
if (diff.new.length === 0) {
|
|
110
|
-
lines.push(
|
|
91
|
+
lines.push(dim(" No new issues"));
|
|
111
92
|
}
|
|
112
93
|
else {
|
|
113
94
|
for (const issue of diff.new) {
|
|
@@ -115,10 +96,10 @@ export function formatDiffHuman(diff, verbose = false) {
|
|
|
115
96
|
}
|
|
116
97
|
}
|
|
117
98
|
lines.push("");
|
|
118
|
-
// Fixed issues section (green)
|
|
119
|
-
lines.push(
|
|
99
|
+
// Fixed issues section (green bold)
|
|
100
|
+
lines.push(boldColor(`FIXED (${diff.summary.fixedCount})`, tokens.success));
|
|
120
101
|
if (diff.fixed.length === 0) {
|
|
121
|
-
lines.push(
|
|
102
|
+
lines.push(dim(" No issues fixed"));
|
|
122
103
|
}
|
|
123
104
|
else {
|
|
124
105
|
for (const issue of diff.fixed) {
|
|
@@ -126,18 +107,18 @@ export function formatDiffHuman(diff, verbose = false) {
|
|
|
126
107
|
}
|
|
127
108
|
}
|
|
128
109
|
lines.push("");
|
|
129
|
-
// Still present section (dim)
|
|
130
|
-
lines.push(
|
|
110
|
+
// Still present section (dim only — no bold+dim combo per locked decisions)
|
|
111
|
+
lines.push(dim(`STILL PRESENT (${diff.summary.presentCount})`));
|
|
131
112
|
if (diff.present.length === 0) {
|
|
132
|
-
lines.push(
|
|
113
|
+
lines.push(dim(" No baselined issues remain"));
|
|
133
114
|
}
|
|
134
115
|
else if (verbose) {
|
|
135
116
|
for (const issue of diff.present) {
|
|
136
|
-
lines.push(
|
|
117
|
+
lines.push(dim(` ${formatIssueLine(issue)}`));
|
|
137
118
|
}
|
|
138
119
|
}
|
|
139
120
|
else {
|
|
140
|
-
lines.push(
|
|
121
|
+
lines.push(dim(" (use --verbose to show all)"));
|
|
141
122
|
}
|
|
142
123
|
return lines.join("\n");
|
|
143
124
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy a11y command handler.
|
|
3
|
+
* Runs accessibility-focused audit (alias for audit with a11y filter).
|
|
4
|
+
*/
|
|
5
|
+
import type { Command } from "commander";
|
|
6
|
+
import type { Flags } from "../types.js";
|
|
7
|
+
export declare function handleA11y(rawUrl: string, cmdOptions: Flags): Promise<void>;
|
|
8
|
+
export declare function registerA11yCommand(program: Command): void;
|
|
9
|
+
//# sourceMappingURL=a11y.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a11y.d.ts","sourceRoot":"","sources":["../../src/commands/a11y.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGzC,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDjF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuB1D"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy a11y command handler.
|
|
3
|
+
* Runs accessibility-focused audit (alias for audit with a11y filter).
|
|
4
|
+
*/
|
|
5
|
+
import { renderError, runSteps, createRenderer } from "@vertaaux/tui";
|
|
6
|
+
import { ExitCode } from "../utils/exit-codes.js";
|
|
7
|
+
import { parseMode, parseTimeout, parseInterval, parseScore } from "../utils/validators.js";
|
|
8
|
+
import { resolveApiBase } from "../utils/api-client.js";
|
|
9
|
+
import { runAuditCommand } from "./scan.js";
|
|
10
|
+
export async function handleA11y(rawUrl, cmdOptions) {
|
|
11
|
+
const url = /^https?:\/\//i.test(rawUrl) ? rawUrl : `https://${rawUrl}`;
|
|
12
|
+
const renderer = createRenderer("auto");
|
|
13
|
+
const baseState = {
|
|
14
|
+
phase: "a11y",
|
|
15
|
+
phaseIndex: 1,
|
|
16
|
+
phaseTotal: 1,
|
|
17
|
+
url,
|
|
18
|
+
mode: "a11y",
|
|
19
|
+
progress: {},
|
|
20
|
+
totals: {},
|
|
21
|
+
issueCount: 0,
|
|
22
|
+
scorePreview: null,
|
|
23
|
+
verbose: false,
|
|
24
|
+
elapsed: 0,
|
|
25
|
+
};
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
const steps = [
|
|
28
|
+
{
|
|
29
|
+
id: "a11y",
|
|
30
|
+
actionText: "Running accessibility audit...",
|
|
31
|
+
summaryText: "Accessibility audit complete",
|
|
32
|
+
run: async () => {
|
|
33
|
+
const base = resolveApiBase(cmdOptions);
|
|
34
|
+
await runAuditCommand(base, url, { ...cmdOptions, wait: cmdOptions.wait ?? true }, "a11y");
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
const { success, states } = await runSteps(steps, {
|
|
39
|
+
failFast: true,
|
|
40
|
+
onStateChange: (stepStates) => {
|
|
41
|
+
renderer.update({ ...baseState, stepStates, elapsed: Date.now() - startTime });
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
renderer.finish({ url, mode: "a11y", overallScore: 0, scores: {}, issueCount: 0, passed: success, elapsed: Date.now() - startTime });
|
|
45
|
+
if (!success) {
|
|
46
|
+
const failed = states.find(s => s.status === "failed");
|
|
47
|
+
process.stderr.write(renderError({
|
|
48
|
+
message: failed?.failReason || "Command failed",
|
|
49
|
+
suggestion: "vertaa doctor",
|
|
50
|
+
}) + "\n");
|
|
51
|
+
process.exitCode = ExitCode.ERROR;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function registerA11yCommand(program) {
|
|
55
|
+
program
|
|
56
|
+
.command("a11y <url>")
|
|
57
|
+
.description("Run accessibility-focused audit (alias for audit with a11y filter)")
|
|
58
|
+
.option("--mode <mode>", "Audit depth: basic|standard|deep", parseMode, "basic")
|
|
59
|
+
.option("--wait", "Wait for audit completion")
|
|
60
|
+
.option("--timeout <ms>", "Wait timeout in milliseconds (1-300000)", parseTimeout, 60000)
|
|
61
|
+
.option("--interval <ms>", "Poll interval in milliseconds (1-300000)", parseInterval, 5000)
|
|
62
|
+
.option("--fail-on-score <n>", "Exit non-zero if score below n (0-100)", parseScore)
|
|
63
|
+
.action(async (url, cmdOptions) => {
|
|
64
|
+
try {
|
|
65
|
+
await handleA11y(url, cmdOptions);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
process.stderr.write(renderError({
|
|
69
|
+
message: error instanceof Error ? error.message : String(error),
|
|
70
|
+
suggestion: "vertaa audit <url>",
|
|
71
|
+
exitCode: ExitCode.ERROR,
|
|
72
|
+
}) + "\n");
|
|
73
|
+
process.exit(ExitCode.ERROR);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact saving for the audit command.
|
|
3
|
+
*
|
|
4
|
+
* Handles repro artifacts (trace, HAR, screenshots, DOM snapshots)
|
|
5
|
+
* and CI artifact bundling.
|
|
6
|
+
*/
|
|
7
|
+
import type { AuditResponse } from "../../utils/client.js";
|
|
8
|
+
import type { IssueLike, AuditCommandOptions, ArtifactManifest } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Count issues by severity level.
|
|
11
|
+
*/
|
|
12
|
+
export declare function countIssuesBySeverity(issues: IssueLike[]): ArtifactManifest["issue_count"];
|
|
13
|
+
/**
|
|
14
|
+
* Save repro artifacts from API response.
|
|
15
|
+
*/
|
|
16
|
+
export declare function saveReproArtifacts(jobId: string, response: AuditResponse, options: AuditCommandOptions, quiet: boolean): void;
|
|
17
|
+
/**
|
|
18
|
+
* Save CI artifact bundle for GitHub Actions upload.
|
|
19
|
+
*
|
|
20
|
+
* Creates a complete evidence bundle:
|
|
21
|
+
* - results.json: Full audit results
|
|
22
|
+
* - results.sarif: SARIF for Code Scanning
|
|
23
|
+
* - report.html: HTML report for viewing
|
|
24
|
+
* - manifest.json: Metadata about the bundle
|
|
25
|
+
*/
|
|
26
|
+
export declare function saveArtifactBundle(jobId: string, result: AuditResponse, issues: IssueLike[], exitCode: number, quiet: boolean): string;
|
|
27
|
+
//# sourceMappingURL=artifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../../src/commands/audit/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAI3D,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,gBAAgB,CAAC,aAAa,CAAC,CAe1F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,mBAAmB,EAC5B,KAAK,EAAE,OAAO,GACb,IAAI,CAmFN;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,SAAS,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,GACb,MAAM,CAkDR"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Artifact saving for the audit command.
|
|
3
|
+
*
|
|
4
|
+
* Handles repro artifacts (trace, HAR, screenshots, DOM snapshots)
|
|
5
|
+
* and CI artifact bundling.
|
|
6
|
+
*/
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { writeOutput } from "../../output/envelope.js";
|
|
10
|
+
import { formatSarif, formatAuditHtml } from "../../output/factory.js";
|
|
11
|
+
import { assertPathContainment } from "../../utils/sanitize.js";
|
|
12
|
+
import { ARTIFACTS_DIR } from "./types.js";
|
|
13
|
+
/**
|
|
14
|
+
* Count issues by severity level.
|
|
15
|
+
*/
|
|
16
|
+
export function countIssuesBySeverity(issues) {
|
|
17
|
+
const counts = { error: 0, warning: 0, info: 0 };
|
|
18
|
+
for (const issue of issues) {
|
|
19
|
+
const sev = (issue.severity || "info").toLowerCase();
|
|
20
|
+
if (sev === "error" || sev === "critical") {
|
|
21
|
+
counts.error++;
|
|
22
|
+
}
|
|
23
|
+
else if (sev === "warning" || sev === "serious") {
|
|
24
|
+
counts.warning++;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
counts.info++;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return counts;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Save repro artifacts from API response.
|
|
34
|
+
*/
|
|
35
|
+
export function saveReproArtifacts(jobId, response, options, quiet) {
|
|
36
|
+
const hasArtifactOptions = options.saveTrace || options.saveHar || options.screenshots || options.domSnapshots;
|
|
37
|
+
if (!hasArtifactOptions)
|
|
38
|
+
return;
|
|
39
|
+
// Create artifacts directory
|
|
40
|
+
const artifactsPath = path.resolve(process.cwd(), ARTIFACTS_DIR, jobId);
|
|
41
|
+
// Check if API response includes artifact data
|
|
42
|
+
const responseAny = response;
|
|
43
|
+
const artifacts = responseAny.artifacts;
|
|
44
|
+
if (!artifacts) {
|
|
45
|
+
if (!quiet) {
|
|
46
|
+
writeOutput("Note: Repro artifacts were requested but not available in API response.\n");
|
|
47
|
+
writeOutput("Artifact capture may require a 'deep' mode audit or premium plan.\n");
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Ensure directory exists
|
|
52
|
+
if (!fs.existsSync(artifactsPath)) {
|
|
53
|
+
fs.mkdirSync(artifactsPath, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
const saved = [];
|
|
56
|
+
// Save trace file if available and requested
|
|
57
|
+
if (options.saveTrace && artifacts.trace) {
|
|
58
|
+
const tracePath = path.join(artifactsPath, "trace.zip");
|
|
59
|
+
fs.writeFileSync(tracePath, Buffer.from(artifacts.trace, "base64"));
|
|
60
|
+
saved.push("trace.zip");
|
|
61
|
+
}
|
|
62
|
+
// Save HAR file if available and requested
|
|
63
|
+
if (options.saveHar && artifacts.har) {
|
|
64
|
+
const harPath = path.join(artifactsPath, "network.har");
|
|
65
|
+
fs.writeFileSync(harPath, typeof artifacts.har === "string" ? artifacts.har : JSON.stringify(artifacts.har, null, 2));
|
|
66
|
+
saved.push("network.har");
|
|
67
|
+
}
|
|
68
|
+
// Save screenshots if available and requested
|
|
69
|
+
if (options.screenshots && artifacts.screenshots) {
|
|
70
|
+
const screenshots = artifacts.screenshots;
|
|
71
|
+
for (const screenshot of screenshots) {
|
|
72
|
+
const screenshotName = screenshot.name || "screenshot.png";
|
|
73
|
+
let screenshotPath;
|
|
74
|
+
try {
|
|
75
|
+
screenshotPath = assertPathContainment(screenshotName, artifactsPath);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
writeOutput(`Security: Rejected screenshot "${screenshotName}" -- path traversal outside artifacts directory.\n`);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
fs.writeFileSync(screenshotPath, Buffer.from(screenshot.data, "base64"));
|
|
82
|
+
saved.push(screenshotName);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Save DOM snapshots if available and requested
|
|
86
|
+
if (options.domSnapshots && artifacts.domSnapshots) {
|
|
87
|
+
const snapshots = artifacts.domSnapshots;
|
|
88
|
+
for (const snapshot of snapshots) {
|
|
89
|
+
const snapshotName = snapshot.name || "snapshot.html";
|
|
90
|
+
let snapshotPath;
|
|
91
|
+
try {
|
|
92
|
+
snapshotPath = assertPathContainment(snapshotName, artifactsPath);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
writeOutput(`Security: Rejected snapshot "${snapshotName}" -- path traversal outside artifacts directory.\n`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
fs.writeFileSync(snapshotPath, snapshot.html);
|
|
99
|
+
saved.push(snapshotName);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (saved.length > 0 && !quiet) {
|
|
103
|
+
writeOutput(`Artifacts saved to: ${artifactsPath}\n`);
|
|
104
|
+
writeOutput(` - ${saved.join("\n - ")}\n`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Save CI artifact bundle for GitHub Actions upload.
|
|
109
|
+
*
|
|
110
|
+
* Creates a complete evidence bundle:
|
|
111
|
+
* - results.json: Full audit results
|
|
112
|
+
* - results.sarif: SARIF for Code Scanning
|
|
113
|
+
* - report.html: HTML report for viewing
|
|
114
|
+
* - manifest.json: Metadata about the bundle
|
|
115
|
+
*/
|
|
116
|
+
export function saveArtifactBundle(jobId, result, issues, exitCode, quiet) {
|
|
117
|
+
const artifactsPath = path.resolve(process.cwd(), ARTIFACTS_DIR, jobId);
|
|
118
|
+
// Ensure directory exists
|
|
119
|
+
if (!fs.existsSync(artifactsPath)) {
|
|
120
|
+
fs.mkdirSync(artifactsPath, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
const files = [];
|
|
123
|
+
// 1. Save JSON results
|
|
124
|
+
const jsonPath = path.join(artifactsPath, "results.json");
|
|
125
|
+
fs.writeFileSync(jsonPath, JSON.stringify(result, null, 2), "utf-8");
|
|
126
|
+
files.push("results.json");
|
|
127
|
+
// 2. Save SARIF for Code Scanning
|
|
128
|
+
const sarifContent = formatSarif(result, {
|
|
129
|
+
workingDirectory: process.cwd(),
|
|
130
|
+
});
|
|
131
|
+
const sarifPath = path.join(artifactsPath, "results.sarif");
|
|
132
|
+
fs.writeFileSync(sarifPath, sarifContent, "utf-8");
|
|
133
|
+
files.push("results.sarif");
|
|
134
|
+
// 3. Save HTML report
|
|
135
|
+
const htmlContent = formatAuditHtml(result, {
|
|
136
|
+
interactive: true,
|
|
137
|
+
});
|
|
138
|
+
const htmlPath = path.join(artifactsPath, "report.html");
|
|
139
|
+
fs.writeFileSync(htmlPath, htmlContent, "utf-8");
|
|
140
|
+
files.push("report.html");
|
|
141
|
+
// 4. Save manifest
|
|
142
|
+
const manifest = {
|
|
143
|
+
job_id: jobId,
|
|
144
|
+
timestamp: new Date().toISOString(),
|
|
145
|
+
files,
|
|
146
|
+
audit_url: result.url,
|
|
147
|
+
issue_count: countIssuesBySeverity(issues),
|
|
148
|
+
exit_code: exitCode,
|
|
149
|
+
};
|
|
150
|
+
const manifestPath = path.join(artifactsPath, "manifest.json");
|
|
151
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
152
|
+
files.push("manifest.json");
|
|
153
|
+
if (!quiet) {
|
|
154
|
+
writeOutput(`Artifacts saved to: ${artifactsPath}\n`);
|
|
155
|
+
writeOutput(` - ${files.join("\n - ")}\n`);
|
|
156
|
+
}
|
|
157
|
+
return artifactsPath;
|
|
158
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI environment detection for the audit command.
|
|
3
|
+
*
|
|
4
|
+
* Detects current branch and PR labels from various CI providers.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Detect current branch from CI environment or git.
|
|
8
|
+
*/
|
|
9
|
+
export declare function detectCurrentBranch(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Detect PR labels from CI environment variables.
|
|
12
|
+
*
|
|
13
|
+
* Supports:
|
|
14
|
+
* - GitHub Actions: GITHUB_EVENT_PATH contains event JSON with labels
|
|
15
|
+
* - GitLab CI: CI_MERGE_REQUEST_LABELS is comma-separated
|
|
16
|
+
*/
|
|
17
|
+
export declare function detectPRLabels(): string[];
|
|
18
|
+
//# sourceMappingURL=ci-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-detection.d.ts","sourceRoot":"","sources":["../../../src/commands/audit/ci-detection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAqC5C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,MAAM,EAAE,CA0BzC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI environment detection for the audit command.
|
|
3
|
+
*
|
|
4
|
+
* Detects current branch and PR labels from various CI providers.
|
|
5
|
+
*/
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
/**
|
|
8
|
+
* Detect current branch from CI environment or git.
|
|
9
|
+
*/
|
|
10
|
+
export function detectCurrentBranch() {
|
|
11
|
+
// GitHub Actions
|
|
12
|
+
if (process.env.GITHUB_HEAD_REF) {
|
|
13
|
+
return process.env.GITHUB_HEAD_REF;
|
|
14
|
+
}
|
|
15
|
+
if (process.env.GITHUB_REF_NAME) {
|
|
16
|
+
return process.env.GITHUB_REF_NAME;
|
|
17
|
+
}
|
|
18
|
+
// GitLab CI
|
|
19
|
+
if (process.env.CI_COMMIT_REF_NAME) {
|
|
20
|
+
return process.env.CI_COMMIT_REF_NAME;
|
|
21
|
+
}
|
|
22
|
+
// Azure DevOps
|
|
23
|
+
if (process.env.BUILD_SOURCEBRANCHNAME) {
|
|
24
|
+
return process.env.BUILD_SOURCEBRANCHNAME;
|
|
25
|
+
}
|
|
26
|
+
// CircleCI
|
|
27
|
+
if (process.env.CIRCLE_BRANCH) {
|
|
28
|
+
return process.env.CIRCLE_BRANCH;
|
|
29
|
+
}
|
|
30
|
+
// Jenkins
|
|
31
|
+
if (process.env.GIT_BRANCH) {
|
|
32
|
+
// Jenkins often includes origin/, remove it
|
|
33
|
+
return process.env.GIT_BRANCH.replace(/^origin\//, "");
|
|
34
|
+
}
|
|
35
|
+
// Generic CI
|
|
36
|
+
if (process.env.BRANCH_NAME) {
|
|
37
|
+
return process.env.BRANCH_NAME;
|
|
38
|
+
}
|
|
39
|
+
// Default
|
|
40
|
+
return "";
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Detect PR labels from CI environment variables.
|
|
44
|
+
*
|
|
45
|
+
* Supports:
|
|
46
|
+
* - GitHub Actions: GITHUB_EVENT_PATH contains event JSON with labels
|
|
47
|
+
* - GitLab CI: CI_MERGE_REQUEST_LABELS is comma-separated
|
|
48
|
+
*/
|
|
49
|
+
export function detectPRLabels() {
|
|
50
|
+
// GitHub Actions: GITHUB_EVENT_PATH contains event JSON with labels
|
|
51
|
+
if (process.env.GITHUB_EVENT_PATH) {
|
|
52
|
+
try {
|
|
53
|
+
const eventContent = fs.readFileSync(process.env.GITHUB_EVENT_PATH, "utf-8");
|
|
54
|
+
const event = JSON.parse(eventContent);
|
|
55
|
+
const labels = event.pull_request?.labels;
|
|
56
|
+
if (Array.isArray(labels)) {
|
|
57
|
+
return labels.map((l) => l.name || "").filter(Boolean);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Ignore errors reading event file
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// GitLab CI: CI_MERGE_REQUEST_LABELS is comma-separated
|
|
65
|
+
if (process.env.CI_MERGE_REQUEST_LABELS) {
|
|
66
|
+
return process.env.CI_MERGE_REQUEST_LABELS.split(",")
|
|
67
|
+
.map((l) => l.trim())
|
|
68
|
+
.filter(Boolean);
|
|
69
|
+
}
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI inline explanation for the audit command.
|
|
3
|
+
*/
|
|
4
|
+
import type { VertaauxConfig } from "../../config/schema.js";
|
|
5
|
+
import { type AuditResponse } from "../../utils/client.js";
|
|
6
|
+
import type { IssueLike, AuditCommandOptions } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Run the inline AI explanation for audit issues.
|
|
9
|
+
*/
|
|
10
|
+
export declare function runInlineExplanation(issues: IssueLike[], result: AuditResponse, targetUrl: string, options: AuditCommandOptions, config: VertaauxConfig): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=explain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../../src/commands/audit/explain.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,uBAAuB,CAAC;AAK/B,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGjE;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,SAAS,EAAE,EACnB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,mBAAmB,EAC5B,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC,CAyCf"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI inline explanation for the audit command.
|
|
3
|
+
*/
|
|
4
|
+
import { bold, dim, colorize, brand } from "@vertaaux/tui";
|
|
5
|
+
import { writeOutput } from "../../output/envelope.js";
|
|
6
|
+
import { resolveApiBase, getApiKey, apiRequest, } from "../../utils/client.js";
|
|
7
|
+
import { createSpinner, succeedSpinner, } from "../../ui/spinner.js";
|
|
8
|
+
import { strings } from "../../ui/strings.js";
|
|
9
|
+
/**
|
|
10
|
+
* Run the inline AI explanation for audit issues.
|
|
11
|
+
*/
|
|
12
|
+
export async function runInlineExplanation(issues, result, targetUrl, options, config) {
|
|
13
|
+
try {
|
|
14
|
+
const explainBase = resolveApiBase(options.base);
|
|
15
|
+
const explainKey = getApiKey(config.apiKey);
|
|
16
|
+
const explainIssues = issues.map((i) => ({
|
|
17
|
+
id: i.id || null,
|
|
18
|
+
title: i.title || i.description || null,
|
|
19
|
+
description: i.description || null,
|
|
20
|
+
severity: i.severity || null,
|
|
21
|
+
category: i.category || null,
|
|
22
|
+
selector: i.selector || null,
|
|
23
|
+
wcag_reference: i.wcag_reference || null,
|
|
24
|
+
recommendation: i.recommendation || i.recommended_fix || null,
|
|
25
|
+
}));
|
|
26
|
+
const explainPayload = {
|
|
27
|
+
job_id: result.job_id || null,
|
|
28
|
+
url: targetUrl || null,
|
|
29
|
+
scores: result.scores || null,
|
|
30
|
+
issues: explainIssues,
|
|
31
|
+
};
|
|
32
|
+
const explainSpinner = createSpinner(strings.explain.run.action);
|
|
33
|
+
const explainResponse = await apiRequest(explainBase, "/cli/ai/explain", { method: "POST", body: { audit: explainPayload } }, explainKey);
|
|
34
|
+
succeedSpinner(explainSpinner, strings.explain.run.done(explainResponse.data.issues.length));
|
|
35
|
+
writeOutput("\n");
|
|
36
|
+
writeOutput(bold("AI Explanation") + "\n");
|
|
37
|
+
writeOutput(dim("\u2500".repeat(40)) + "\n");
|
|
38
|
+
for (const bullet of explainResponse.data.summary) {
|
|
39
|
+
writeOutput(` ${colorize("*", brand.cyan)} ${bullet}\n`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (explainErr) {
|
|
43
|
+
writeOutput(dim(`\n(${strings.explain.aiUnavailable(explainErr instanceof Error ? explainErr.message : String(explainErr))})\n`));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue filtering helpers for the audit command.
|
|
3
|
+
*/
|
|
4
|
+
import type { IssueLike } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Normalize issues from various API response formats.
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeIssues(issues: unknown): IssueLike[];
|
|
9
|
+
/**
|
|
10
|
+
* Filter issues by severity.
|
|
11
|
+
*/
|
|
12
|
+
export declare function filterBySeverity(issues: IssueLike[], severityFilter: string): IssueLike[];
|
|
13
|
+
/**
|
|
14
|
+
* Filter issues by category.
|
|
15
|
+
*/
|
|
16
|
+
export declare function filterByCategory(issues: IssueLike[], categoryFilter: string): IssueLike[];
|
|
17
|
+
//# sourceMappingURL=filters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../../src/commands/audit/filters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,CAS5D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EAAE,EACnB,cAAc,EAAE,MAAM,GACrB,SAAS,EAAE,CAab;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EAAE,EACnB,cAAc,EAAE,MAAM,GACrB,SAAS,EAAE,CASb"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Issue filtering helpers for the audit command.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Normalize issues from various API response formats.
|
|
6
|
+
*/
|
|
7
|
+
export function normalizeIssues(issues) {
|
|
8
|
+
if (Array.isArray(issues))
|
|
9
|
+
return issues;
|
|
10
|
+
if (issues && typeof issues === "object") {
|
|
11
|
+
const values = Object.values(issues);
|
|
12
|
+
return values.flatMap((value) => Array.isArray(value) ? value : []);
|
|
13
|
+
}
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Filter issues by severity.
|
|
18
|
+
*/
|
|
19
|
+
export function filterBySeverity(issues, severityFilter) {
|
|
20
|
+
const allowed = new Set(severityFilter.split(",").map((s) => s.trim().toLowerCase()));
|
|
21
|
+
// Map common aliases
|
|
22
|
+
if (allowed.has("error"))
|
|
23
|
+
allowed.add("critical");
|
|
24
|
+
if (allowed.has("warning"))
|
|
25
|
+
allowed.add("serious");
|
|
26
|
+
return issues.filter((issue) => {
|
|
27
|
+
const sev = issue.severity?.toLowerCase() || "info";
|
|
28
|
+
return allowed.has(sev);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Filter issues by category.
|
|
33
|
+
*/
|
|
34
|
+
export function filterByCategory(issues, categoryFilter) {
|
|
35
|
+
const allowed = new Set(categoryFilter.split(",").map((c) => c.trim().toLowerCase()));
|
|
36
|
+
return issues.filter((issue) => {
|
|
37
|
+
const cat = issue.category?.toLowerCase() || "";
|
|
38
|
+
return allowed.has(cat) || Array.from(allowed).some((a) => cat.includes(a));
|
|
39
|
+
});
|
|
40
|
+
}
|