@oculum/scanner 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/dist/formatters/cli-terminal.d.ts +27 -0
  2. package/dist/formatters/cli-terminal.d.ts.map +1 -0
  3. package/dist/formatters/cli-terminal.js +412 -0
  4. package/dist/formatters/cli-terminal.js.map +1 -0
  5. package/dist/formatters/github-comment.d.ts +41 -0
  6. package/dist/formatters/github-comment.d.ts.map +1 -0
  7. package/dist/formatters/github-comment.js +306 -0
  8. package/dist/formatters/github-comment.js.map +1 -0
  9. package/dist/formatters/grouping.d.ts +52 -0
  10. package/dist/formatters/grouping.d.ts.map +1 -0
  11. package/dist/formatters/grouping.js +152 -0
  12. package/dist/formatters/grouping.js.map +1 -0
  13. package/dist/formatters/index.d.ts +9 -0
  14. package/dist/formatters/index.d.ts.map +1 -0
  15. package/dist/formatters/index.js +35 -0
  16. package/dist/formatters/index.js.map +1 -0
  17. package/dist/formatters/vscode-diagnostic.d.ts +103 -0
  18. package/dist/formatters/vscode-diagnostic.d.ts.map +1 -0
  19. package/dist/formatters/vscode-diagnostic.js +151 -0
  20. package/dist/formatters/vscode-diagnostic.js.map +1 -0
  21. package/dist/index.d.ts +52 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +648 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/layer1/comments.d.ts +8 -0
  26. package/dist/layer1/comments.d.ts.map +1 -0
  27. package/dist/layer1/comments.js +203 -0
  28. package/dist/layer1/comments.js.map +1 -0
  29. package/dist/layer1/config-audit.d.ts +8 -0
  30. package/dist/layer1/config-audit.d.ts.map +1 -0
  31. package/dist/layer1/config-audit.js +252 -0
  32. package/dist/layer1/config-audit.js.map +1 -0
  33. package/dist/layer1/entropy.d.ts +8 -0
  34. package/dist/layer1/entropy.d.ts.map +1 -0
  35. package/dist/layer1/entropy.js +500 -0
  36. package/dist/layer1/entropy.js.map +1 -0
  37. package/dist/layer1/file-flags.d.ts +7 -0
  38. package/dist/layer1/file-flags.d.ts.map +1 -0
  39. package/dist/layer1/file-flags.js +112 -0
  40. package/dist/layer1/file-flags.js.map +1 -0
  41. package/dist/layer1/index.d.ts +36 -0
  42. package/dist/layer1/index.d.ts.map +1 -0
  43. package/dist/layer1/index.js +132 -0
  44. package/dist/layer1/index.js.map +1 -0
  45. package/dist/layer1/patterns.d.ts +8 -0
  46. package/dist/layer1/patterns.d.ts.map +1 -0
  47. package/dist/layer1/patterns.js +482 -0
  48. package/dist/layer1/patterns.js.map +1 -0
  49. package/dist/layer1/urls.d.ts +8 -0
  50. package/dist/layer1/urls.d.ts.map +1 -0
  51. package/dist/layer1/urls.js +296 -0
  52. package/dist/layer1/urls.js.map +1 -0
  53. package/dist/layer1/weak-crypto.d.ts +7 -0
  54. package/dist/layer1/weak-crypto.d.ts.map +1 -0
  55. package/dist/layer1/weak-crypto.js +291 -0
  56. package/dist/layer1/weak-crypto.js.map +1 -0
  57. package/dist/layer2/ai-agent-tools.d.ts +19 -0
  58. package/dist/layer2/ai-agent-tools.d.ts.map +1 -0
  59. package/dist/layer2/ai-agent-tools.js +528 -0
  60. package/dist/layer2/ai-agent-tools.js.map +1 -0
  61. package/dist/layer2/ai-endpoint-protection.d.ts +36 -0
  62. package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -0
  63. package/dist/layer2/ai-endpoint-protection.js +332 -0
  64. package/dist/layer2/ai-endpoint-protection.js.map +1 -0
  65. package/dist/layer2/ai-execution-sinks.d.ts +18 -0
  66. package/dist/layer2/ai-execution-sinks.d.ts.map +1 -0
  67. package/dist/layer2/ai-execution-sinks.js +496 -0
  68. package/dist/layer2/ai-execution-sinks.js.map +1 -0
  69. package/dist/layer2/ai-fingerprinting.d.ts +7 -0
  70. package/dist/layer2/ai-fingerprinting.d.ts.map +1 -0
  71. package/dist/layer2/ai-fingerprinting.js +654 -0
  72. package/dist/layer2/ai-fingerprinting.js.map +1 -0
  73. package/dist/layer2/ai-prompt-hygiene.d.ts +19 -0
  74. package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -0
  75. package/dist/layer2/ai-prompt-hygiene.js +356 -0
  76. package/dist/layer2/ai-prompt-hygiene.js.map +1 -0
  77. package/dist/layer2/ai-rag-safety.d.ts +21 -0
  78. package/dist/layer2/ai-rag-safety.d.ts.map +1 -0
  79. package/dist/layer2/ai-rag-safety.js +459 -0
  80. package/dist/layer2/ai-rag-safety.js.map +1 -0
  81. package/dist/layer2/ai-schema-validation.d.ts +25 -0
  82. package/dist/layer2/ai-schema-validation.d.ts.map +1 -0
  83. package/dist/layer2/ai-schema-validation.js +375 -0
  84. package/dist/layer2/ai-schema-validation.js.map +1 -0
  85. package/dist/layer2/auth-antipatterns.d.ts +20 -0
  86. package/dist/layer2/auth-antipatterns.d.ts.map +1 -0
  87. package/dist/layer2/auth-antipatterns.js +333 -0
  88. package/dist/layer2/auth-antipatterns.js.map +1 -0
  89. package/dist/layer2/byok-patterns.d.ts +12 -0
  90. package/dist/layer2/byok-patterns.d.ts.map +1 -0
  91. package/dist/layer2/byok-patterns.js +299 -0
  92. package/dist/layer2/byok-patterns.js.map +1 -0
  93. package/dist/layer2/dangerous-functions.d.ts +7 -0
  94. package/dist/layer2/dangerous-functions.d.ts.map +1 -0
  95. package/dist/layer2/dangerous-functions.js +1375 -0
  96. package/dist/layer2/dangerous-functions.js.map +1 -0
  97. package/dist/layer2/data-exposure.d.ts +16 -0
  98. package/dist/layer2/data-exposure.d.ts.map +1 -0
  99. package/dist/layer2/data-exposure.js +279 -0
  100. package/dist/layer2/data-exposure.js.map +1 -0
  101. package/dist/layer2/framework-checks.d.ts +7 -0
  102. package/dist/layer2/framework-checks.d.ts.map +1 -0
  103. package/dist/layer2/framework-checks.js +388 -0
  104. package/dist/layer2/framework-checks.js.map +1 -0
  105. package/dist/layer2/index.d.ts +58 -0
  106. package/dist/layer2/index.d.ts.map +1 -0
  107. package/dist/layer2/index.js +380 -0
  108. package/dist/layer2/index.js.map +1 -0
  109. package/dist/layer2/logic-gates.d.ts +7 -0
  110. package/dist/layer2/logic-gates.d.ts.map +1 -0
  111. package/dist/layer2/logic-gates.js +182 -0
  112. package/dist/layer2/logic-gates.js.map +1 -0
  113. package/dist/layer2/risky-imports.d.ts +7 -0
  114. package/dist/layer2/risky-imports.d.ts.map +1 -0
  115. package/dist/layer2/risky-imports.js +161 -0
  116. package/dist/layer2/risky-imports.js.map +1 -0
  117. package/dist/layer2/variables.d.ts +8 -0
  118. package/dist/layer2/variables.d.ts.map +1 -0
  119. package/dist/layer2/variables.js +152 -0
  120. package/dist/layer2/variables.js.map +1 -0
  121. package/dist/layer3/anthropic.d.ts +83 -0
  122. package/dist/layer3/anthropic.d.ts.map +1 -0
  123. package/dist/layer3/anthropic.js +1745 -0
  124. package/dist/layer3/anthropic.js.map +1 -0
  125. package/dist/layer3/index.d.ts +24 -0
  126. package/dist/layer3/index.d.ts.map +1 -0
  127. package/dist/layer3/index.js +119 -0
  128. package/dist/layer3/index.js.map +1 -0
  129. package/dist/layer3/openai.d.ts +25 -0
  130. package/dist/layer3/openai.d.ts.map +1 -0
  131. package/dist/layer3/openai.js +238 -0
  132. package/dist/layer3/openai.js.map +1 -0
  133. package/dist/layer3/package-check.d.ts +63 -0
  134. package/dist/layer3/package-check.d.ts.map +1 -0
  135. package/dist/layer3/package-check.js +508 -0
  136. package/dist/layer3/package-check.js.map +1 -0
  137. package/dist/modes/incremental.d.ts +66 -0
  138. package/dist/modes/incremental.d.ts.map +1 -0
  139. package/dist/modes/incremental.js +200 -0
  140. package/dist/modes/incremental.js.map +1 -0
  141. package/dist/tiers.d.ts +125 -0
  142. package/dist/tiers.d.ts.map +1 -0
  143. package/dist/tiers.js +234 -0
  144. package/dist/tiers.js.map +1 -0
  145. package/dist/types.d.ts +175 -0
  146. package/dist/types.d.ts.map +1 -0
  147. package/dist/types.js +50 -0
  148. package/dist/types.js.map +1 -0
  149. package/dist/utils/auth-helper-detector.d.ts +56 -0
  150. package/dist/utils/auth-helper-detector.d.ts.map +1 -0
  151. package/dist/utils/auth-helper-detector.js +360 -0
  152. package/dist/utils/auth-helper-detector.js.map +1 -0
  153. package/dist/utils/context-helpers.d.ts +96 -0
  154. package/dist/utils/context-helpers.d.ts.map +1 -0
  155. package/dist/utils/context-helpers.js +493 -0
  156. package/dist/utils/context-helpers.js.map +1 -0
  157. package/dist/utils/diff-detector.d.ts +53 -0
  158. package/dist/utils/diff-detector.d.ts.map +1 -0
  159. package/dist/utils/diff-detector.js +104 -0
  160. package/dist/utils/diff-detector.js.map +1 -0
  161. package/dist/utils/diff-parser.d.ts +80 -0
  162. package/dist/utils/diff-parser.d.ts.map +1 -0
  163. package/dist/utils/diff-parser.js +202 -0
  164. package/dist/utils/diff-parser.js.map +1 -0
  165. package/dist/utils/imported-auth-detector.d.ts +37 -0
  166. package/dist/utils/imported-auth-detector.d.ts.map +1 -0
  167. package/dist/utils/imported-auth-detector.js +251 -0
  168. package/dist/utils/imported-auth-detector.js.map +1 -0
  169. package/dist/utils/middleware-detector.d.ts +55 -0
  170. package/dist/utils/middleware-detector.d.ts.map +1 -0
  171. package/dist/utils/middleware-detector.js +260 -0
  172. package/dist/utils/middleware-detector.js.map +1 -0
  173. package/dist/utils/oauth-flow-detector.d.ts +41 -0
  174. package/dist/utils/oauth-flow-detector.d.ts.map +1 -0
  175. package/dist/utils/oauth-flow-detector.js +202 -0
  176. package/dist/utils/oauth-flow-detector.js.map +1 -0
  177. package/dist/utils/path-exclusions.d.ts +55 -0
  178. package/dist/utils/path-exclusions.d.ts.map +1 -0
  179. package/dist/utils/path-exclusions.js +222 -0
  180. package/dist/utils/path-exclusions.js.map +1 -0
  181. package/dist/utils/project-context-builder.d.ts +119 -0
  182. package/dist/utils/project-context-builder.d.ts.map +1 -0
  183. package/dist/utils/project-context-builder.js +534 -0
  184. package/dist/utils/project-context-builder.js.map +1 -0
  185. package/dist/utils/registry-clients.d.ts +93 -0
  186. package/dist/utils/registry-clients.d.ts.map +1 -0
  187. package/dist/utils/registry-clients.js +273 -0
  188. package/dist/utils/registry-clients.js.map +1 -0
  189. package/dist/utils/trpc-analyzer.d.ts +78 -0
  190. package/dist/utils/trpc-analyzer.d.ts.map +1 -0
  191. package/dist/utils/trpc-analyzer.js +297 -0
  192. package/dist/utils/trpc-analyzer.js.map +1 -0
  193. package/package.json +45 -0
  194. package/src/__tests__/benchmark/fixtures/false-positives.ts +227 -0
  195. package/src/__tests__/benchmark/fixtures/index.ts +68 -0
  196. package/src/__tests__/benchmark/fixtures/layer1/config-audit.ts +364 -0
  197. package/src/__tests__/benchmark/fixtures/layer1/hardcoded-secrets.ts +173 -0
  198. package/src/__tests__/benchmark/fixtures/layer1/high-entropy.ts +234 -0
  199. package/src/__tests__/benchmark/fixtures/layer1/index.ts +31 -0
  200. package/src/__tests__/benchmark/fixtures/layer1/sensitive-urls.ts +90 -0
  201. package/src/__tests__/benchmark/fixtures/layer1/weak-crypto.ts +197 -0
  202. package/src/__tests__/benchmark/fixtures/layer2/ai-agent-tools.ts +170 -0
  203. package/src/__tests__/benchmark/fixtures/layer2/ai-endpoint-protection.ts +418 -0
  204. package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +189 -0
  205. package/src/__tests__/benchmark/fixtures/layer2/ai-fingerprinting.ts +316 -0
  206. package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +178 -0
  207. package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +184 -0
  208. package/src/__tests__/benchmark/fixtures/layer2/ai-schema-validation.ts +434 -0
  209. package/src/__tests__/benchmark/fixtures/layer2/auth-antipatterns.ts +159 -0
  210. package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +112 -0
  211. package/src/__tests__/benchmark/fixtures/layer2/dangerous-functions.ts +246 -0
  212. package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +168 -0
  213. package/src/__tests__/benchmark/fixtures/layer2/framework-checks.ts +346 -0
  214. package/src/__tests__/benchmark/fixtures/layer2/index.ts +67 -0
  215. package/src/__tests__/benchmark/fixtures/layer2/injection-vulnerabilities.ts +239 -0
  216. package/src/__tests__/benchmark/fixtures/layer2/logic-gates.ts +246 -0
  217. package/src/__tests__/benchmark/fixtures/layer2/risky-imports.ts +231 -0
  218. package/src/__tests__/benchmark/fixtures/layer2/variables.ts +167 -0
  219. package/src/__tests__/benchmark/index.ts +29 -0
  220. package/src/__tests__/benchmark/run-benchmark.ts +144 -0
  221. package/src/__tests__/benchmark/run-depth-validation.ts +206 -0
  222. package/src/__tests__/benchmark/run-real-world-test.ts +243 -0
  223. package/src/__tests__/benchmark/security-benchmark-script.ts +1737 -0
  224. package/src/__tests__/benchmark/tier-integration-script.ts +177 -0
  225. package/src/__tests__/benchmark/types.ts +144 -0
  226. package/src/__tests__/benchmark/utils/test-runner.ts +475 -0
  227. package/src/__tests__/regression/known-false-positives.test.ts +467 -0
  228. package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +178 -0
  229. package/src/__tests__/snapshots/scan-depth.test.ts +258 -0
  230. package/src/__tests__/validation/analyze-results.ts +542 -0
  231. package/src/__tests__/validation/extract-for-triage.ts +146 -0
  232. package/src/__tests__/validation/fp-deep-analysis.ts +327 -0
  233. package/src/__tests__/validation/run-validation.ts +364 -0
  234. package/src/__tests__/validation/triage-template.md +132 -0
  235. package/src/formatters/cli-terminal.ts +446 -0
  236. package/src/formatters/github-comment.ts +382 -0
  237. package/src/formatters/grouping.ts +190 -0
  238. package/src/formatters/index.ts +47 -0
  239. package/src/formatters/vscode-diagnostic.ts +243 -0
  240. package/src/index.ts +823 -0
  241. package/src/layer1/comments.ts +218 -0
  242. package/src/layer1/config-audit.ts +289 -0
  243. package/src/layer1/entropy.ts +583 -0
  244. package/src/layer1/file-flags.ts +127 -0
  245. package/src/layer1/index.ts +181 -0
  246. package/src/layer1/patterns.ts +516 -0
  247. package/src/layer1/urls.ts +334 -0
  248. package/src/layer1/weak-crypto.ts +328 -0
  249. package/src/layer2/ai-agent-tools.ts +601 -0
  250. package/src/layer2/ai-endpoint-protection.ts +387 -0
  251. package/src/layer2/ai-execution-sinks.ts +580 -0
  252. package/src/layer2/ai-fingerprinting.ts +758 -0
  253. package/src/layer2/ai-prompt-hygiene.ts +411 -0
  254. package/src/layer2/ai-rag-safety.ts +511 -0
  255. package/src/layer2/ai-schema-validation.ts +421 -0
  256. package/src/layer2/auth-antipatterns.ts +394 -0
  257. package/src/layer2/byok-patterns.ts +336 -0
  258. package/src/layer2/dangerous-functions.ts +1563 -0
  259. package/src/layer2/data-exposure.ts +315 -0
  260. package/src/layer2/framework-checks.ts +433 -0
  261. package/src/layer2/index.ts +473 -0
  262. package/src/layer2/logic-gates.ts +206 -0
  263. package/src/layer2/risky-imports.ts +186 -0
  264. package/src/layer2/variables.ts +166 -0
  265. package/src/layer3/anthropic.ts +2030 -0
  266. package/src/layer3/index.ts +130 -0
  267. package/src/layer3/package-check.ts +604 -0
  268. package/src/modes/incremental.ts +293 -0
  269. package/src/tiers.ts +318 -0
  270. package/src/types.ts +284 -0
  271. package/src/utils/auth-helper-detector.ts +443 -0
  272. package/src/utils/context-helpers.ts +535 -0
  273. package/src/utils/diff-detector.ts +135 -0
  274. package/src/utils/diff-parser.ts +272 -0
  275. package/src/utils/imported-auth-detector.ts +320 -0
  276. package/src/utils/middleware-detector.ts +333 -0
  277. package/src/utils/oauth-flow-detector.ts +246 -0
  278. package/src/utils/path-exclusions.ts +266 -0
  279. package/src/utils/project-context-builder.ts +707 -0
  280. package/src/utils/registry-clients.ts +351 -0
  281. package/src/utils/trpc-analyzer.ts +382 -0
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ /**
3
+ * Incremental Scan Mode
4
+ * Optimized scanning for PR workflows - only scan changed files and surface relevant findings
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.runIncrementalScan = runIncrementalScan;
8
+ exports.createPRScanConfig = createPRScanConfig;
9
+ exports.formatIncrementalForPR = formatIncrementalForPR;
10
+ const layer1_1 = require("../layer1");
11
+ const layer2_1 = require("../layer2");
12
+ const diff_parser_1 = require("../utils/diff-parser");
13
+ const middleware_detector_1 = require("../utils/middleware-detector");
14
+ /**
15
+ * Run an incremental scan optimized for PR workflows
16
+ *
17
+ * This scans:
18
+ * 1. All changed files (added + modified)
19
+ * 2. Files that import changed files (for context)
20
+ * 3. Middleware files (for auth context)
21
+ *
22
+ * And only surfaces findings on/near changed lines.
23
+ */
24
+ async function runIncrementalScan(allFiles, options) {
25
+ const startTime = Date.now();
26
+ const { diffContent, changedFiles, strictLineMatching = false, contextWindow = 5, markAsIntroduced = true, previousFindings = [], } = options;
27
+ // Parse diff or file list to get changed files
28
+ let diffs;
29
+ if (diffContent) {
30
+ diffs = (0, diff_parser_1.parseDiff)(diffContent, contextWindow);
31
+ }
32
+ else if (changedFiles && changedFiles.length > 0) {
33
+ diffs = (0, diff_parser_1.parseChangedFileList)(changedFiles);
34
+ }
35
+ else {
36
+ // No diff info - scan everything but don't filter
37
+ console.log('[Incremental] No diff info provided, scanning all files');
38
+ diffs = new Map();
39
+ }
40
+ const changedPaths = (0, diff_parser_1.getChangedFilePaths)(diffs);
41
+ console.log(`[Incremental] Changed files: ${changedPaths.length}`);
42
+ // Build file index for import resolution
43
+ const fileIndex = new Map();
44
+ for (const file of allFiles) {
45
+ fileIndex.set(file.path, file);
46
+ }
47
+ // Determine which files to scan
48
+ const filesToScan = [];
49
+ const scannedPaths = new Set();
50
+ // 1. Add all changed files
51
+ for (const path of changedPaths) {
52
+ const file = fileIndex.get(path);
53
+ if (file && !scannedPaths.has(path)) {
54
+ filesToScan.push(file);
55
+ scannedPaths.add(path);
56
+ }
57
+ }
58
+ // 2. Add files that import changed files (for context)
59
+ // This helps detect issues where changes break dependencies
60
+ const importers = findImporters(allFiles, changedPaths);
61
+ for (const path of importers) {
62
+ if (!scannedPaths.has(path)) {
63
+ const file = fileIndex.get(path);
64
+ if (file) {
65
+ filesToScan.push(file);
66
+ scannedPaths.add(path);
67
+ }
68
+ }
69
+ }
70
+ // 3. Always include middleware files for auth context
71
+ const middlewareFile = allFiles.find(f => f.path.includes('middleware.ts') ||
72
+ f.path.includes('middleware.js'));
73
+ if (middlewareFile && !scannedPaths.has(middlewareFile.path)) {
74
+ filesToScan.push(middlewareFile);
75
+ scannedPaths.add(middlewareFile.path);
76
+ }
77
+ console.log(`[Incremental] Scanning ${filesToScan.length} files (${changedPaths.length} changed + ${importers.size} importers)`);
78
+ // Detect auth middleware from ALL files (for context)
79
+ const middlewareConfig = (0, middleware_detector_1.detectGlobalAuthMiddleware)(allFiles);
80
+ // Run Layer 1 + Layer 2 on selected files
81
+ const layer1Result = await (0, layer1_1.runLayer1Scan)(filesToScan);
82
+ const layer2Result = await (0, layer2_1.runLayer2Scan)(filesToScan, { middlewareConfig });
83
+ let allFindings = [...layer1Result.vulnerabilities, ...layer2Result.vulnerabilities];
84
+ // Filter to only findings on/near changed lines
85
+ if (diffs.size > 0) {
86
+ const beforeFilter = allFindings.length;
87
+ allFindings = (0, diff_parser_1.filterToChangedLines)(allFindings, diffs, { strictMode: strictLineMatching });
88
+ console.log(`[Incremental] Filtered findings: ${beforeFilter} → ${allFindings.length} (on/near changed lines)`);
89
+ }
90
+ // Mark findings as introduced and separate pre-existing
91
+ const introduced = [];
92
+ const preExisting = [];
93
+ if (previousFindings.length > 0) {
94
+ // Create fingerprints for previous findings
95
+ const previousFingerprints = new Set(previousFindings.map(f => `${f.filePath}:${f.lineNumber}:${f.category}`));
96
+ for (const finding of allFindings) {
97
+ const fingerprint = `${finding.filePath}:${finding.lineNumber}:${finding.category}`;
98
+ if (previousFingerprints.has(fingerprint)) {
99
+ preExisting.push(finding);
100
+ }
101
+ else {
102
+ if (markAsIntroduced) {
103
+ finding.validationNotes = (finding.validationNotes || '') + ' [Introduced in this PR]';
104
+ }
105
+ introduced.push(finding);
106
+ }
107
+ }
108
+ }
109
+ else {
110
+ // No previous findings - all are "introduced"
111
+ introduced.push(...allFindings);
112
+ }
113
+ const duration = Date.now() - startTime;
114
+ console.log(`[Incremental] Scan completed in ${duration}ms: ${introduced.length} new, ${preExisting.length} pre-existing`);
115
+ return {
116
+ findings: allFindings,
117
+ introduced,
118
+ preExisting,
119
+ filesScanned: filesToScan.length,
120
+ filesChanged: changedPaths.length,
121
+ diffs,
122
+ duration,
123
+ };
124
+ }
125
+ /**
126
+ * Find files that import any of the changed files
127
+ */
128
+ function findImporters(allFiles, changedPaths) {
129
+ const importers = new Set();
130
+ // Create patterns to match imports
131
+ const importPatterns = changedPaths.map(path => {
132
+ // Remove extension for import matching
133
+ const withoutExt = path.replace(/\.[^/.]+$/, '');
134
+ // Get just the filename without path for relative imports
135
+ const filename = withoutExt.split('/').pop() || '';
136
+ return { fullPath: withoutExt, filename };
137
+ });
138
+ for (const file of allFiles) {
139
+ // Skip if this file is already in changed paths
140
+ if (changedPaths.includes(file.path))
141
+ continue;
142
+ // Check if this file imports any changed file
143
+ for (const { fullPath, filename } of importPatterns) {
144
+ // Match various import patterns
145
+ const importRegex = new RegExp(`(?:import|require)\\s*(?:\\([^)]*|[^;]*from\\s*)['"]` +
146
+ `(?:\\.{0,2}/)?(?:${escapeRegex(fullPath)}|[^'"]*/${escapeRegex(filename)})['"]`, 'i');
147
+ if (importRegex.test(file.content)) {
148
+ importers.add(file.path);
149
+ break;
150
+ }
151
+ }
152
+ }
153
+ return importers;
154
+ }
155
+ /**
156
+ * Escape special regex characters
157
+ */
158
+ function escapeRegex(str) {
159
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
160
+ }
161
+ /**
162
+ * Create a PR-optimized scan config
163
+ */
164
+ function createPRScanConfig(changedFiles, options = {}) {
165
+ return {
166
+ mode: 'incremental',
167
+ changedFiles,
168
+ skipAIValidation: false, // Use AI for validation
169
+ skipLayer3: true, // Skip deep analysis for speed
170
+ maxAIValidationFiles: 20,
171
+ maxLayer3Files: 0,
172
+ scanDepth: 'cheap', // Fast feedback for PRs
173
+ ...options,
174
+ };
175
+ }
176
+ /**
177
+ * Format incremental scan result for PR comment
178
+ */
179
+ function formatIncrementalForPR(result) {
180
+ const blocking = result.introduced.filter(f => f.severity === 'critical' || f.severity === 'high');
181
+ let summary;
182
+ if (result.introduced.length === 0) {
183
+ summary = `✅ No new security issues introduced in this PR`;
184
+ }
185
+ else if (blocking.length > 0) {
186
+ summary = `🚨 ${blocking.length} blocking issue${blocking.length === 1 ? '' : 's'} introduced`;
187
+ }
188
+ else {
189
+ summary = `⚠️ ${result.introduced.length} new issue${result.introduced.length === 1 ? '' : 's'} to review`;
190
+ }
191
+ if (result.preExisting.length > 0) {
192
+ summary += ` (${result.preExisting.length} pre-existing)`;
193
+ }
194
+ return {
195
+ summary,
196
+ hasNewIssues: result.introduced.length > 0,
197
+ blockingIssues: blocking.length,
198
+ };
199
+ }
200
+ //# sourceMappingURL=incremental.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incremental.js","sourceRoot":"","sources":["../../src/modes/incremental.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Detector Tier System
3
+ *
4
+ * Provides a shared language for "how much we trust this detector" so we can:
5
+ * - Filter findings in runScan by tier + depth
6
+ * - Log tier breakdowns for tuning
7
+ * - Route AI validation budget toward Tier B
8
+ *
9
+ * Security reasoning:
10
+ * - Makes it explicit which detectors are safe to expose in cheap scans
11
+ * - Avoids "accidental promotion" of an experimental heuristic to production output
12
+ */
13
+ import type { VulnerabilityCategory } from './types';
14
+ /**
15
+ * Detector tiers control visibility and trust level:
16
+ *
17
+ * - core: High-precision SAST + core AI-safety detectors. Visible in all scan depths.
18
+ * - ai_assisted: Context-heavy heuristics that need AI validation. Shown in validated/deep.
19
+ * - experimental: High-noise signals used only for internal scoring/AI hints. Hidden from users.
20
+ */
21
+ export type DetectorTier = 'core' | 'ai_assisted' | 'experimental';
22
+ /**
23
+ * Tier statistics for logging and analysis
24
+ */
25
+ export interface TierStats {
26
+ core: number;
27
+ ai_assisted: number;
28
+ experimental: number;
29
+ }
30
+ /**
31
+ * Layer 1 detector names (internal identifiers matching detector function names)
32
+ */
33
+ export type Layer1DetectorName = 'known_secrets' | 'weak_crypto' | 'sensitive_urls' | 'entropy' | 'config_audit' | 'file_flags' | 'ai_comments';
34
+ /**
35
+ * Layer 1 tier assignments
36
+ *
37
+ * Tier A (core):
38
+ * - known_secrets: Hardcoded secrets are objectively bad and high-impact
39
+ * - weak_crypto: Weak crypto is a classic SAST finding with clear remediation
40
+ * - sensitive_urls: Hardcoded webhook URLs + tokens are real data exfil vectors
41
+ *
42
+ * Tier B (ai_assisted):
43
+ * - entropy: Great at finding candidates, needs AI to separate real secrets from noise
44
+ * - config_audit: Depends on project norms; better reviewed with AI + project context
45
+ * - file_flags: Subjective items should be AI-triaged (except committed .env = Tier A)
46
+ *
47
+ * Tier C (experimental):
48
+ * - ai_comments: Not directly a vuln; belongs in separate "AI hygiene" report
49
+ */
50
+ export declare const LAYER1_DETECTOR_TIERS: Record<Layer1DetectorName, DetectorTier>;
51
+ /**
52
+ * Mapping from vulnerability category to Layer 1 detector name
53
+ * Used for tier lookups when we only have the category
54
+ */
55
+ export declare const LAYER1_CATEGORY_TO_DETECTOR: Partial<Record<VulnerabilityCategory, Layer1DetectorName>>;
56
+ /**
57
+ * Layer 2 detector names (internal identifiers matching detector function names)
58
+ */
59
+ export type Layer2DetectorName = 'dangerous_functions' | 'byok_patterns' | 'ai_execution_sinks' | 'ai_agent_tools' | 'auth_antipatterns' | 'data_exposure' | 'ai_fingerprinting' | 'ai_prompt_hygiene' | 'logic_gates' | 'variables' | 'risky_imports' | 'framework_checks' | 'ai_rag_safety' | 'ai_endpoint_protection' | 'ai_schema_validation';
60
+ /**
61
+ * Layer 2 tier assignments
62
+ *
63
+ * Tier A (core) - High-precision, high-risk, clear remediation:
64
+ * - dangerous_functions: Classic injection footholds (eval, exec, unsafe SQL)
65
+ * - byok_patterns: Storing/logging BYOK is critical AI-era customer trust risk
66
+ * - ai_execution_sinks: Core to Oculum's AI story; LLM output as code/commands
67
+ * - ai_agent_tools: Over-permissive tools are central AI alignment problem
68
+ *
69
+ * Tier B (ai_assisted) - Context-heavy, need AI validation:
70
+ * - auth_antipatterns: Very context-dependent; needs middleware awareness
71
+ * - data_exposure: Logging queries/user IDs is often acceptable but context-specific
72
+ * - ai_fingerprinting: TypeScript 'any' at trust boundaries is risk indicator, not vuln
73
+ * - ai_prompt_hygiene: Needs semantic understanding of prompt design
74
+ *
75
+ * Tier C (experimental) - High-noise, internal use only:
76
+ * - logic_gates: Many hits with limited actionable signal
77
+ * - variables: Generic token/password variable names - too generic
78
+ * - risky_imports: Most imports are fine; keep tiny whitelist if proved valuable
79
+ * - framework_checks: Many findings are style/low-risk; prone to noisy lint
80
+ */
81
+ export declare const LAYER2_DETECTOR_TIERS: Record<Layer2DetectorName, DetectorTier>;
82
+ /**
83
+ * Mapping from vulnerability category to Layer 2 detector name
84
+ * Used for tier lookups when we only have the category
85
+ *
86
+ * NOTE: Some categories are used by multiple detectors:
87
+ * - ai_pattern: used by ai-fingerprinting (Tier B), byok-patterns (Tier A), dangerous-functions (Tier A)
88
+ * - insecure_config: used by config-audit (L1 Tier B), framework-checks (L2 Tier C)
89
+ *
90
+ * For ambiguous categories, we use the most conservative (highest trust) tier mapping.
91
+ * When category alone isn't sufficient, the orchestrator can use detector-specific tracking.
92
+ */
93
+ export declare const LAYER2_CATEGORY_TO_DETECTOR: Partial<Record<VulnerabilityCategory, Layer2DetectorName>>;
94
+ /**
95
+ * Get the tier for a vulnerability based on its category and layer
96
+ */
97
+ export declare function getTierForCategory(category: VulnerabilityCategory, layer: 1 | 2 | 3): DetectorTier;
98
+ /**
99
+ * Get tier for a Layer 1 detector by name
100
+ */
101
+ export declare function getLayer1DetectorTier(detector: Layer1DetectorName): DetectorTier;
102
+ /**
103
+ * Get tier for a Layer 2 detector by name
104
+ */
105
+ export declare function getLayer2DetectorTier(detector: Layer2DetectorName): DetectorTier;
106
+ /**
107
+ * Check if a tier should be visible at a given scan depth
108
+ */
109
+ export declare function isTierVisibleAtDepth(tier: DetectorTier, depth: 'cheap' | 'validated' | 'deep'): boolean;
110
+ /**
111
+ * Check if a tier should go through AI validation at a given scan depth
112
+ */
113
+ export declare function shouldValidateWithAI(tier: DetectorTier, depth: 'cheap' | 'validated' | 'deep'): boolean;
114
+ /**
115
+ * Compute tier statistics from an array of vulnerabilities
116
+ */
117
+ export declare function computeTierStats(vulnerabilities: Array<{
118
+ category: VulnerabilityCategory;
119
+ layer: 1 | 2 | 3;
120
+ }>): TierStats;
121
+ /**
122
+ * Format tier stats for logging
123
+ */
124
+ export declare function formatTierStats(stats: TierStats): string;
125
+ //# sourceMappingURL=tiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiers.d.ts","sourceRoot":"","sources":["../src/tiers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAEpD;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,cAAc,CAAA;AAElE;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;CACrB;AAMD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,aAAa,GACb,gBAAgB,GAChB,SAAS,GACT,cAAc,GACd,YAAY,GACZ,aAAa,CAAA;AAEjB;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,kBAAkB,EAAE,YAAY,CAQ1E,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,OAAO,CAAC,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,CASlG,CAAA;AAMD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,qBAAqB,GACrB,eAAe,GACf,oBAAoB,GACpB,gBAAgB,GAChB,mBAAmB,GACnB,eAAe,GACf,mBAAmB,GACnB,mBAAmB,GACnB,aAAa,GACb,WAAW,GACX,eAAe,GACf,kBAAkB,GAElB,eAAe,GACf,wBAAwB,GACxB,sBAAsB,CAAA;AAE1B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,kBAAkB,EAAE,YAAY,CAuB1E,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,EAAE,OAAO,CAAC,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,CAkClG,CAAA;AAMD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,qBAAqB,EAC/B,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GACf,YAAY,CAoBd;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,YAAY,CAEhF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,YAAY,CAEhF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,GACpC,OAAO,CAYT;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,GACpC,OAAO,CAUT;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,qBAAqB,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAAE,CAAC,GAC5E,SAAS,CAaX;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAExD"}
package/dist/tiers.js ADDED
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ /**
3
+ * Detector Tier System
4
+ *
5
+ * Provides a shared language for "how much we trust this detector" so we can:
6
+ * - Filter findings in runScan by tier + depth
7
+ * - Log tier breakdowns for tuning
8
+ * - Route AI validation budget toward Tier B
9
+ *
10
+ * Security reasoning:
11
+ * - Makes it explicit which detectors are safe to expose in cheap scans
12
+ * - Avoids "accidental promotion" of an experimental heuristic to production output
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.LAYER2_CATEGORY_TO_DETECTOR = exports.LAYER2_DETECTOR_TIERS = exports.LAYER1_CATEGORY_TO_DETECTOR = exports.LAYER1_DETECTOR_TIERS = void 0;
16
+ exports.getTierForCategory = getTierForCategory;
17
+ exports.getLayer1DetectorTier = getLayer1DetectorTier;
18
+ exports.getLayer2DetectorTier = getLayer2DetectorTier;
19
+ exports.isTierVisibleAtDepth = isTierVisibleAtDepth;
20
+ exports.shouldValidateWithAI = shouldValidateWithAI;
21
+ exports.computeTierStats = computeTierStats;
22
+ exports.formatTierStats = formatTierStats;
23
+ /**
24
+ * Layer 1 tier assignments
25
+ *
26
+ * Tier A (core):
27
+ * - known_secrets: Hardcoded secrets are objectively bad and high-impact
28
+ * - weak_crypto: Weak crypto is a classic SAST finding with clear remediation
29
+ * - sensitive_urls: Hardcoded webhook URLs + tokens are real data exfil vectors
30
+ *
31
+ * Tier B (ai_assisted):
32
+ * - entropy: Great at finding candidates, needs AI to separate real secrets from noise
33
+ * - config_audit: Depends on project norms; better reviewed with AI + project context
34
+ * - file_flags: Subjective items should be AI-triaged (except committed .env = Tier A)
35
+ *
36
+ * Tier C (experimental):
37
+ * - ai_comments: Not directly a vuln; belongs in separate "AI hygiene" report
38
+ */
39
+ exports.LAYER1_DETECTOR_TIERS = {
40
+ known_secrets: 'core',
41
+ weak_crypto: 'core',
42
+ sensitive_urls: 'core',
43
+ entropy: 'ai_assisted',
44
+ config_audit: 'ai_assisted',
45
+ file_flags: 'ai_assisted', // Mixed: committed .env is effectively core
46
+ ai_comments: 'experimental',
47
+ };
48
+ /**
49
+ * Mapping from vulnerability category to Layer 1 detector name
50
+ * Used for tier lookups when we only have the category
51
+ */
52
+ exports.LAYER1_CATEGORY_TO_DETECTOR = {
53
+ hardcoded_secret: 'known_secrets',
54
+ weak_crypto: 'weak_crypto',
55
+ sensitive_url: 'sensitive_urls',
56
+ high_entropy_string: 'entropy',
57
+ insecure_config: 'config_audit',
58
+ root_container: 'config_audit',
59
+ dangerous_file: 'file_flags',
60
+ ai_pattern: 'ai_comments', // AI comment patterns detected in Layer 1
61
+ };
62
+ /**
63
+ * Layer 2 tier assignments
64
+ *
65
+ * Tier A (core) - High-precision, high-risk, clear remediation:
66
+ * - dangerous_functions: Classic injection footholds (eval, exec, unsafe SQL)
67
+ * - byok_patterns: Storing/logging BYOK is critical AI-era customer trust risk
68
+ * - ai_execution_sinks: Core to Oculum's AI story; LLM output as code/commands
69
+ * - ai_agent_tools: Over-permissive tools are central AI alignment problem
70
+ *
71
+ * Tier B (ai_assisted) - Context-heavy, need AI validation:
72
+ * - auth_antipatterns: Very context-dependent; needs middleware awareness
73
+ * - data_exposure: Logging queries/user IDs is often acceptable but context-specific
74
+ * - ai_fingerprinting: TypeScript 'any' at trust boundaries is risk indicator, not vuln
75
+ * - ai_prompt_hygiene: Needs semantic understanding of prompt design
76
+ *
77
+ * Tier C (experimental) - High-noise, internal use only:
78
+ * - logic_gates: Many hits with limited actionable signal
79
+ * - variables: Generic token/password variable names - too generic
80
+ * - risky_imports: Most imports are fine; keep tiny whitelist if proved valuable
81
+ * - framework_checks: Many findings are style/low-risk; prone to noisy lint
82
+ */
83
+ exports.LAYER2_DETECTOR_TIERS = {
84
+ // Tier A - Core SAST / AI-safety
85
+ dangerous_functions: 'core',
86
+ byok_patterns: 'core',
87
+ ai_execution_sinks: 'core',
88
+ ai_agent_tools: 'core',
89
+ // Tier B - AI-assisted heuristics
90
+ auth_antipatterns: 'ai_assisted',
91
+ data_exposure: 'ai_assisted',
92
+ ai_fingerprinting: 'ai_assisted',
93
+ ai_prompt_hygiene: 'ai_assisted',
94
+ // Tier C - Experimental / high-noise
95
+ logic_gates: 'experimental',
96
+ variables: 'experimental',
97
+ risky_imports: 'experimental',
98
+ framework_checks: 'experimental',
99
+ // M5: New AI-era detectors
100
+ ai_rag_safety: 'core', // Tier A - Cross-tenant data access is critical
101
+ ai_endpoint_protection: 'core', // Tier A - Cost abuse / API exposure has clear signals
102
+ ai_schema_validation: 'ai_assisted', // Tier B - Context-dependent, benefits from AI validation
103
+ };
104
+ /**
105
+ * Mapping from vulnerability category to Layer 2 detector name
106
+ * Used for tier lookups when we only have the category
107
+ *
108
+ * NOTE: Some categories are used by multiple detectors:
109
+ * - ai_pattern: used by ai-fingerprinting (Tier B), byok-patterns (Tier A), dangerous-functions (Tier A)
110
+ * - insecure_config: used by config-audit (L1 Tier B), framework-checks (L2 Tier C)
111
+ *
112
+ * For ambiguous categories, we use the most conservative (highest trust) tier mapping.
113
+ * When category alone isn't sufficient, the orchestrator can use detector-specific tracking.
114
+ */
115
+ exports.LAYER2_CATEGORY_TO_DETECTOR = {
116
+ // Tier A categories (unambiguous)
117
+ dangerous_function: 'dangerous_functions',
118
+ sql_injection: 'dangerous_functions',
119
+ command_injection: 'dangerous_functions',
120
+ ai_unsafe_execution: 'ai_execution_sinks',
121
+ ai_overpermissive_tool: 'ai_agent_tools',
122
+ // Tier B categories
123
+ missing_auth: 'auth_antipatterns',
124
+ data_exposure: 'data_exposure',
125
+ ai_prompt_injection: 'ai_prompt_hygiene',
126
+ // ai_pattern is ambiguous - used by multiple detectors with different tiers:
127
+ // - ai-fingerprinting (Tier B): TypeScript 'any' at boundaries
128
+ // - byok-patterns (Tier A): BYOK key handling
129
+ // - dangerous-functions (Tier A): JSON.parse related AI patterns
130
+ // Default to ai_fingerprinting (Tier B) since it's most common; byok/dangerous_functions
131
+ // findings are usually categorized differently or handled explicitly
132
+ ai_pattern: 'ai_fingerprinting',
133
+ // Tier C categories
134
+ security_bypass: 'logic_gates',
135
+ sensitive_variable: 'variables',
136
+ suspicious_package: 'risky_imports',
137
+ cors_misconfiguration: 'framework_checks',
138
+ // insecure_config from framework-checks is Tier C in Layer 2
139
+ // (but same category from config-audit is Tier B in Layer 1 - handled by layer check)
140
+ insecure_config: 'framework_checks',
141
+ // M5: New AI-era categories
142
+ ai_rag_exfiltration: 'ai_rag_safety',
143
+ ai_endpoint_unprotected: 'ai_endpoint_protection',
144
+ ai_schema_mismatch: 'ai_schema_validation',
145
+ };
146
+ // ============================================================================
147
+ // Tier Lookup Helpers
148
+ // ============================================================================
149
+ /**
150
+ * Get the tier for a vulnerability based on its category and layer
151
+ */
152
+ function getTierForCategory(category, layer) {
153
+ if (layer === 1) {
154
+ const detector = exports.LAYER1_CATEGORY_TO_DETECTOR[category];
155
+ if (detector) {
156
+ return exports.LAYER1_DETECTOR_TIERS[detector];
157
+ }
158
+ }
159
+ else if (layer === 2) {
160
+ const detector = exports.LAYER2_CATEGORY_TO_DETECTOR[category];
161
+ if (detector) {
162
+ return exports.LAYER2_DETECTOR_TIERS[detector];
163
+ }
164
+ }
165
+ // Layer 3 findings are always core (AI semantic analysis)
166
+ if (layer === 3) {
167
+ return 'core';
168
+ }
169
+ // Default to ai_assisted if unmapped (safe default - will go through AI validation)
170
+ return 'ai_assisted';
171
+ }
172
+ /**
173
+ * Get tier for a Layer 1 detector by name
174
+ */
175
+ function getLayer1DetectorTier(detector) {
176
+ return exports.LAYER1_DETECTOR_TIERS[detector];
177
+ }
178
+ /**
179
+ * Get tier for a Layer 2 detector by name
180
+ */
181
+ function getLayer2DetectorTier(detector) {
182
+ return exports.LAYER2_DETECTOR_TIERS[detector];
183
+ }
184
+ /**
185
+ * Check if a tier should be visible at a given scan depth
186
+ */
187
+ function isTierVisibleAtDepth(tier, depth) {
188
+ switch (depth) {
189
+ case 'cheap':
190
+ // Only Tier A (core) findings are visible in cheap scans
191
+ return tier === 'core';
192
+ case 'validated':
193
+ // Tier A always visible, Tier B visible after AI validation
194
+ return tier === 'core' || tier === 'ai_assisted';
195
+ case 'deep':
196
+ // Same as validated for visibility (deep adds Layer 3, not more tiers)
197
+ return tier === 'core' || tier === 'ai_assisted';
198
+ }
199
+ }
200
+ /**
201
+ * Check if a tier should go through AI validation at a given scan depth
202
+ */
203
+ function shouldValidateWithAI(tier, depth) {
204
+ // Cheap scans skip AI validation entirely
205
+ if (depth === 'cheap') {
206
+ return false;
207
+ }
208
+ // In validated/deep, Tier B findings should go through AI validation
209
+ // Tier A is high-precision and doesn't need AI validation
210
+ // Tier C is hidden anyway
211
+ return tier === 'ai_assisted';
212
+ }
213
+ /**
214
+ * Compute tier statistics from an array of vulnerabilities
215
+ */
216
+ function computeTierStats(vulnerabilities) {
217
+ const stats = {
218
+ core: 0,
219
+ ai_assisted: 0,
220
+ experimental: 0,
221
+ };
222
+ for (const vuln of vulnerabilities) {
223
+ const tier = getTierForCategory(vuln.category, vuln.layer);
224
+ stats[tier]++;
225
+ }
226
+ return stats;
227
+ }
228
+ /**
229
+ * Format tier stats for logging
230
+ */
231
+ function formatTierStats(stats) {
232
+ return `tiers={core:${stats.core},ai_assisted:${stats.ai_assisted},experimental:${stats.experimental}}`;
233
+ }
234
+ //# sourceMappingURL=tiers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiers.js","sourceRoot":"","sources":["../src/tiers.ts"],"names":[],"mappings":"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"}