@vertaaux/cli 0.2.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 +345 -0
- package/dist/auth/ci-token.d.ts +49 -0
- package/dist/auth/ci-token.d.ts.map +1 -0
- package/dist/auth/ci-token.js +83 -0
- package/dist/auth/device-flow.d.ts +66 -0
- package/dist/auth/device-flow.d.ts.map +1 -0
- package/dist/auth/device-flow.js +156 -0
- package/dist/auth/token-store.d.ts +53 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +78 -0
- package/dist/baseline/diff.d.ts +57 -0
- package/dist/baseline/diff.d.ts.map +1 -0
- package/dist/baseline/diff.js +152 -0
- package/dist/baseline/hash.d.ts +54 -0
- package/dist/baseline/hash.d.ts.map +1 -0
- package/dist/baseline/hash.js +66 -0
- package/dist/baseline/manager.d.ts +89 -0
- package/dist/baseline/manager.d.ts.map +1 -0
- package/dist/baseline/manager.js +157 -0
- package/dist/cache/index.d.ts +8 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +7 -0
- package/dist/cache/route-cache.d.ts +119 -0
- package/dist/cache/route-cache.d.ts.map +1 -0
- package/dist/cache/route-cache.js +213 -0
- package/dist/ci/changed-routes.d.ts +95 -0
- package/dist/ci/changed-routes.d.ts.map +1 -0
- package/dist/ci/changed-routes.js +304 -0
- package/dist/ci/github-api.d.ts +68 -0
- package/dist/ci/github-api.d.ts.map +1 -0
- package/dist/ci/github-api.js +138 -0
- package/dist/ci/gitlab-api.d.ts +75 -0
- package/dist/ci/gitlab-api.d.ts.map +1 -0
- package/dist/ci/gitlab-api.js +180 -0
- package/dist/ci/index.d.ts +6 -0
- package/dist/ci/index.d.ts.map +1 -0
- package/dist/ci/index.js +4 -0
- package/dist/commands/audit.d.ts +58 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +862 -0
- package/dist/commands/baseline.d.ts +22 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +210 -0
- package/dist/commands/comment.d.ts +14 -0
- package/dist/commands/comment.d.ts.map +1 -0
- package/dist/commands/comment.js +363 -0
- package/dist/commands/diff.d.ts +24 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +196 -0
- package/dist/commands/doctor.d.ts +58 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +338 -0
- package/dist/commands/download.d.ts +12 -0
- package/dist/commands/download.d.ts.map +1 -0
- package/dist/commands/download.js +183 -0
- package/dist/commands/explain.d.ts +62 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +302 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +212 -0
- package/dist/commands/login.d.ts +14 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +222 -0
- package/dist/commands/policy.d.ts +13 -0
- package/dist/commands/policy.d.ts.map +1 -0
- package/dist/commands/policy.js +347 -0
- package/dist/commands/upload.d.ts +12 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +158 -0
- package/dist/config/defaults.d.ts +21 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +49 -0
- package/dist/config/loader.d.ts +66 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +167 -0
- package/dist/config/schema.d.ts +55 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +6 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1090 -0
- package/dist/interactive/fix-wizard.d.ts +44 -0
- package/dist/interactive/fix-wizard.d.ts.map +1 -0
- package/dist/interactive/fix-wizard.js +286 -0
- package/dist/interactive/init-wizard.d.ts +32 -0
- package/dist/interactive/init-wizard.d.ts.map +1 -0
- package/dist/interactive/init-wizard.js +193 -0
- package/dist/interactive/prompts.d.ts +62 -0
- package/dist/interactive/prompts.d.ts.map +1 -0
- package/dist/interactive/prompts.js +78 -0
- package/dist/monorepo/detector.d.ts +70 -0
- package/dist/monorepo/detector.d.ts.map +1 -0
- package/dist/monorepo/detector.js +278 -0
- package/dist/monorepo/index.d.ts +9 -0
- package/dist/monorepo/index.d.ts.map +1 -0
- package/dist/monorepo/index.js +8 -0
- package/dist/monorepo/workspace.d.ts +142 -0
- package/dist/monorepo/workspace.d.ts.map +1 -0
- package/dist/monorepo/workspace.js +171 -0
- package/dist/output/envelope.d.ts +21 -0
- package/dist/output/envelope.d.ts.map +1 -0
- package/dist/output/envelope.js +27 -0
- package/dist/output/factory.d.ts +73 -0
- package/dist/output/factory.d.ts.map +1 -0
- package/dist/output/factory.js +60 -0
- package/dist/output/formats.d.ts +11 -0
- package/dist/output/formats.d.ts.map +1 -0
- package/dist/output/formats.js +41 -0
- package/dist/output/html.d.ts +45 -0
- package/dist/output/html.d.ts.map +1 -0
- package/dist/output/html.js +607 -0
- package/dist/output/human.d.ts +41 -0
- package/dist/output/human.d.ts.map +1 -0
- package/dist/output/human.js +274 -0
- package/dist/output/json.d.ts +42 -0
- package/dist/output/json.d.ts.map +1 -0
- package/dist/output/json.js +37 -0
- package/dist/output/junit.d.ts +56 -0
- package/dist/output/junit.d.ts.map +1 -0
- package/dist/output/junit.js +135 -0
- package/dist/output/markdown.d.ts +77 -0
- package/dist/output/markdown.d.ts.map +1 -0
- package/dist/output/markdown.js +411 -0
- package/dist/output/sarif.d.ts +160 -0
- package/dist/output/sarif.d.ts.map +1 -0
- package/dist/output/sarif.js +207 -0
- package/dist/policy/evaluator.d.ts +111 -0
- package/dist/policy/evaluator.d.ts.map +1 -0
- package/dist/policy/evaluator.js +362 -0
- package/dist/policy/index.d.ts +15 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +11 -0
- package/dist/policy/loader.d.ts +97 -0
- package/dist/policy/loader.d.ts.map +1 -0
- package/dist/policy/loader.js +281 -0
- package/dist/policy/schema.d.ts +297 -0
- package/dist/policy/schema.d.ts.map +1 -0
- package/dist/policy/schema.js +230 -0
- package/dist/quality-gate/evaluator.d.ts +58 -0
- package/dist/quality-gate/evaluator.d.ts.map +1 -0
- package/dist/quality-gate/evaluator.js +274 -0
- package/dist/quality-gate/index.d.ts +10 -0
- package/dist/quality-gate/index.d.ts.map +1 -0
- package/dist/quality-gate/index.js +7 -0
- package/dist/quality-gate/types.d.ts +103 -0
- package/dist/quality-gate/types.d.ts.map +1 -0
- package/dist/quality-gate/types.js +23 -0
- package/dist/templates/azure-devops.d.ts +25 -0
- package/dist/templates/azure-devops.d.ts.map +1 -0
- package/dist/templates/azure-devops.js +109 -0
- package/dist/templates/circleci.d.ts +28 -0
- package/dist/templates/circleci.d.ts.map +1 -0
- package/dist/templates/circleci.js +86 -0
- package/dist/templates/github-actions.d.ts +81 -0
- package/dist/templates/github-actions.d.ts.map +1 -0
- package/dist/templates/github-actions.js +393 -0
- package/dist/templates/gitlab-ci.d.ts +26 -0
- package/dist/templates/gitlab-ci.d.ts.map +1 -0
- package/dist/templates/gitlab-ci.js +70 -0
- package/dist/templates/index.d.ts +72 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +112 -0
- package/dist/templates/jenkins.d.ts +26 -0
- package/dist/templates/jenkins.d.ts.map +1 -0
- package/dist/templates/jenkins.js +110 -0
- package/dist/ui/banner.d.ts +31 -0
- package/dist/ui/banner.d.ts.map +1 -0
- package/dist/ui/banner.js +84 -0
- package/dist/ui/diagnostics.d.ts +39 -0
- package/dist/ui/diagnostics.d.ts.map +1 -0
- package/dist/ui/diagnostics.js +153 -0
- package/dist/ui/spinner.d.ts +61 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +101 -0
- package/dist/ui/table.d.ts +63 -0
- package/dist/ui/table.d.ts.map +1 -0
- package/dist/ui/table.js +236 -0
- package/dist/utils/client.d.ts +82 -0
- package/dist/utils/client.d.ts.map +1 -0
- package/dist/utils/client.js +128 -0
- package/dist/utils/detect-env.d.ts +59 -0
- package/dist/utils/detect-env.d.ts.map +1 -0
- package/dist/utils/detect-env.js +115 -0
- package/dist/utils/exit-codes.d.ts +47 -0
- package/dist/utils/exit-codes.d.ts.map +1 -0
- package/dist/utils/exit-codes.js +61 -0
- package/dist/utils/logger.d.ts +87 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +185 -0
- package/dist/utils/sanitize.d.ts +36 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +64 -0
- package/dist/utils/validators.d.ts +41 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +123 -0
- package/package.json +63 -0
- package/schemas/vertaaux.config.schema.json +103 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure token storage for VertaaUX CLI.
|
|
3
|
+
*
|
|
4
|
+
* Tokens are stored in ~/.vertaaux/credentials.json with restrictive permissions.
|
|
5
|
+
* This is separate from project config - tokens are user-scoped, not project-scoped.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Token data structure.
|
|
9
|
+
*/
|
|
10
|
+
export interface TokenData {
|
|
11
|
+
/** OAuth access token */
|
|
12
|
+
accessToken: string;
|
|
13
|
+
/** OAuth refresh token (optional for CI tokens) */
|
|
14
|
+
refreshToken?: string;
|
|
15
|
+
/** Token expiration timestamp (ISO 8601) */
|
|
16
|
+
expiresAt?: string;
|
|
17
|
+
/** Token type: device (interactive) or ci (API key) */
|
|
18
|
+
type: "device" | "ci";
|
|
19
|
+
/** When token was saved */
|
|
20
|
+
savedAt: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get the credentials file path.
|
|
24
|
+
* Uses ~/.vertaaux/credentials.json
|
|
25
|
+
*/
|
|
26
|
+
export declare function getCredentialsPath(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Save token data to credentials file.
|
|
29
|
+
*
|
|
30
|
+
* Creates ~/.vertaaux directory if needed.
|
|
31
|
+
* Writes with restrictive permissions (0o600).
|
|
32
|
+
*
|
|
33
|
+
* @param token - Token data to save
|
|
34
|
+
*/
|
|
35
|
+
export declare function saveToken(token: TokenData): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Load token data from credentials file.
|
|
38
|
+
*
|
|
39
|
+
* @returns Token data or null if file doesn't exist
|
|
40
|
+
*/
|
|
41
|
+
export declare function loadToken(): Promise<TokenData | null>;
|
|
42
|
+
/**
|
|
43
|
+
* Clear stored token by deleting credentials file.
|
|
44
|
+
*/
|
|
45
|
+
export declare function clearToken(): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Check if token is expired.
|
|
48
|
+
*
|
|
49
|
+
* @param token - Token data to check
|
|
50
|
+
* @returns true if token is expired or will expire within 5 minutes
|
|
51
|
+
*/
|
|
52
|
+
export declare function isTokenExpired(token: TokenData): boolean;
|
|
53
|
+
//# sourceMappingURL=token-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../../src/auth/token-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/D;AAED;;;;GAIG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAa3D;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAMhD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAUxD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure token storage for VertaaUX CLI.
|
|
3
|
+
*
|
|
4
|
+
* Tokens are stored in ~/.vertaaux/credentials.json with restrictive permissions.
|
|
5
|
+
* This is separate from project config - tokens are user-scoped, not project-scoped.
|
|
6
|
+
*/
|
|
7
|
+
import { readFile, writeFile, mkdir, unlink } from "fs/promises";
|
|
8
|
+
import { existsSync } from "fs";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import { join, dirname } from "path";
|
|
11
|
+
/**
|
|
12
|
+
* Get the credentials file path.
|
|
13
|
+
* Uses ~/.vertaaux/credentials.json
|
|
14
|
+
*/
|
|
15
|
+
export function getCredentialsPath() {
|
|
16
|
+
return join(homedir(), ".vertaaux", "credentials.json");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Save token data to credentials file.
|
|
20
|
+
*
|
|
21
|
+
* Creates ~/.vertaaux directory if needed.
|
|
22
|
+
* Writes with restrictive permissions (0o600).
|
|
23
|
+
*
|
|
24
|
+
* @param token - Token data to save
|
|
25
|
+
*/
|
|
26
|
+
export async function saveToken(token) {
|
|
27
|
+
const credPath = getCredentialsPath();
|
|
28
|
+
const dir = dirname(credPath);
|
|
29
|
+
// Create directory if needed
|
|
30
|
+
if (!existsSync(dir)) {
|
|
31
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
32
|
+
}
|
|
33
|
+
// Write token with restrictive permissions
|
|
34
|
+
const content = JSON.stringify(token, null, 2);
|
|
35
|
+
await writeFile(credPath, content + "\n", { encoding: "utf-8", mode: 0o600 });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Load token data from credentials file.
|
|
39
|
+
*
|
|
40
|
+
* @returns Token data or null if file doesn't exist
|
|
41
|
+
*/
|
|
42
|
+
export async function loadToken() {
|
|
43
|
+
const credPath = getCredentialsPath();
|
|
44
|
+
if (!existsSync(credPath)) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const content = await readFile(credPath, "utf-8");
|
|
49
|
+
return JSON.parse(content);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Clear stored token by deleting credentials file.
|
|
57
|
+
*/
|
|
58
|
+
export async function clearToken() {
|
|
59
|
+
const credPath = getCredentialsPath();
|
|
60
|
+
if (existsSync(credPath)) {
|
|
61
|
+
await unlink(credPath);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if token is expired.
|
|
66
|
+
*
|
|
67
|
+
* @param token - Token data to check
|
|
68
|
+
* @returns true if token is expired or will expire within 5 minutes
|
|
69
|
+
*/
|
|
70
|
+
export function isTokenExpired(token) {
|
|
71
|
+
if (!token.expiresAt) {
|
|
72
|
+
return false; // CI tokens don't expire
|
|
73
|
+
}
|
|
74
|
+
const expiresAt = new Date(token.expiresAt);
|
|
75
|
+
const now = new Date();
|
|
76
|
+
const fiveMinutes = 5 * 60 * 1000;
|
|
77
|
+
return expiresAt.getTime() - now.getTime() < fiveMinutes;
|
|
78
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff computation between audit runs.
|
|
3
|
+
*
|
|
4
|
+
* Compares current audit results against baseline or previous audit.
|
|
5
|
+
* Shows three categories:
|
|
6
|
+
* - New: Issues in current but not in baseline
|
|
7
|
+
* - Fixed: Issues in baseline but not in current
|
|
8
|
+
* - Present: Issues in both current and baseline
|
|
9
|
+
*/
|
|
10
|
+
import { type Issue } from "./hash.js";
|
|
11
|
+
import type { BaselineFile, BaselineIssue } from "./manager.js";
|
|
12
|
+
/**
|
|
13
|
+
* Diff result with categorized issues.
|
|
14
|
+
*/
|
|
15
|
+
export interface DiffResult {
|
|
16
|
+
/** New issues not in baseline */
|
|
17
|
+
new: Issue[];
|
|
18
|
+
/** Issues in baseline but fixed in current */
|
|
19
|
+
fixed: BaselineIssue[];
|
|
20
|
+
/** Issues still present (in both) */
|
|
21
|
+
present: Issue[];
|
|
22
|
+
/** Summary counts */
|
|
23
|
+
summary: {
|
|
24
|
+
newCount: number;
|
|
25
|
+
fixedCount: number;
|
|
26
|
+
presentCount: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Compute diff between current issues and baseline.
|
|
31
|
+
*
|
|
32
|
+
* @param currentIssues - Issues from current audit
|
|
33
|
+
* @param baseline - Baseline to compare against
|
|
34
|
+
* @returns Diff result with new/fixed/present categories
|
|
35
|
+
*/
|
|
36
|
+
export declare function computeDiff(currentIssues: Issue[], baseline: BaselineFile): DiffResult;
|
|
37
|
+
/**
|
|
38
|
+
* Format diff result for human-readable output.
|
|
39
|
+
*
|
|
40
|
+
* Uses colors:
|
|
41
|
+
* - New issues: red
|
|
42
|
+
* - Fixed issues: green
|
|
43
|
+
* - Still present: dim
|
|
44
|
+
*
|
|
45
|
+
* @param diff - Diff result to format
|
|
46
|
+
* @param verbose - Show all present issues (default: false)
|
|
47
|
+
* @returns Formatted string for console output
|
|
48
|
+
*/
|
|
49
|
+
export declare function formatDiffHuman(diff: DiffResult, verbose?: boolean): string;
|
|
50
|
+
/**
|
|
51
|
+
* Format diff result as JSON.
|
|
52
|
+
*
|
|
53
|
+
* @param diff - Diff result to format
|
|
54
|
+
* @returns JSON-formatted string
|
|
55
|
+
*/
|
|
56
|
+
export declare function formatDiffJson(diff: DiffResult): string;
|
|
57
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +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;AA2CD;;;;;;;;;;;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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Diff computation between audit runs.
|
|
3
|
+
*
|
|
4
|
+
* Compares current audit results against baseline or previous audit.
|
|
5
|
+
* Shows three categories:
|
|
6
|
+
* - New: Issues in current but not in baseline
|
|
7
|
+
* - Fixed: Issues in baseline but not in current
|
|
8
|
+
* - Present: Issues in both current and baseline
|
|
9
|
+
*/
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import { generateFingerprint } from "./hash.js";
|
|
12
|
+
/**
|
|
13
|
+
* Compute diff between current issues and baseline.
|
|
14
|
+
*
|
|
15
|
+
* @param currentIssues - Issues from current audit
|
|
16
|
+
* @param baseline - Baseline to compare against
|
|
17
|
+
* @returns Diff result with new/fixed/present categories
|
|
18
|
+
*/
|
|
19
|
+
export function computeDiff(currentIssues, baseline) {
|
|
20
|
+
// Build set of baseline fingerprints for fast lookup
|
|
21
|
+
const baselineFingerprints = new Set(baseline.issues.map((issue) => issue.fingerprint));
|
|
22
|
+
// Build map of current fingerprints to issues
|
|
23
|
+
const currentByFingerprint = new Map();
|
|
24
|
+
for (const issue of currentIssues) {
|
|
25
|
+
const fingerprint = generateFingerprint(issue);
|
|
26
|
+
currentByFingerprint.set(fingerprint, issue);
|
|
27
|
+
}
|
|
28
|
+
// Categorize issues
|
|
29
|
+
const newIssues = [];
|
|
30
|
+
const presentIssues = [];
|
|
31
|
+
for (const [fingerprint, issue] of currentByFingerprint) {
|
|
32
|
+
if (baselineFingerprints.has(fingerprint)) {
|
|
33
|
+
presentIssues.push(issue);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
newIssues.push(issue);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Find fixed issues (in baseline but not in current)
|
|
40
|
+
const fixedIssues = [];
|
|
41
|
+
for (const baselineIssue of baseline.issues) {
|
|
42
|
+
if (!currentByFingerprint.has(baselineIssue.fingerprint)) {
|
|
43
|
+
fixedIssues.push(baselineIssue);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
new: newIssues,
|
|
48
|
+
fixed: fixedIssues,
|
|
49
|
+
present: presentIssues,
|
|
50
|
+
summary: {
|
|
51
|
+
newCount: newIssues.length,
|
|
52
|
+
fixedCount: fixedIssues.length,
|
|
53
|
+
presentCount: presentIssues.length,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get rule ID from an issue, checking multiple field names.
|
|
59
|
+
*/
|
|
60
|
+
function getRuleId(issue) {
|
|
61
|
+
return issue.ruleId || issue.rule_id || issue.id || "unknown";
|
|
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
|
+
/**
|
|
83
|
+
* Format issue line for display.
|
|
84
|
+
*/
|
|
85
|
+
function formatIssueLine(issue) {
|
|
86
|
+
const ruleId = "ruleId" in issue ? issue.ruleId : getRuleId(issue);
|
|
87
|
+
const description = "description" in issue
|
|
88
|
+
? issue.description
|
|
89
|
+
: issue.description || issue.title || "";
|
|
90
|
+
const severity = issue.severity || "info";
|
|
91
|
+
return `${formatSeverityBadge(severity)} ${ruleId}: ${description}`;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Format diff result for human-readable output.
|
|
95
|
+
*
|
|
96
|
+
* Uses colors:
|
|
97
|
+
* - New issues: red
|
|
98
|
+
* - Fixed issues: green
|
|
99
|
+
* - Still present: dim
|
|
100
|
+
*
|
|
101
|
+
* @param diff - Diff result to format
|
|
102
|
+
* @param verbose - Show all present issues (default: false)
|
|
103
|
+
* @returns Formatted string for console output
|
|
104
|
+
*/
|
|
105
|
+
export function formatDiffHuman(diff, verbose = false) {
|
|
106
|
+
const lines = [];
|
|
107
|
+
// New issues section (red)
|
|
108
|
+
lines.push(chalk.red.bold(`NEW ISSUES (${diff.summary.newCount})`));
|
|
109
|
+
if (diff.new.length === 0) {
|
|
110
|
+
lines.push(chalk.dim(" No new issues"));
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
for (const issue of diff.new) {
|
|
114
|
+
lines.push(` ${formatIssueLine(issue)}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
lines.push("");
|
|
118
|
+
// Fixed issues section (green)
|
|
119
|
+
lines.push(chalk.green.bold(`FIXED (${diff.summary.fixedCount})`));
|
|
120
|
+
if (diff.fixed.length === 0) {
|
|
121
|
+
lines.push(chalk.dim(" No issues fixed"));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
for (const issue of diff.fixed) {
|
|
125
|
+
lines.push(` ${formatIssueLine(issue)}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
lines.push("");
|
|
129
|
+
// Still present section (dim)
|
|
130
|
+
lines.push(chalk.dim.bold(`STILL PRESENT (${diff.summary.presentCount})`));
|
|
131
|
+
if (diff.present.length === 0) {
|
|
132
|
+
lines.push(chalk.dim(" No baselined issues remain"));
|
|
133
|
+
}
|
|
134
|
+
else if (verbose) {
|
|
135
|
+
for (const issue of diff.present) {
|
|
136
|
+
lines.push(chalk.dim(` ${formatIssueLine(issue)}`));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
lines.push(chalk.dim(" (use --verbose to show all)"));
|
|
141
|
+
}
|
|
142
|
+
return lines.join("\n");
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Format diff result as JSON.
|
|
146
|
+
*
|
|
147
|
+
* @param diff - Diff result to format
|
|
148
|
+
* @returns JSON-formatted string
|
|
149
|
+
*/
|
|
150
|
+
export function formatDiffJson(diff) {
|
|
151
|
+
return JSON.stringify(diff, null, 2);
|
|
152
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable fingerprint generation for baseline matching.
|
|
3
|
+
*
|
|
4
|
+
* Generates hash-based fingerprints that remain stable across:
|
|
5
|
+
* - Code reformatting
|
|
6
|
+
* - Line number changes
|
|
7
|
+
* - Dynamic data attribute changes
|
|
8
|
+
*
|
|
9
|
+
* Matches SDK finding ID format for cross-surface consistency (CROSS-01).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Issue type from audit results.
|
|
13
|
+
*/
|
|
14
|
+
export interface Issue {
|
|
15
|
+
id?: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
severity?: string;
|
|
18
|
+
category?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
recommendation?: string;
|
|
21
|
+
recommended_fix?: string;
|
|
22
|
+
wcag_reference?: string;
|
|
23
|
+
selector?: string;
|
|
24
|
+
ruleId?: string;
|
|
25
|
+
rule_id?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Normalize a CSS selector for stable fingerprinting.
|
|
29
|
+
*
|
|
30
|
+
* Removes dynamic/unstable parts:
|
|
31
|
+
* - data-* attributes (often contain generated IDs)
|
|
32
|
+
* - :nth-child indices (change with DOM order)
|
|
33
|
+
* - Extra whitespace
|
|
34
|
+
*
|
|
35
|
+
* @param selector - Raw CSS selector from audit
|
|
36
|
+
* @returns Normalized selector for hashing
|
|
37
|
+
*/
|
|
38
|
+
export declare function normalizeSelector(selector: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Generate a stable fingerprint for an issue.
|
|
41
|
+
*
|
|
42
|
+
* Hash is based on:
|
|
43
|
+
* - Rule ID (type of issue)
|
|
44
|
+
* - Normalized selector (where the issue is)
|
|
45
|
+
* - First 50 chars of description (what the issue is)
|
|
46
|
+
*
|
|
47
|
+
* This matches SDK finding ID format: {ruleId}:{hash16}
|
|
48
|
+
* for cross-surface consistency (CROSS-01).
|
|
49
|
+
*
|
|
50
|
+
* @param issue - Issue from audit results
|
|
51
|
+
* @returns 16-character hex fingerprint
|
|
52
|
+
*/
|
|
53
|
+
export declare function generateFingerprint(issue: Issue): string;
|
|
54
|
+
//# sourceMappingURL=hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/baseline/hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAe1D;AASD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAWxD"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable fingerprint generation for baseline matching.
|
|
3
|
+
*
|
|
4
|
+
* Generates hash-based fingerprints that remain stable across:
|
|
5
|
+
* - Code reformatting
|
|
6
|
+
* - Line number changes
|
|
7
|
+
* - Dynamic data attribute changes
|
|
8
|
+
*
|
|
9
|
+
* Matches SDK finding ID format for cross-surface consistency (CROSS-01).
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from "crypto";
|
|
12
|
+
/**
|
|
13
|
+
* Normalize a CSS selector for stable fingerprinting.
|
|
14
|
+
*
|
|
15
|
+
* Removes dynamic/unstable parts:
|
|
16
|
+
* - data-* attributes (often contain generated IDs)
|
|
17
|
+
* - :nth-child indices (change with DOM order)
|
|
18
|
+
* - Extra whitespace
|
|
19
|
+
*
|
|
20
|
+
* @param selector - Raw CSS selector from audit
|
|
21
|
+
* @returns Normalized selector for hashing
|
|
22
|
+
*/
|
|
23
|
+
export function normalizeSelector(selector) {
|
|
24
|
+
if (!selector)
|
|
25
|
+
return "";
|
|
26
|
+
return (selector
|
|
27
|
+
// Remove data attributes: [data-testid="foo"], [data-v-abc123], etc.
|
|
28
|
+
.replace(/\[data-[^\]]+\]/g, "")
|
|
29
|
+
// Remove nth-child indices: :nth-child(2), :nth-of-type(5)
|
|
30
|
+
.replace(/:nth-(?:child|of-type)\(\d+\)/g, "")
|
|
31
|
+
// Normalize whitespace: collapse multiple spaces, trim
|
|
32
|
+
.replace(/\s+/g, " ")
|
|
33
|
+
.trim()
|
|
34
|
+
// Lowercase for consistency
|
|
35
|
+
.toLowerCase());
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get the rule ID from an issue, checking multiple field names.
|
|
39
|
+
*/
|
|
40
|
+
function getRuleId(issue) {
|
|
41
|
+
return issue.ruleId || issue.rule_id || issue.id || "";
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Generate a stable fingerprint for an issue.
|
|
45
|
+
*
|
|
46
|
+
* Hash is based on:
|
|
47
|
+
* - Rule ID (type of issue)
|
|
48
|
+
* - Normalized selector (where the issue is)
|
|
49
|
+
* - First 50 chars of description (what the issue is)
|
|
50
|
+
*
|
|
51
|
+
* This matches SDK finding ID format: {ruleId}:{hash16}
|
|
52
|
+
* for cross-surface consistency (CROSS-01).
|
|
53
|
+
*
|
|
54
|
+
* @param issue - Issue from audit results
|
|
55
|
+
* @returns 16-character hex fingerprint
|
|
56
|
+
*/
|
|
57
|
+
export function generateFingerprint(issue) {
|
|
58
|
+
const ruleId = getRuleId(issue);
|
|
59
|
+
const normalizedSelector = normalizeSelector(issue.selector || "");
|
|
60
|
+
const descriptionPrefix = (issue.description || "").slice(0, 50);
|
|
61
|
+
// Combine fields for hashing
|
|
62
|
+
const input = `${ruleId}|${normalizedSelector}|${descriptionPrefix}`;
|
|
63
|
+
// SHA-256 hash, take first 16 hex chars
|
|
64
|
+
const hash = createHash("sha256").update(input).digest("hex");
|
|
65
|
+
return hash.slice(0, 16);
|
|
66
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline file management for tracking technical debt.
|
|
3
|
+
*
|
|
4
|
+
* Enables teams to:
|
|
5
|
+
* - Create baselines from audit results
|
|
6
|
+
* - Add individual issues to baseline (ignore)
|
|
7
|
+
* - Load and save baseline files
|
|
8
|
+
*
|
|
9
|
+
* Baseline is stored in .vertaaux/baseline.json and committed to git.
|
|
10
|
+
*/
|
|
11
|
+
import { type Issue } from "./hash.js";
|
|
12
|
+
/**
|
|
13
|
+
* Current baseline file format version.
|
|
14
|
+
*/
|
|
15
|
+
export declare const BASELINE_VERSION = 1;
|
|
16
|
+
/**
|
|
17
|
+
* Default baseline file path.
|
|
18
|
+
*/
|
|
19
|
+
export declare const DEFAULT_BASELINE_PATH = ".vertaaux/baseline.json";
|
|
20
|
+
/**
|
|
21
|
+
* Issue stored in baseline with metadata.
|
|
22
|
+
*/
|
|
23
|
+
export interface BaselineIssue {
|
|
24
|
+
/** Stable fingerprint for matching */
|
|
25
|
+
fingerprint: string;
|
|
26
|
+
/** Rule/issue type ID */
|
|
27
|
+
ruleId: string;
|
|
28
|
+
/** Severity: error, warning, info */
|
|
29
|
+
severity: string;
|
|
30
|
+
/** Category: accessibility, ux, performance, etc. */
|
|
31
|
+
category: string;
|
|
32
|
+
/** Issue description */
|
|
33
|
+
description: string;
|
|
34
|
+
/** CSS selector where issue occurs */
|
|
35
|
+
selector?: string;
|
|
36
|
+
/** Reason for baselining (optional) */
|
|
37
|
+
reason?: string;
|
|
38
|
+
/** When issue was added to baseline */
|
|
39
|
+
baselinedAt: string;
|
|
40
|
+
/** Who added the issue (from git config) */
|
|
41
|
+
baselinedBy?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Baseline file structure.
|
|
45
|
+
*/
|
|
46
|
+
export interface BaselineFile {
|
|
47
|
+
/** File format version */
|
|
48
|
+
version: number;
|
|
49
|
+
/** When baseline was first created */
|
|
50
|
+
created: string;
|
|
51
|
+
/** When baseline was last updated */
|
|
52
|
+
updated: string;
|
|
53
|
+
/** URL that was audited */
|
|
54
|
+
url: string;
|
|
55
|
+
/** Baselined issues */
|
|
56
|
+
issues: BaselineIssue[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Load a baseline file from disk.
|
|
60
|
+
*
|
|
61
|
+
* @param path - Path to baseline file (default: .vertaaux/baseline.json)
|
|
62
|
+
* @returns Baseline file contents or null if file doesn't exist
|
|
63
|
+
*/
|
|
64
|
+
export declare function loadBaseline(path?: string): Promise<BaselineFile | null>;
|
|
65
|
+
/**
|
|
66
|
+
* Save a baseline file to disk.
|
|
67
|
+
*
|
|
68
|
+
* @param baseline - Baseline file contents
|
|
69
|
+
* @param path - Path to baseline file (default: .vertaaux/baseline.json)
|
|
70
|
+
*/
|
|
71
|
+
export declare function saveBaseline(baseline: BaselineFile, path?: string): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Create a new baseline from audit issues.
|
|
74
|
+
*
|
|
75
|
+
* @param issues - Issues from audit results
|
|
76
|
+
* @param url - URL that was audited
|
|
77
|
+
* @returns New baseline file
|
|
78
|
+
*/
|
|
79
|
+
export declare function createBaseline(issues: Issue[], url: string): BaselineFile;
|
|
80
|
+
/**
|
|
81
|
+
* Add an issue to an existing baseline.
|
|
82
|
+
*
|
|
83
|
+
* @param baseline - Existing baseline file
|
|
84
|
+
* @param issue - Issue to add
|
|
85
|
+
* @param reason - Optional reason for baselining
|
|
86
|
+
* @returns Updated baseline file
|
|
87
|
+
*/
|
|
88
|
+
export declare function addToBaseline(baseline: BaselineFile, issue: Issue, reason?: string): BaselineFile;
|
|
89
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/baseline/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,EAAuB,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;GAEG;AACH,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,yBAAyB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,uBAAuB;IACvB,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AA0BD;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,IAAI,GAAE,MAA8B,GACnC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAwB9B;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,YAAY,EACtB,IAAI,GAAE,MAA8B,GACnC,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAsBzE;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,KAAK,EACZ,MAAM,CAAC,EAAE,MAAM,GACd,YAAY,CAoCd"}
|