@quantracode/vibecheck 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/index.d.ts +0 -2
- package/dist/index.js +7902 -8
- package/package.json +13 -7
- package/dist/__tests__/cli.test.d.ts +0 -2
- package/dist/__tests__/cli.test.d.ts.map +0 -1
- package/dist/__tests__/cli.test.js +0 -243
- package/dist/__tests__/fixtures/safe-app/app/api/users/route.js +0 -36
- package/dist/__tests__/fixtures/vulnerable-app/app/api/users/route.js +0 -28
- package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts +0 -4
- package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts.map +0 -1
- package/dist/__tests__/fixtures/vulnerable-app/lib/config.js +0 -6
- package/dist/__tests__/scanners/env-config.test.d.ts +0 -2
- package/dist/__tests__/scanners/env-config.test.d.ts.map +0 -1
- package/dist/__tests__/scanners/env-config.test.js +0 -142
- package/dist/__tests__/scanners/nextjs-middleware.test.d.ts +0 -2
- package/dist/__tests__/scanners/nextjs-middleware.test.d.ts.map +0 -1
- package/dist/__tests__/scanners/nextjs-middleware.test.js +0 -193
- package/dist/__tests__/scanners/scanner-packs.test.d.ts +0 -2
- package/dist/__tests__/scanners/scanner-packs.test.d.ts.map +0 -1
- package/dist/__tests__/scanners/scanner-packs.test.js +0 -126
- package/dist/__tests__/scanners/unused-security-imports.test.d.ts +0 -2
- package/dist/__tests__/scanners/unused-security-imports.test.d.ts.map +0 -1
- package/dist/__tests__/scanners/unused-security-imports.test.js +0 -145
- package/dist/commands/demo-artifact.d.ts +0 -7
- package/dist/commands/demo-artifact.d.ts.map +0 -1
- package/dist/commands/demo-artifact.js +0 -322
- package/dist/commands/evaluate.d.ts +0 -30
- package/dist/commands/evaluate.d.ts.map +0 -1
- package/dist/commands/evaluate.js +0 -258
- package/dist/commands/explain.d.ts +0 -12
- package/dist/commands/explain.d.ts.map +0 -1
- package/dist/commands/explain.js +0 -214
- package/dist/commands/index.d.ts +0 -7
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js +0 -6
- package/dist/commands/intent.d.ts +0 -21
- package/dist/commands/intent.d.ts.map +0 -1
- package/dist/commands/intent.js +0 -192
- package/dist/commands/scan.d.ts +0 -44
- package/dist/commands/scan.d.ts.map +0 -1
- package/dist/commands/scan.js +0 -497
- package/dist/commands/waivers.d.ts +0 -30
- package/dist/commands/waivers.d.ts.map +0 -1
- package/dist/commands/waivers.js +0 -249
- package/dist/index.d.ts.map +0 -1
- package/dist/phase3/index.d.ts +0 -11
- package/dist/phase3/index.d.ts.map +0 -1
- package/dist/phase3/index.js +0 -12
- package/dist/phase3/intent-miner.d.ts +0 -32
- package/dist/phase3/intent-miner.d.ts.map +0 -1
- package/dist/phase3/intent-miner.js +0 -323
- package/dist/phase3/proof-trace-builder.d.ts +0 -42
- package/dist/phase3/proof-trace-builder.d.ts.map +0 -1
- package/dist/phase3/proof-trace-builder.js +0 -441
- package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts +0 -15
- package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts.map +0 -1
- package/dist/phase3/scanners/auth-by-ui-server-gap.js +0 -237
- package/dist/phase3/scanners/comment-claim-unproven.d.ts +0 -14
- package/dist/phase3/scanners/comment-claim-unproven.d.ts.map +0 -1
- package/dist/phase3/scanners/comment-claim-unproven.js +0 -161
- package/dist/phase3/scanners/index.d.ts +0 -31
- package/dist/phase3/scanners/index.d.ts.map +0 -1
- package/dist/phase3/scanners/index.js +0 -40
- package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts +0 -14
- package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts.map +0 -1
- package/dist/phase3/scanners/middleware-assumed-not-matching.js +0 -172
- package/dist/phase3/scanners/validation-claimed-missing.d.ts +0 -15
- package/dist/phase3/scanners/validation-claimed-missing.d.ts.map +0 -1
- package/dist/phase3/scanners/validation-claimed-missing.js +0 -204
- package/dist/scanners/abuse/compute-abuse.d.ts +0 -20
- package/dist/scanners/abuse/compute-abuse.d.ts.map +0 -1
- package/dist/scanners/abuse/compute-abuse.js +0 -509
- package/dist/scanners/abuse/index.d.ts +0 -12
- package/dist/scanners/abuse/index.d.ts.map +0 -1
- package/dist/scanners/abuse/index.js +0 -15
- package/dist/scanners/auth/index.d.ts +0 -5
- package/dist/scanners/auth/index.d.ts.map +0 -1
- package/dist/scanners/auth/index.js +0 -10
- package/dist/scanners/auth/middleware-gap.d.ts +0 -22
- package/dist/scanners/auth/middleware-gap.d.ts.map +0 -1
- package/dist/scanners/auth/middleware-gap.js +0 -203
- package/dist/scanners/auth/unprotected-api-route.d.ts +0 -12
- package/dist/scanners/auth/unprotected-api-route.d.ts.map +0 -1
- package/dist/scanners/auth/unprotected-api-route.js +0 -126
- package/dist/scanners/config/index.d.ts +0 -5
- package/dist/scanners/config/index.d.ts.map +0 -1
- package/dist/scanners/config/index.js +0 -10
- package/dist/scanners/config/insecure-defaults.d.ts +0 -12
- package/dist/scanners/config/insecure-defaults.d.ts.map +0 -1
- package/dist/scanners/config/insecure-defaults.js +0 -77
- package/dist/scanners/config/undocumented-env.d.ts +0 -24
- package/dist/scanners/config/undocumented-env.d.ts.map +0 -1
- package/dist/scanners/config/undocumented-env.js +0 -159
- package/dist/scanners/crypto/index.d.ts +0 -6
- package/dist/scanners/crypto/index.d.ts.map +0 -1
- package/dist/scanners/crypto/index.js +0 -11
- package/dist/scanners/crypto/jwt-decode-unverified.d.ts +0 -14
- package/dist/scanners/crypto/jwt-decode-unverified.d.ts.map +0 -1
- package/dist/scanners/crypto/jwt-decode-unverified.js +0 -87
- package/dist/scanners/crypto/math-random-tokens.d.ts +0 -13
- package/dist/scanners/crypto/math-random-tokens.d.ts.map +0 -1
- package/dist/scanners/crypto/math-random-tokens.js +0 -80
- package/dist/scanners/crypto/weak-hashing.d.ts +0 -11
- package/dist/scanners/crypto/weak-hashing.d.ts.map +0 -1
- package/dist/scanners/crypto/weak-hashing.js +0 -95
- package/dist/scanners/env-config.d.ts +0 -24
- package/dist/scanners/env-config.d.ts.map +0 -1
- package/dist/scanners/env-config.js +0 -164
- package/dist/scanners/hallucinations/index.d.ts +0 -4
- package/dist/scanners/hallucinations/index.d.ts.map +0 -1
- package/dist/scanners/hallucinations/index.js +0 -8
- package/dist/scanners/hallucinations/unused-security-imports.d.ts +0 -36
- package/dist/scanners/hallucinations/unused-security-imports.d.ts.map +0 -1
- package/dist/scanners/hallucinations/unused-security-imports.js +0 -309
- package/dist/scanners/helpers/ast-helpers.d.ts +0 -6
- package/dist/scanners/helpers/ast-helpers.d.ts.map +0 -1
- package/dist/scanners/helpers/ast-helpers.js +0 -945
- package/dist/scanners/helpers/context-builder.d.ts +0 -17
- package/dist/scanners/helpers/context-builder.d.ts.map +0 -1
- package/dist/scanners/helpers/context-builder.js +0 -148
- package/dist/scanners/helpers/index.d.ts +0 -3
- package/dist/scanners/helpers/index.d.ts.map +0 -1
- package/dist/scanners/helpers/index.js +0 -2
- package/dist/scanners/index.d.ts +0 -30
- package/dist/scanners/index.d.ts.map +0 -1
- package/dist/scanners/index.js +0 -102
- package/dist/scanners/middleware/index.d.ts +0 -4
- package/dist/scanners/middleware/index.d.ts.map +0 -1
- package/dist/scanners/middleware/index.js +0 -7
- package/dist/scanners/middleware/missing-rate-limit.d.ts +0 -13
- package/dist/scanners/middleware/missing-rate-limit.d.ts.map +0 -1
- package/dist/scanners/middleware/missing-rate-limit.js +0 -140
- package/dist/scanners/network/cors-misconfiguration.d.ts +0 -14
- package/dist/scanners/network/cors-misconfiguration.d.ts.map +0 -1
- package/dist/scanners/network/cors-misconfiguration.js +0 -89
- package/dist/scanners/network/index.d.ts +0 -7
- package/dist/scanners/network/index.d.ts.map +0 -1
- package/dist/scanners/network/index.js +0 -18
- package/dist/scanners/network/missing-timeout.d.ts +0 -15
- package/dist/scanners/network/missing-timeout.d.ts.map +0 -1
- package/dist/scanners/network/missing-timeout.js +0 -93
- package/dist/scanners/network/open-redirect.d.ts +0 -15
- package/dist/scanners/network/open-redirect.d.ts.map +0 -1
- package/dist/scanners/network/open-redirect.js +0 -88
- package/dist/scanners/network/ssrf-prone-fetch.d.ts +0 -12
- package/dist/scanners/network/ssrf-prone-fetch.d.ts.map +0 -1
- package/dist/scanners/network/ssrf-prone-fetch.js +0 -90
- package/dist/scanners/nextjs-middleware.d.ts +0 -26
- package/dist/scanners/nextjs-middleware.d.ts.map +0 -1
- package/dist/scanners/nextjs-middleware.js +0 -246
- package/dist/scanners/privacy/debug-flags.d.ts +0 -13
- package/dist/scanners/privacy/debug-flags.d.ts.map +0 -1
- package/dist/scanners/privacy/debug-flags.js +0 -124
- package/dist/scanners/privacy/index.d.ts +0 -6
- package/dist/scanners/privacy/index.d.ts.map +0 -1
- package/dist/scanners/privacy/index.js +0 -11
- package/dist/scanners/privacy/over-broad-response.d.ts +0 -15
- package/dist/scanners/privacy/over-broad-response.d.ts.map +0 -1
- package/dist/scanners/privacy/over-broad-response.js +0 -109
- package/dist/scanners/privacy/sensitive-logging.d.ts +0 -11
- package/dist/scanners/privacy/sensitive-logging.d.ts.map +0 -1
- package/dist/scanners/privacy/sensitive-logging.js +0 -78
- package/dist/scanners/types.d.ts +0 -456
- package/dist/scanners/types.d.ts.map +0 -1
- package/dist/scanners/types.js +0 -16
- package/dist/scanners/unused-security-imports.d.ts +0 -34
- package/dist/scanners/unused-security-imports.d.ts.map +0 -1
- package/dist/scanners/unused-security-imports.js +0 -206
- package/dist/scanners/uploads/index.d.ts +0 -5
- package/dist/scanners/uploads/index.d.ts.map +0 -1
- package/dist/scanners/uploads/index.js +0 -9
- package/dist/scanners/uploads/missing-constraints.d.ts +0 -15
- package/dist/scanners/uploads/missing-constraints.d.ts.map +0 -1
- package/dist/scanners/uploads/missing-constraints.js +0 -109
- package/dist/scanners/uploads/public-path.d.ts +0 -11
- package/dist/scanners/uploads/public-path.d.ts.map +0 -1
- package/dist/scanners/uploads/public-path.js +0 -87
- package/dist/scanners/validation/client-side-only.d.ts +0 -14
- package/dist/scanners/validation/client-side-only.d.ts.map +0 -1
- package/dist/scanners/validation/client-side-only.js +0 -140
- package/dist/scanners/validation/ignored-validation.d.ts +0 -12
- package/dist/scanners/validation/ignored-validation.d.ts.map +0 -1
- package/dist/scanners/validation/ignored-validation.js +0 -119
- package/dist/scanners/validation/index.d.ts +0 -5
- package/dist/scanners/validation/index.d.ts.map +0 -1
- package/dist/scanners/validation/index.js +0 -9
- package/dist/utils/exclude-patterns.d.ts +0 -35
- package/dist/utils/exclude-patterns.d.ts.map +0 -1
- package/dist/utils/exclude-patterns.js +0 -78
- package/dist/utils/file-utils.d.ts +0 -37
- package/dist/utils/file-utils.d.ts.map +0 -1
- package/dist/utils/file-utils.js +0 -77
- package/dist/utils/fingerprint.d.ts +0 -25
- package/dist/utils/fingerprint.d.ts.map +0 -1
- package/dist/utils/fingerprint.js +0 -28
- package/dist/utils/git-info.d.ts +0 -14
- package/dist/utils/git-info.d.ts.map +0 -1
- package/dist/utils/git-info.js +0 -55
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -3
- package/dist/utils/progress.d.ts +0 -42
- package/dist/utils/progress.d.ts.map +0 -1
- package/dist/utils/progress.js +0 -165
- package/dist/utils/sarif-formatter.d.ts +0 -92
- package/dist/utils/sarif-formatter.d.ts.map +0 -1
- package/dist/utils/sarif-formatter.js +0 -172
package/dist/commands/waivers.js
DELETED
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { readFileSync, fileExists, resolvePath, writeFileSync, ensureDir, } from "../utils/file-utils.js";
|
|
3
|
-
import { createEmptyWaiversFile, createWaiver, addWaiver, removeWaiver, WaiversFileSchema, } from "@vibecheck/policy";
|
|
4
|
-
const DEFAULT_WAIVERS_FILE = "vibecheck-waivers.json";
|
|
5
|
-
/**
|
|
6
|
-
* Load waivers file from path
|
|
7
|
-
*/
|
|
8
|
-
function loadWaiversFile(filepath) {
|
|
9
|
-
const absolutePath = resolvePath(filepath);
|
|
10
|
-
if (!fileExists(absolutePath)) {
|
|
11
|
-
throw new Error(`Waivers file not found: ${filepath}`);
|
|
12
|
-
}
|
|
13
|
-
const content = readFileSync(absolutePath);
|
|
14
|
-
if (!content) {
|
|
15
|
-
throw new Error(`Failed to read waivers file: ${filepath}`);
|
|
16
|
-
}
|
|
17
|
-
const data = JSON.parse(content);
|
|
18
|
-
const result = WaiversFileSchema.safeParse(data);
|
|
19
|
-
if (!result.success) {
|
|
20
|
-
throw new Error(`Invalid waivers file: ${result.error.message}`);
|
|
21
|
-
}
|
|
22
|
-
return result.data;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Save waivers file to path
|
|
26
|
-
*/
|
|
27
|
-
function saveWaiversFile(filepath, file) {
|
|
28
|
-
const absolutePath = resolvePath(filepath);
|
|
29
|
-
ensureDir(path.dirname(absolutePath));
|
|
30
|
-
writeFileSync(absolutePath, JSON.stringify(file, null, 2));
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Initialize a new waivers file
|
|
34
|
-
*/
|
|
35
|
-
export function executeWaiversInit(filepath, force) {
|
|
36
|
-
const absolutePath = resolvePath(filepath);
|
|
37
|
-
if (fileExists(absolutePath) && !force) {
|
|
38
|
-
console.error(`\x1b[31mError: Waivers file already exists: ${absolutePath}\x1b[0m`);
|
|
39
|
-
console.error("Use --force to overwrite");
|
|
40
|
-
return 1;
|
|
41
|
-
}
|
|
42
|
-
const emptyFile = createEmptyWaiversFile();
|
|
43
|
-
saveWaiversFile(filepath, emptyFile);
|
|
44
|
-
console.log(`Created waivers file: ${absolutePath}`);
|
|
45
|
-
return 0;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Add a waiver to the file
|
|
49
|
-
*/
|
|
50
|
-
export function executeWaiversAdd(filepath, options) {
|
|
51
|
-
// Validate options
|
|
52
|
-
if (!options.fingerprint && !options.ruleId) {
|
|
53
|
-
console.error("\x1b[31mError: Must specify either --fingerprint or --ruleId\x1b[0m");
|
|
54
|
-
return 1;
|
|
55
|
-
}
|
|
56
|
-
if (options.fingerprint && options.ruleId) {
|
|
57
|
-
console.error("\x1b[31mError: Cannot specify both --fingerprint and --ruleId\x1b[0m");
|
|
58
|
-
return 1;
|
|
59
|
-
}
|
|
60
|
-
// Validate expiry date if provided
|
|
61
|
-
if (options.expiresAt) {
|
|
62
|
-
const date = new Date(options.expiresAt);
|
|
63
|
-
if (isNaN(date.getTime())) {
|
|
64
|
-
console.error(`\x1b[31mError: Invalid expiry date: ${options.expiresAt}\x1b[0m`);
|
|
65
|
-
return 1;
|
|
66
|
-
}
|
|
67
|
-
if (date <= new Date()) {
|
|
68
|
-
console.error("\x1b[31mError: Expiry date must be in the future\x1b[0m");
|
|
69
|
-
return 1;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Load or create waivers file
|
|
73
|
-
let file;
|
|
74
|
-
const absolutePath = resolvePath(filepath);
|
|
75
|
-
if (fileExists(absolutePath)) {
|
|
76
|
-
file = loadWaiversFile(filepath);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
console.log("Creating new waivers file...");
|
|
80
|
-
file = createEmptyWaiversFile();
|
|
81
|
-
}
|
|
82
|
-
// Create waiver
|
|
83
|
-
const waiver = createWaiver({
|
|
84
|
-
fingerprint: options.fingerprint,
|
|
85
|
-
ruleId: options.ruleId,
|
|
86
|
-
pathPattern: options.pathPattern,
|
|
87
|
-
reason: options.reason,
|
|
88
|
-
createdBy: options.createdBy,
|
|
89
|
-
expiresAt: options.expiresAt ? new Date(options.expiresAt).toISOString() : undefined,
|
|
90
|
-
ticketRef: options.ticketRef,
|
|
91
|
-
});
|
|
92
|
-
// Add to file
|
|
93
|
-
const updated = addWaiver(file, waiver);
|
|
94
|
-
saveWaiversFile(filepath, updated);
|
|
95
|
-
console.log(`Added waiver: ${waiver.id}`);
|
|
96
|
-
if (options.fingerprint) {
|
|
97
|
-
console.log(` Fingerprint: ${options.fingerprint}`);
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
console.log(` Rule ID: ${options.ruleId}`);
|
|
101
|
-
if (options.pathPattern) {
|
|
102
|
-
console.log(` Path pattern: ${options.pathPattern}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
console.log(` Reason: ${options.reason}`);
|
|
106
|
-
console.log(` Created by: ${options.createdBy}`);
|
|
107
|
-
if (options.expiresAt) {
|
|
108
|
-
console.log(` Expires: ${options.expiresAt}`);
|
|
109
|
-
}
|
|
110
|
-
if (options.ticketRef) {
|
|
111
|
-
console.log(` Ticket: ${options.ticketRef}`);
|
|
112
|
-
}
|
|
113
|
-
return 0;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* List waivers in the file
|
|
117
|
-
*/
|
|
118
|
-
export function executeWaiversList(filepath, verbose) {
|
|
119
|
-
const file = loadWaiversFile(filepath);
|
|
120
|
-
if (file.waivers.length === 0) {
|
|
121
|
-
console.log("No waivers in file");
|
|
122
|
-
return 0;
|
|
123
|
-
}
|
|
124
|
-
console.log(`Found ${file.waivers.length} waiver(s):\n`);
|
|
125
|
-
for (const waiver of file.waivers) {
|
|
126
|
-
const isExpired = waiver.expiresAt && new Date(waiver.expiresAt) < new Date();
|
|
127
|
-
const expiredNote = isExpired ? " \x1b[31m[EXPIRED]\x1b[0m" : "";
|
|
128
|
-
console.log(`ID: ${waiver.id}${expiredNote}`);
|
|
129
|
-
if (waiver.match.fingerprint) {
|
|
130
|
-
console.log(` Match: fingerprint = ${waiver.match.fingerprint}`);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
console.log(` Match: ruleId = ${waiver.match.ruleId}`);
|
|
134
|
-
if (waiver.match.pathPattern) {
|
|
135
|
-
console.log(` pathPattern = ${waiver.match.pathPattern}`);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
console.log(` Reason: ${waiver.reason}`);
|
|
139
|
-
if (verbose) {
|
|
140
|
-
console.log(` Created by: ${waiver.createdBy}`);
|
|
141
|
-
console.log(` Created at: ${waiver.createdAt}`);
|
|
142
|
-
if (waiver.expiresAt) {
|
|
143
|
-
console.log(` Expires at: ${waiver.expiresAt}`);
|
|
144
|
-
}
|
|
145
|
-
if (waiver.ticketRef) {
|
|
146
|
-
console.log(` Ticket: ${waiver.ticketRef}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
console.log("");
|
|
150
|
-
}
|
|
151
|
-
return 0;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Remove a waiver from the file
|
|
155
|
-
*/
|
|
156
|
-
export function executeWaiversRemove(filepath, waiverId) {
|
|
157
|
-
const file = loadWaiversFile(filepath);
|
|
158
|
-
// Check if waiver exists
|
|
159
|
-
const exists = file.waivers.some((w) => w.id === waiverId);
|
|
160
|
-
if (!exists) {
|
|
161
|
-
console.error(`\x1b[31mError: Waiver not found: ${waiverId}\x1b[0m`);
|
|
162
|
-
return 1;
|
|
163
|
-
}
|
|
164
|
-
const updated = removeWaiver(file, waiverId);
|
|
165
|
-
saveWaiversFile(filepath, updated);
|
|
166
|
-
console.log(`Removed waiver: ${waiverId}`);
|
|
167
|
-
return 0;
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Register waivers command with subcommands
|
|
171
|
-
*/
|
|
172
|
-
export function registerWaiversCommand(program) {
|
|
173
|
-
const waiversCmd = program
|
|
174
|
-
.command("waivers")
|
|
175
|
-
.description("Manage policy waivers");
|
|
176
|
-
// waivers init
|
|
177
|
-
waiversCmd
|
|
178
|
-
.command("init [path]")
|
|
179
|
-
.description("Initialize a new waivers file")
|
|
180
|
-
.option("-f, --force", "Overwrite existing file")
|
|
181
|
-
.action((pathArg, cmdOptions) => {
|
|
182
|
-
const filepath = pathArg ?? DEFAULT_WAIVERS_FILE;
|
|
183
|
-
const exitCode = executeWaiversInit(filepath, Boolean(cmdOptions.force));
|
|
184
|
-
process.exit(exitCode);
|
|
185
|
-
});
|
|
186
|
-
// waivers add
|
|
187
|
-
waiversCmd
|
|
188
|
-
.command("add [path]")
|
|
189
|
-
.description("Add a waiver to the file")
|
|
190
|
-
.option("--fingerprint <sha256>", "Match by finding fingerprint")
|
|
191
|
-
.option("--rule-id <id>", "Match by rule ID (supports wildcards like VC-AUTH-*)")
|
|
192
|
-
.option("--path-pattern <glob>", "Additional path pattern for rule ID match")
|
|
193
|
-
.requiredOption("-r, --reason <text>", "Justification for the waiver")
|
|
194
|
-
.requiredOption("--created-by <email>", "Who is creating this waiver")
|
|
195
|
-
.option("--expires <date>", "Expiration date (ISO format)")
|
|
196
|
-
.option("--ticket <ref>", "Reference to ticket/issue")
|
|
197
|
-
.addHelpText("after", `
|
|
198
|
-
Examples:
|
|
199
|
-
$ vibecheck waivers add --fingerprint sha256:abc123 -r "False positive" --created-by dev@example.com
|
|
200
|
-
$ vibecheck waivers add --rule-id VC-AUTH-001 -r "Accepted risk" --created-by dev@example.com
|
|
201
|
-
$ vibecheck waivers add --rule-id "VC-VAL-*" --path-pattern "src/legacy/**" -r "Legacy code" --created-by dev@example.com
|
|
202
|
-
$ vibecheck waivers add --fingerprint sha256:xyz --expires 2025-12-31 -r "Temporary" --created-by dev@example.com
|
|
203
|
-
$ vibecheck waivers add ./custom-waivers.json --fingerprint sha256:abc -r "Custom file" --created-by dev@example.com
|
|
204
|
-
`)
|
|
205
|
-
.action((pathArg, cmdOptions) => {
|
|
206
|
-
const filepath = pathArg ?? DEFAULT_WAIVERS_FILE;
|
|
207
|
-
const exitCode = executeWaiversAdd(filepath, {
|
|
208
|
-
fingerprint: cmdOptions.fingerprint,
|
|
209
|
-
ruleId: cmdOptions.ruleId,
|
|
210
|
-
pathPattern: cmdOptions.pathPattern,
|
|
211
|
-
reason: cmdOptions.reason,
|
|
212
|
-
createdBy: cmdOptions.createdBy,
|
|
213
|
-
expiresAt: cmdOptions.expires,
|
|
214
|
-
ticketRef: cmdOptions.ticket,
|
|
215
|
-
});
|
|
216
|
-
process.exit(exitCode);
|
|
217
|
-
});
|
|
218
|
-
// waivers list
|
|
219
|
-
waiversCmd
|
|
220
|
-
.command("list [path]")
|
|
221
|
-
.description("List waivers in the file")
|
|
222
|
-
.option("-v, --verbose", "Show all waiver details")
|
|
223
|
-
.action((pathArg, cmdOptions) => {
|
|
224
|
-
const filepath = pathArg ?? DEFAULT_WAIVERS_FILE;
|
|
225
|
-
try {
|
|
226
|
-
const exitCode = executeWaiversList(filepath, Boolean(cmdOptions.verbose));
|
|
227
|
-
process.exit(exitCode);
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
console.error(`\x1b[31mError: ${error instanceof Error ? error.message : String(error)}\x1b[0m`);
|
|
231
|
-
process.exit(1);
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
// waivers remove
|
|
235
|
-
waiversCmd
|
|
236
|
-
.command("remove <waiverId> [path]")
|
|
237
|
-
.description("Remove a waiver from the file")
|
|
238
|
-
.action((waiverId, pathArg) => {
|
|
239
|
-
const filepath = pathArg ?? DEFAULT_WAIVERS_FILE;
|
|
240
|
-
try {
|
|
241
|
-
const exitCode = executeWaiversRemove(filepath, waiverId);
|
|
242
|
-
process.exit(exitCode);
|
|
243
|
-
}
|
|
244
|
-
catch (error) {
|
|
245
|
-
console.error(`\x1b[31mError: ${error instanceof Error ? error.message : String(error)}\x1b[0m`);
|
|
246
|
-
process.exit(1);
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/phase3/index.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 3: Hallucination Detection Engine
|
|
3
|
-
*
|
|
4
|
-
* Cross-file proof traces, intent claim mining, and hallucination detection.
|
|
5
|
-
* All deterministic, local-only.
|
|
6
|
-
*/
|
|
7
|
-
export { generateRouteId, filePathToRoutePath, buildRouteMap, buildMiddlewareMap, isRouteCoveredByMiddleware, buildProofTrace, buildAllProofTraces, calculateCoverage, } from "./proof-trace-builder.js";
|
|
8
|
-
export { generateIntentId, mineIntentClaims, mineAllIntentClaims, findClaimsForRoute, findUnprovenClaims, } from "./intent-miner.js";
|
|
9
|
-
export { phase3Scanners, hallucinationsPack, authPackPhase3, scanCommentClaimUnproven, scanMiddlewareAssumedNotMatching, scanValidationClaimedMissing, scanAuthByUiServerGap, } from "./scanners/index.js";
|
|
10
|
-
export type { RouteInfo, MiddlewareInfo, IntentClaim, IntentClaimType, IntentClaimSource, IntentClaimScope, IntentClaimStrength, ProofTrace, ProofTraceStep, CoverageMetrics, Phase3Context, } from "../scanners/types.js";
|
|
11
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/phase3/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,0BAA0B,EAC1B,eAAe,EACf,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,wBAAwB,EACxB,gCAAgC,EAChC,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAG7B,YAAY,EACV,SAAS,EACT,cAAc,EACd,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,sBAAsB,CAAC"}
|
package/dist/phase3/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 3: Hallucination Detection Engine
|
|
3
|
-
*
|
|
4
|
-
* Cross-file proof traces, intent claim mining, and hallucination detection.
|
|
5
|
-
* All deterministic, local-only.
|
|
6
|
-
*/
|
|
7
|
-
// Proof trace builder
|
|
8
|
-
export { generateRouteId, filePathToRoutePath, buildRouteMap, buildMiddlewareMap, isRouteCoveredByMiddleware, buildProofTrace, buildAllProofTraces, calculateCoverage, } from "./proof-trace-builder.js";
|
|
9
|
-
// Intent claim miner
|
|
10
|
-
export { generateIntentId, mineIntentClaims, mineAllIntentClaims, findClaimsForRoute, findUnprovenClaims, } from "./intent-miner.js";
|
|
11
|
-
// Scanners
|
|
12
|
-
export { phase3Scanners, hallucinationsPack, authPackPhase3, scanCommentClaimUnproven, scanMiddlewareAssumedNotMatching, scanValidationClaimedMissing, scanAuthByUiServerGap, } from "./scanners/index.js";
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 3: Intent Claim Miner
|
|
3
|
-
*
|
|
4
|
-
* Parses comments, identifiers, imports, and config for security claims.
|
|
5
|
-
* Deterministic, local-only.
|
|
6
|
-
*/
|
|
7
|
-
import { type SourceFile } from "ts-morph";
|
|
8
|
-
import type { ScanContext, IntentClaim, IntentClaimType, RouteInfo } from "../scanners/types.js";
|
|
9
|
-
/**
|
|
10
|
-
* Generate a stable intent ID
|
|
11
|
-
*/
|
|
12
|
-
export declare function generateIntentId(type: IntentClaimType, file: string, line: number, evidence: string): string;
|
|
13
|
-
/**
|
|
14
|
-
* Mine intent claims from a source file
|
|
15
|
-
*/
|
|
16
|
-
export declare function mineIntentClaims(ctx: ScanContext, sourceFile: SourceFile, routes: RouteInfo[]): IntentClaim[];
|
|
17
|
-
/**
|
|
18
|
-
* Mine all intent claims from scan context
|
|
19
|
-
*/
|
|
20
|
-
export declare function mineAllIntentClaims(ctx: ScanContext, routes: RouteInfo[]): IntentClaim[];
|
|
21
|
-
/**
|
|
22
|
-
* Find claims that target a specific route
|
|
23
|
-
*/
|
|
24
|
-
export declare function findClaimsForRoute(claims: IntentClaim[], routeId: string): IntentClaim[];
|
|
25
|
-
/**
|
|
26
|
-
* Find unproven claims (claims without corresponding proof)
|
|
27
|
-
*/
|
|
28
|
-
export declare function findUnprovenClaims(claims: IntentClaim[], proofTraces: Map<string, {
|
|
29
|
-
authProven: boolean;
|
|
30
|
-
validationProven: boolean;
|
|
31
|
-
}>): IntentClaim[];
|
|
32
|
-
//# sourceMappingURL=intent-miner.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"intent-miner.d.ts","sourceRoot":"","sources":["../../src/phase3/intent-miner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,eAAe,EAIf,SAAS,EACV,MAAM,sBAAsB,CAAC;AAkD9B;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,MAAM,CAGR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,SAAS,EAAE,GAClB,WAAW,EAAE,CAef;AA6PD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,SAAS,EAAE,GAClB,WAAW,EAAE,CAuBf;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EAAE,EACrB,OAAO,EAAE,MAAM,GACd,WAAW,EAAE,CAIf;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EAAE,EACrB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAA;CAAE,CAAC,GAC3E,WAAW,EAAE,CAqBf"}
|
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 3: Intent Claim Miner
|
|
3
|
-
*
|
|
4
|
-
* Parses comments, identifiers, imports, and config for security claims.
|
|
5
|
-
* Deterministic, local-only.
|
|
6
|
-
*/
|
|
7
|
-
import crypto from "node:crypto";
|
|
8
|
-
import path from "node:path";
|
|
9
|
-
import { SyntaxKind } from "ts-morph";
|
|
10
|
-
/**
|
|
11
|
-
* Patterns for detecting security intent claims
|
|
12
|
-
*/
|
|
13
|
-
const INTENT_PATTERNS = [
|
|
14
|
-
// Auth patterns
|
|
15
|
-
{ pattern: /\b(auth|authenticate|authorized|protected|secured)\b/i, type: "AUTH_ENFORCED", strength: "strong" },
|
|
16
|
-
{ pattern: /\brequires?\s*(auth|login|session)\b/i, type: "AUTH_ENFORCED", strength: "strong" },
|
|
17
|
-
{ pattern: /\b(getServerSession|useSession|withAuth|requireAuth)\b/, type: "AUTH_ENFORCED", strength: "medium" },
|
|
18
|
-
// Validation patterns
|
|
19
|
-
{ pattern: /\b(validat(e|ed|ion|or)|sanitiz(e|ed))\b/i, type: "INPUT_VALIDATED", strength: "strong" },
|
|
20
|
-
{ pattern: /\b(schema|zod|yup|joi)\b/i, type: "INPUT_VALIDATED", strength: "medium" },
|
|
21
|
-
{ pattern: /\.parse\(|\.validate\(|\.safeParse\(/, type: "INPUT_VALIDATED", strength: "medium" },
|
|
22
|
-
// CSRF patterns
|
|
23
|
-
{ pattern: /\b(csrf|xsrf|cross.?site)\b/i, type: "CSRF_ENABLED", strength: "strong" },
|
|
24
|
-
// Rate limiting patterns
|
|
25
|
-
{ pattern: /\b(rate.?limit|throttl|limit.?rate)\b/i, type: "RATE_LIMITED", strength: "strong" },
|
|
26
|
-
// Encryption patterns
|
|
27
|
-
{ pattern: /\b(encrypt|cipher|aes|rsa)\b/i, type: "ENCRYPTED_AT_REST", strength: "medium" },
|
|
28
|
-
// Middleware patterns
|
|
29
|
-
{ pattern: /\b(middleware|intercept|guard)\b/i, type: "MIDDLEWARE_PROTECTED", strength: "medium" },
|
|
30
|
-
];
|
|
31
|
-
/**
|
|
32
|
-
* Security-related import patterns
|
|
33
|
-
*/
|
|
34
|
-
const SECURITY_IMPORTS = [
|
|
35
|
-
{ module: /^next-auth/, type: "AUTH_ENFORCED" },
|
|
36
|
-
{ module: /^@auth\//, type: "AUTH_ENFORCED" },
|
|
37
|
-
{ module: /^passport/, type: "AUTH_ENFORCED" },
|
|
38
|
-
{ module: /^zod$/, type: "INPUT_VALIDATED" },
|
|
39
|
-
{ module: /^yup$/, type: "INPUT_VALIDATED" },
|
|
40
|
-
{ module: /^joi$/, type: "INPUT_VALIDATED" },
|
|
41
|
-
{ module: /^csurf$/, type: "CSRF_ENABLED" },
|
|
42
|
-
{ module: /^express-rate-limit$/, type: "RATE_LIMITED" },
|
|
43
|
-
{ module: /^rate-limiter-flexible$/, type: "RATE_LIMITED" },
|
|
44
|
-
{ module: /^helmet$/, type: "MIDDLEWARE_PROTECTED" },
|
|
45
|
-
];
|
|
46
|
-
/**
|
|
47
|
-
* Generate a stable intent ID
|
|
48
|
-
*/
|
|
49
|
-
export function generateIntentId(type, file, line, evidence) {
|
|
50
|
-
const normalized = `${type}:${file}:${line}:${evidence.slice(0, 50)}`.toLowerCase();
|
|
51
|
-
return crypto.createHash("sha256").update(normalized).digest("hex").slice(0, 12);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Mine intent claims from a source file
|
|
55
|
-
*/
|
|
56
|
-
export function mineIntentClaims(ctx, sourceFile, routes) {
|
|
57
|
-
const claims = [];
|
|
58
|
-
const filePath = sourceFile.getFilePath();
|
|
59
|
-
const relPath = path.relative(ctx.repoRoot, filePath).replace(/\\/g, "/");
|
|
60
|
-
// Mine from comments
|
|
61
|
-
claims.push(...mineFromComments(sourceFile, relPath, routes));
|
|
62
|
-
// Mine from imports
|
|
63
|
-
claims.push(...mineFromImports(sourceFile, relPath));
|
|
64
|
-
// Mine from identifiers (function names, variable names)
|
|
65
|
-
claims.push(...mineFromIdentifiers(sourceFile, relPath, routes));
|
|
66
|
-
return claims;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Mine claims from code comments
|
|
70
|
-
*/
|
|
71
|
-
function mineFromComments(sourceFile, relPath, routes) {
|
|
72
|
-
const claims = [];
|
|
73
|
-
// Get all comments in the file
|
|
74
|
-
const leadingComments = [];
|
|
75
|
-
sourceFile.forEachDescendant((node) => {
|
|
76
|
-
const nodeComments = node.getLeadingCommentRanges();
|
|
77
|
-
for (const comment of nodeComments) {
|
|
78
|
-
leadingComments.push({
|
|
79
|
-
text: comment.getText(),
|
|
80
|
-
line: sourceFile.getLineAndColumnAtPos(comment.getPos()).line,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
// Also get file-level comments
|
|
85
|
-
const fullText = sourceFile.getFullText();
|
|
86
|
-
const commentMatches = fullText.matchAll(/\/\*\*?[\s\S]*?\*\/|\/\/[^\n]*/g);
|
|
87
|
-
for (const match of commentMatches) {
|
|
88
|
-
const line = sourceFile.getLineAndColumnAtPos(match.index || 0).line;
|
|
89
|
-
// Avoid duplicates
|
|
90
|
-
if (!leadingComments.some((c) => c.line === line)) {
|
|
91
|
-
leadingComments.push({ text: match[0], line });
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
for (const { text, line } of leadingComments) {
|
|
95
|
-
for (const { pattern, type, strength } of INTENT_PATTERNS) {
|
|
96
|
-
if (pattern.test(text)) {
|
|
97
|
-
// Determine scope based on comment context
|
|
98
|
-
const scope = determineCommentScope(text, relPath);
|
|
99
|
-
// Try to find associated route
|
|
100
|
-
const targetRouteId = findAssociatedRoute(relPath, line, routes);
|
|
101
|
-
claims.push({
|
|
102
|
-
intentId: generateIntentId(type, relPath, line, text),
|
|
103
|
-
type,
|
|
104
|
-
scope,
|
|
105
|
-
targetRouteId,
|
|
106
|
-
source: "comment",
|
|
107
|
-
location: {
|
|
108
|
-
file: relPath,
|
|
109
|
-
startLine: line,
|
|
110
|
-
endLine: line,
|
|
111
|
-
},
|
|
112
|
-
strength,
|
|
113
|
-
textEvidence: truncateEvidence(text),
|
|
114
|
-
});
|
|
115
|
-
break; // One claim per comment
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return claims;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Mine claims from import statements
|
|
123
|
-
*/
|
|
124
|
-
function mineFromImports(sourceFile, relPath) {
|
|
125
|
-
const claims = [];
|
|
126
|
-
for (const importDecl of sourceFile.getImportDeclarations()) {
|
|
127
|
-
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
128
|
-
const line = importDecl.getStartLineNumber();
|
|
129
|
-
for (const { module, type } of SECURITY_IMPORTS) {
|
|
130
|
-
if (module.test(moduleSpecifier)) {
|
|
131
|
-
claims.push({
|
|
132
|
-
intentId: generateIntentId(type, relPath, line, moduleSpecifier),
|
|
133
|
-
type,
|
|
134
|
-
scope: "module",
|
|
135
|
-
source: "import",
|
|
136
|
-
location: {
|
|
137
|
-
file: relPath,
|
|
138
|
-
startLine: line,
|
|
139
|
-
endLine: line,
|
|
140
|
-
},
|
|
141
|
-
strength: "medium",
|
|
142
|
-
textEvidence: `import from "${moduleSpecifier}"`,
|
|
143
|
-
});
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return claims;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Mine claims from function and variable identifiers
|
|
152
|
-
*/
|
|
153
|
-
function mineFromIdentifiers(sourceFile, relPath, routes) {
|
|
154
|
-
const claims = [];
|
|
155
|
-
// Function declarations
|
|
156
|
-
for (const func of sourceFile.getFunctions()) {
|
|
157
|
-
const name = func.getName() || "";
|
|
158
|
-
const line = func.getStartLineNumber();
|
|
159
|
-
for (const { pattern, type, strength } of INTENT_PATTERNS) {
|
|
160
|
-
if (pattern.test(name)) {
|
|
161
|
-
const targetRouteId = findAssociatedRoute(relPath, line, routes);
|
|
162
|
-
claims.push({
|
|
163
|
-
intentId: generateIntentId(type, relPath, line, name),
|
|
164
|
-
type,
|
|
165
|
-
scope: "route",
|
|
166
|
-
targetRouteId,
|
|
167
|
-
source: "identifier",
|
|
168
|
-
location: {
|
|
169
|
-
file: relPath,
|
|
170
|
-
startLine: line,
|
|
171
|
-
endLine: func.getEndLineNumber(),
|
|
172
|
-
},
|
|
173
|
-
strength,
|
|
174
|
-
textEvidence: `function ${name}`,
|
|
175
|
-
});
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
// Variable declarations with security-related names
|
|
181
|
-
sourceFile.forEachDescendant((node) => {
|
|
182
|
-
if (node.getKind() === SyntaxKind.VariableDeclaration) {
|
|
183
|
-
const text = node.getText();
|
|
184
|
-
const name = text.split("=")[0].trim();
|
|
185
|
-
const line = node.getStartLineNumber();
|
|
186
|
-
for (const { pattern, type, strength } of INTENT_PATTERNS) {
|
|
187
|
-
if (pattern.test(name)) {
|
|
188
|
-
claims.push({
|
|
189
|
-
intentId: generateIntentId(type, relPath, line, name),
|
|
190
|
-
type,
|
|
191
|
-
scope: "route",
|
|
192
|
-
source: "identifier",
|
|
193
|
-
location: {
|
|
194
|
-
file: relPath,
|
|
195
|
-
startLine: line,
|
|
196
|
-
endLine: line,
|
|
197
|
-
},
|
|
198
|
-
strength,
|
|
199
|
-
textEvidence: `variable: ${truncateEvidence(name)}`,
|
|
200
|
-
});
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
return claims;
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Determine the scope of a comment-based claim
|
|
210
|
-
*/
|
|
211
|
-
function determineCommentScope(text, filePath) {
|
|
212
|
-
const lowerText = text.toLowerCase();
|
|
213
|
-
// Module-level indicators (file or function scope maps to module)
|
|
214
|
-
if (lowerText.includes("@file") ||
|
|
215
|
-
lowerText.includes("this file") ||
|
|
216
|
-
lowerText.includes("this module")) {
|
|
217
|
-
return "module";
|
|
218
|
-
}
|
|
219
|
-
// Route-level indicators
|
|
220
|
-
if (lowerText.includes("this route") ||
|
|
221
|
-
lowerText.includes("this endpoint") ||
|
|
222
|
-
lowerText.includes("this handler")) {
|
|
223
|
-
return "route";
|
|
224
|
-
}
|
|
225
|
-
// Global indicators
|
|
226
|
-
if (lowerText.includes("all routes") ||
|
|
227
|
-
lowerText.includes("every request") ||
|
|
228
|
-
lowerText.includes("globally")) {
|
|
229
|
-
return "global";
|
|
230
|
-
}
|
|
231
|
-
// Default to route scope for comments near handlers
|
|
232
|
-
return "route";
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Find an associated route for a given file and line
|
|
236
|
-
*/
|
|
237
|
-
function findAssociatedRoute(filePath, line, routes) {
|
|
238
|
-
// Find routes in the same file
|
|
239
|
-
const fileRoutes = routes.filter((r) => r.file === filePath);
|
|
240
|
-
if (fileRoutes.length === 0) {
|
|
241
|
-
return undefined;
|
|
242
|
-
}
|
|
243
|
-
// If only one route, associate with it
|
|
244
|
-
if (fileRoutes.length === 1) {
|
|
245
|
-
return fileRoutes[0].routeId;
|
|
246
|
-
}
|
|
247
|
-
// Find the closest route that starts after or contains this line
|
|
248
|
-
for (const route of fileRoutes) {
|
|
249
|
-
if (line >= route.startLine && line <= route.endLine) {
|
|
250
|
-
return route.routeId;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
// Find the closest route that starts after this line
|
|
254
|
-
const afterRoutes = fileRoutes.filter((r) => r.startLine > line);
|
|
255
|
-
if (afterRoutes.length > 0) {
|
|
256
|
-
return afterRoutes.sort((a, b) => a.startLine - b.startLine)[0].routeId;
|
|
257
|
-
}
|
|
258
|
-
return undefined;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Truncate evidence text
|
|
262
|
-
*/
|
|
263
|
-
function truncateEvidence(text) {
|
|
264
|
-
const cleaned = text.replace(/\s+/g, " ").trim();
|
|
265
|
-
if (cleaned.length <= 100) {
|
|
266
|
-
return cleaned;
|
|
267
|
-
}
|
|
268
|
-
return cleaned.slice(0, 97) + "...";
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Mine all intent claims from scan context
|
|
272
|
-
*/
|
|
273
|
-
export function mineAllIntentClaims(ctx, routes) {
|
|
274
|
-
const allClaims = [];
|
|
275
|
-
// Mine from all source files
|
|
276
|
-
for (const file of ctx.fileIndex.allSourceFiles) {
|
|
277
|
-
// allSourceFiles are relative paths, resolve to absolute for parseFile
|
|
278
|
-
const absolutePath = path.join(ctx.repoRoot, file);
|
|
279
|
-
const sourceFile = ctx.helpers.parseFile(absolutePath);
|
|
280
|
-
if (!sourceFile)
|
|
281
|
-
continue;
|
|
282
|
-
const claims = mineIntentClaims(ctx, sourceFile, routes);
|
|
283
|
-
allClaims.push(...claims);
|
|
284
|
-
}
|
|
285
|
-
// Deduplicate by intentId
|
|
286
|
-
const seen = new Set();
|
|
287
|
-
return allClaims.filter((claim) => {
|
|
288
|
-
if (seen.has(claim.intentId)) {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
seen.add(claim.intentId);
|
|
292
|
-
return true;
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Find claims that target a specific route
|
|
297
|
-
*/
|
|
298
|
-
export function findClaimsForRoute(claims, routeId) {
|
|
299
|
-
return claims.filter((c) => c.targetRouteId === routeId || c.scope === "global" || c.scope === "module");
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Find unproven claims (claims without corresponding proof)
|
|
303
|
-
*/
|
|
304
|
-
export function findUnprovenClaims(claims, proofTraces) {
|
|
305
|
-
const unproven = [];
|
|
306
|
-
for (const claim of claims) {
|
|
307
|
-
if (!claim.targetRouteId)
|
|
308
|
-
continue;
|
|
309
|
-
const proof = proofTraces.get(claim.targetRouteId);
|
|
310
|
-
if (!proof) {
|
|
311
|
-
unproven.push(claim);
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
// Check if the claim type matches the proof
|
|
315
|
-
if (claim.type === "AUTH_ENFORCED" && !proof.authProven) {
|
|
316
|
-
unproven.push(claim);
|
|
317
|
-
}
|
|
318
|
-
else if (claim.type === "INPUT_VALIDATED" && !proof.validationProven) {
|
|
319
|
-
unproven.push(claim);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return unproven;
|
|
323
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase 3: Cross-file Proof Trace Builder
|
|
3
|
-
*
|
|
4
|
-
* Lightweight call-graph tracing for Next.js App Router.
|
|
5
|
-
* Traces auth/validation through local imports (max depth 2).
|
|
6
|
-
* Deterministic, local-only.
|
|
7
|
-
*/
|
|
8
|
-
import type { ScanContext, RouteInfo, MiddlewareInfo, ProofTrace, CoverageMetrics } from "../scanners/types.js";
|
|
9
|
-
/**
|
|
10
|
-
* Generate a stable route ID from path, method, and file
|
|
11
|
-
*/
|
|
12
|
-
export declare function generateRouteId(routePath: string, method: string, file: string): string;
|
|
13
|
-
/**
|
|
14
|
-
* Convert file path to URL path for Next.js App Router
|
|
15
|
-
* e.g., "app/api/users/[id]/route.ts" -> "/api/users/[id]"
|
|
16
|
-
*/
|
|
17
|
-
export declare function filePathToRoutePath(filePath: string): string;
|
|
18
|
-
/**
|
|
19
|
-
* Build route map from scan context
|
|
20
|
-
*/
|
|
21
|
-
export declare function buildRouteMap(ctx: ScanContext): RouteInfo[];
|
|
22
|
-
/**
|
|
23
|
-
* Build middleware map from scan context
|
|
24
|
-
*/
|
|
25
|
-
export declare function buildMiddlewareMap(ctx: ScanContext): MiddlewareInfo[];
|
|
26
|
-
/**
|
|
27
|
-
* Check if a route path is covered by middleware matchers
|
|
28
|
-
*/
|
|
29
|
-
export declare function isRouteCoveredByMiddleware(routePath: string, matchers: string[]): boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Trace auth/validation through a handler and its imports
|
|
32
|
-
*/
|
|
33
|
-
export declare function buildProofTrace(ctx: ScanContext, route: RouteInfo): ProofTrace;
|
|
34
|
-
/**
|
|
35
|
-
* Calculate coverage metrics from routes and proof traces
|
|
36
|
-
*/
|
|
37
|
-
export declare function calculateCoverage(routes: RouteInfo[], proofTraces: Map<string, ProofTrace>, middlewareMap: MiddlewareInfo[]): CoverageMetrics;
|
|
38
|
-
/**
|
|
39
|
-
* Build all proof traces for a scan context
|
|
40
|
-
*/
|
|
41
|
-
export declare function buildAllProofTraces(ctx: ScanContext, routes: RouteInfo[]): Map<string, ProofTrace>;
|
|
42
|
-
//# sourceMappingURL=proof-trace-builder.d.ts.map
|