@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.
Files changed (208) hide show
  1. package/README.md +6 -6
  2. package/dist/index.d.ts +0 -2
  3. package/dist/index.js +7902 -8
  4. package/package.json +13 -7
  5. package/dist/__tests__/cli.test.d.ts +0 -2
  6. package/dist/__tests__/cli.test.d.ts.map +0 -1
  7. package/dist/__tests__/cli.test.js +0 -243
  8. package/dist/__tests__/fixtures/safe-app/app/api/users/route.js +0 -36
  9. package/dist/__tests__/fixtures/vulnerable-app/app/api/users/route.js +0 -28
  10. package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts +0 -4
  11. package/dist/__tests__/fixtures/vulnerable-app/lib/config.d.ts.map +0 -1
  12. package/dist/__tests__/fixtures/vulnerable-app/lib/config.js +0 -6
  13. package/dist/__tests__/scanners/env-config.test.d.ts +0 -2
  14. package/dist/__tests__/scanners/env-config.test.d.ts.map +0 -1
  15. package/dist/__tests__/scanners/env-config.test.js +0 -142
  16. package/dist/__tests__/scanners/nextjs-middleware.test.d.ts +0 -2
  17. package/dist/__tests__/scanners/nextjs-middleware.test.d.ts.map +0 -1
  18. package/dist/__tests__/scanners/nextjs-middleware.test.js +0 -193
  19. package/dist/__tests__/scanners/scanner-packs.test.d.ts +0 -2
  20. package/dist/__tests__/scanners/scanner-packs.test.d.ts.map +0 -1
  21. package/dist/__tests__/scanners/scanner-packs.test.js +0 -126
  22. package/dist/__tests__/scanners/unused-security-imports.test.d.ts +0 -2
  23. package/dist/__tests__/scanners/unused-security-imports.test.d.ts.map +0 -1
  24. package/dist/__tests__/scanners/unused-security-imports.test.js +0 -145
  25. package/dist/commands/demo-artifact.d.ts +0 -7
  26. package/dist/commands/demo-artifact.d.ts.map +0 -1
  27. package/dist/commands/demo-artifact.js +0 -322
  28. package/dist/commands/evaluate.d.ts +0 -30
  29. package/dist/commands/evaluate.d.ts.map +0 -1
  30. package/dist/commands/evaluate.js +0 -258
  31. package/dist/commands/explain.d.ts +0 -12
  32. package/dist/commands/explain.d.ts.map +0 -1
  33. package/dist/commands/explain.js +0 -214
  34. package/dist/commands/index.d.ts +0 -7
  35. package/dist/commands/index.d.ts.map +0 -1
  36. package/dist/commands/index.js +0 -6
  37. package/dist/commands/intent.d.ts +0 -21
  38. package/dist/commands/intent.d.ts.map +0 -1
  39. package/dist/commands/intent.js +0 -192
  40. package/dist/commands/scan.d.ts +0 -44
  41. package/dist/commands/scan.d.ts.map +0 -1
  42. package/dist/commands/scan.js +0 -497
  43. package/dist/commands/waivers.d.ts +0 -30
  44. package/dist/commands/waivers.d.ts.map +0 -1
  45. package/dist/commands/waivers.js +0 -249
  46. package/dist/index.d.ts.map +0 -1
  47. package/dist/phase3/index.d.ts +0 -11
  48. package/dist/phase3/index.d.ts.map +0 -1
  49. package/dist/phase3/index.js +0 -12
  50. package/dist/phase3/intent-miner.d.ts +0 -32
  51. package/dist/phase3/intent-miner.d.ts.map +0 -1
  52. package/dist/phase3/intent-miner.js +0 -323
  53. package/dist/phase3/proof-trace-builder.d.ts +0 -42
  54. package/dist/phase3/proof-trace-builder.d.ts.map +0 -1
  55. package/dist/phase3/proof-trace-builder.js +0 -441
  56. package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts +0 -15
  57. package/dist/phase3/scanners/auth-by-ui-server-gap.d.ts.map +0 -1
  58. package/dist/phase3/scanners/auth-by-ui-server-gap.js +0 -237
  59. package/dist/phase3/scanners/comment-claim-unproven.d.ts +0 -14
  60. package/dist/phase3/scanners/comment-claim-unproven.d.ts.map +0 -1
  61. package/dist/phase3/scanners/comment-claim-unproven.js +0 -161
  62. package/dist/phase3/scanners/index.d.ts +0 -31
  63. package/dist/phase3/scanners/index.d.ts.map +0 -1
  64. package/dist/phase3/scanners/index.js +0 -40
  65. package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts +0 -14
  66. package/dist/phase3/scanners/middleware-assumed-not-matching.d.ts.map +0 -1
  67. package/dist/phase3/scanners/middleware-assumed-not-matching.js +0 -172
  68. package/dist/phase3/scanners/validation-claimed-missing.d.ts +0 -15
  69. package/dist/phase3/scanners/validation-claimed-missing.d.ts.map +0 -1
  70. package/dist/phase3/scanners/validation-claimed-missing.js +0 -204
  71. package/dist/scanners/abuse/compute-abuse.d.ts +0 -20
  72. package/dist/scanners/abuse/compute-abuse.d.ts.map +0 -1
  73. package/dist/scanners/abuse/compute-abuse.js +0 -509
  74. package/dist/scanners/abuse/index.d.ts +0 -12
  75. package/dist/scanners/abuse/index.d.ts.map +0 -1
  76. package/dist/scanners/abuse/index.js +0 -15
  77. package/dist/scanners/auth/index.d.ts +0 -5
  78. package/dist/scanners/auth/index.d.ts.map +0 -1
  79. package/dist/scanners/auth/index.js +0 -10
  80. package/dist/scanners/auth/middleware-gap.d.ts +0 -22
  81. package/dist/scanners/auth/middleware-gap.d.ts.map +0 -1
  82. package/dist/scanners/auth/middleware-gap.js +0 -203
  83. package/dist/scanners/auth/unprotected-api-route.d.ts +0 -12
  84. package/dist/scanners/auth/unprotected-api-route.d.ts.map +0 -1
  85. package/dist/scanners/auth/unprotected-api-route.js +0 -126
  86. package/dist/scanners/config/index.d.ts +0 -5
  87. package/dist/scanners/config/index.d.ts.map +0 -1
  88. package/dist/scanners/config/index.js +0 -10
  89. package/dist/scanners/config/insecure-defaults.d.ts +0 -12
  90. package/dist/scanners/config/insecure-defaults.d.ts.map +0 -1
  91. package/dist/scanners/config/insecure-defaults.js +0 -77
  92. package/dist/scanners/config/undocumented-env.d.ts +0 -24
  93. package/dist/scanners/config/undocumented-env.d.ts.map +0 -1
  94. package/dist/scanners/config/undocumented-env.js +0 -159
  95. package/dist/scanners/crypto/index.d.ts +0 -6
  96. package/dist/scanners/crypto/index.d.ts.map +0 -1
  97. package/dist/scanners/crypto/index.js +0 -11
  98. package/dist/scanners/crypto/jwt-decode-unverified.d.ts +0 -14
  99. package/dist/scanners/crypto/jwt-decode-unverified.d.ts.map +0 -1
  100. package/dist/scanners/crypto/jwt-decode-unverified.js +0 -87
  101. package/dist/scanners/crypto/math-random-tokens.d.ts +0 -13
  102. package/dist/scanners/crypto/math-random-tokens.d.ts.map +0 -1
  103. package/dist/scanners/crypto/math-random-tokens.js +0 -80
  104. package/dist/scanners/crypto/weak-hashing.d.ts +0 -11
  105. package/dist/scanners/crypto/weak-hashing.d.ts.map +0 -1
  106. package/dist/scanners/crypto/weak-hashing.js +0 -95
  107. package/dist/scanners/env-config.d.ts +0 -24
  108. package/dist/scanners/env-config.d.ts.map +0 -1
  109. package/dist/scanners/env-config.js +0 -164
  110. package/dist/scanners/hallucinations/index.d.ts +0 -4
  111. package/dist/scanners/hallucinations/index.d.ts.map +0 -1
  112. package/dist/scanners/hallucinations/index.js +0 -8
  113. package/dist/scanners/hallucinations/unused-security-imports.d.ts +0 -36
  114. package/dist/scanners/hallucinations/unused-security-imports.d.ts.map +0 -1
  115. package/dist/scanners/hallucinations/unused-security-imports.js +0 -309
  116. package/dist/scanners/helpers/ast-helpers.d.ts +0 -6
  117. package/dist/scanners/helpers/ast-helpers.d.ts.map +0 -1
  118. package/dist/scanners/helpers/ast-helpers.js +0 -945
  119. package/dist/scanners/helpers/context-builder.d.ts +0 -17
  120. package/dist/scanners/helpers/context-builder.d.ts.map +0 -1
  121. package/dist/scanners/helpers/context-builder.js +0 -148
  122. package/dist/scanners/helpers/index.d.ts +0 -3
  123. package/dist/scanners/helpers/index.d.ts.map +0 -1
  124. package/dist/scanners/helpers/index.js +0 -2
  125. package/dist/scanners/index.d.ts +0 -30
  126. package/dist/scanners/index.d.ts.map +0 -1
  127. package/dist/scanners/index.js +0 -102
  128. package/dist/scanners/middleware/index.d.ts +0 -4
  129. package/dist/scanners/middleware/index.d.ts.map +0 -1
  130. package/dist/scanners/middleware/index.js +0 -7
  131. package/dist/scanners/middleware/missing-rate-limit.d.ts +0 -13
  132. package/dist/scanners/middleware/missing-rate-limit.d.ts.map +0 -1
  133. package/dist/scanners/middleware/missing-rate-limit.js +0 -140
  134. package/dist/scanners/network/cors-misconfiguration.d.ts +0 -14
  135. package/dist/scanners/network/cors-misconfiguration.d.ts.map +0 -1
  136. package/dist/scanners/network/cors-misconfiguration.js +0 -89
  137. package/dist/scanners/network/index.d.ts +0 -7
  138. package/dist/scanners/network/index.d.ts.map +0 -1
  139. package/dist/scanners/network/index.js +0 -18
  140. package/dist/scanners/network/missing-timeout.d.ts +0 -15
  141. package/dist/scanners/network/missing-timeout.d.ts.map +0 -1
  142. package/dist/scanners/network/missing-timeout.js +0 -93
  143. package/dist/scanners/network/open-redirect.d.ts +0 -15
  144. package/dist/scanners/network/open-redirect.d.ts.map +0 -1
  145. package/dist/scanners/network/open-redirect.js +0 -88
  146. package/dist/scanners/network/ssrf-prone-fetch.d.ts +0 -12
  147. package/dist/scanners/network/ssrf-prone-fetch.d.ts.map +0 -1
  148. package/dist/scanners/network/ssrf-prone-fetch.js +0 -90
  149. package/dist/scanners/nextjs-middleware.d.ts +0 -26
  150. package/dist/scanners/nextjs-middleware.d.ts.map +0 -1
  151. package/dist/scanners/nextjs-middleware.js +0 -246
  152. package/dist/scanners/privacy/debug-flags.d.ts +0 -13
  153. package/dist/scanners/privacy/debug-flags.d.ts.map +0 -1
  154. package/dist/scanners/privacy/debug-flags.js +0 -124
  155. package/dist/scanners/privacy/index.d.ts +0 -6
  156. package/dist/scanners/privacy/index.d.ts.map +0 -1
  157. package/dist/scanners/privacy/index.js +0 -11
  158. package/dist/scanners/privacy/over-broad-response.d.ts +0 -15
  159. package/dist/scanners/privacy/over-broad-response.d.ts.map +0 -1
  160. package/dist/scanners/privacy/over-broad-response.js +0 -109
  161. package/dist/scanners/privacy/sensitive-logging.d.ts +0 -11
  162. package/dist/scanners/privacy/sensitive-logging.d.ts.map +0 -1
  163. package/dist/scanners/privacy/sensitive-logging.js +0 -78
  164. package/dist/scanners/types.d.ts +0 -456
  165. package/dist/scanners/types.d.ts.map +0 -1
  166. package/dist/scanners/types.js +0 -16
  167. package/dist/scanners/unused-security-imports.d.ts +0 -34
  168. package/dist/scanners/unused-security-imports.d.ts.map +0 -1
  169. package/dist/scanners/unused-security-imports.js +0 -206
  170. package/dist/scanners/uploads/index.d.ts +0 -5
  171. package/dist/scanners/uploads/index.d.ts.map +0 -1
  172. package/dist/scanners/uploads/index.js +0 -9
  173. package/dist/scanners/uploads/missing-constraints.d.ts +0 -15
  174. package/dist/scanners/uploads/missing-constraints.d.ts.map +0 -1
  175. package/dist/scanners/uploads/missing-constraints.js +0 -109
  176. package/dist/scanners/uploads/public-path.d.ts +0 -11
  177. package/dist/scanners/uploads/public-path.d.ts.map +0 -1
  178. package/dist/scanners/uploads/public-path.js +0 -87
  179. package/dist/scanners/validation/client-side-only.d.ts +0 -14
  180. package/dist/scanners/validation/client-side-only.d.ts.map +0 -1
  181. package/dist/scanners/validation/client-side-only.js +0 -140
  182. package/dist/scanners/validation/ignored-validation.d.ts +0 -12
  183. package/dist/scanners/validation/ignored-validation.d.ts.map +0 -1
  184. package/dist/scanners/validation/ignored-validation.js +0 -119
  185. package/dist/scanners/validation/index.d.ts +0 -5
  186. package/dist/scanners/validation/index.d.ts.map +0 -1
  187. package/dist/scanners/validation/index.js +0 -9
  188. package/dist/utils/exclude-patterns.d.ts +0 -35
  189. package/dist/utils/exclude-patterns.d.ts.map +0 -1
  190. package/dist/utils/exclude-patterns.js +0 -78
  191. package/dist/utils/file-utils.d.ts +0 -37
  192. package/dist/utils/file-utils.d.ts.map +0 -1
  193. package/dist/utils/file-utils.js +0 -77
  194. package/dist/utils/fingerprint.d.ts +0 -25
  195. package/dist/utils/fingerprint.d.ts.map +0 -1
  196. package/dist/utils/fingerprint.js +0 -28
  197. package/dist/utils/git-info.d.ts +0 -14
  198. package/dist/utils/git-info.d.ts.map +0 -1
  199. package/dist/utils/git-info.js +0 -55
  200. package/dist/utils/index.d.ts +0 -4
  201. package/dist/utils/index.d.ts.map +0 -1
  202. package/dist/utils/index.js +0 -3
  203. package/dist/utils/progress.d.ts +0 -42
  204. package/dist/utils/progress.d.ts.map +0 -1
  205. package/dist/utils/progress.js +0 -165
  206. package/dist/utils/sarif-formatter.d.ts +0 -92
  207. package/dist/utils/sarif-formatter.d.ts.map +0 -1
  208. package/dist/utils/sarif-formatter.js +0 -172
@@ -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
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
@@ -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"}
@@ -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