@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,258 @@
1
+ /**
2
+ * Scan Depth Snapshot Tests
3
+ *
4
+ * Tests the scanner output at different depth levels to ensure consistent results.
5
+ * Snapshots help detect unintended changes to scanner behavior.
6
+ *
7
+ * Run: npx jest src/__tests__/snapshots/scan-depth.test.ts
8
+ * Update snapshots: npx jest --updateSnapshot
9
+ */
10
+
11
+ import { runLayer1Scan } from '../../layer1'
12
+ import { runLayer2Scan } from '../../layer2'
13
+ import type { ScanFile, Vulnerability } from '../../types'
14
+
15
+ // Helper to normalize vulnerability output for snapshot comparison
16
+ // Removes volatile fields like timestamps and IDs
17
+ function normalizeVulnerabilities(vulns: Vulnerability[]): object[] {
18
+ return vulns
19
+ .map(v => ({
20
+ category: v.category,
21
+ severity: v.severity,
22
+ confidence: v.confidence,
23
+ layer: v.layer,
24
+ title: v.title,
25
+ lineNumber: v.lineNumber,
26
+ // Normalize line content to avoid whitespace issues
27
+ lineContent: v.lineContent?.trim(),
28
+ }))
29
+ .sort((a, b) => {
30
+ // Sort by line number, then category for consistent ordering
31
+ if (a.lineNumber !== b.lineNumber) return (a.lineNumber || 0) - (b.lineNumber || 0)
32
+ return a.category.localeCompare(b.category)
33
+ })
34
+ }
35
+
36
+ // Helper to run a cheap scan (Layer 1 only, no AI)
37
+ async function runCheapScan(file: ScanFile): Promise<object[]> {
38
+ const layer1Result = await runLayer1Scan([file])
39
+ return normalizeVulnerabilities(layer1Result.vulnerabilities)
40
+ }
41
+
42
+ // Helper to run a full scan (Layer 1 + Layer 2, no AI validation)
43
+ async function runFullScan(file: ScanFile): Promise<object[]> {
44
+ const [layer1Result, layer2Result] = await Promise.all([
45
+ runLayer1Scan([file]),
46
+ runLayer2Scan([file]),
47
+ ])
48
+ return normalizeVulnerabilities([...layer1Result.vulnerabilities, ...layer2Result.vulnerabilities])
49
+ }
50
+
51
+ describe('Scan Depth Snapshots', () => {
52
+ describe('Clean File - No Findings Expected', () => {
53
+ const cleanFile: ScanFile = {
54
+ path: 'src/utils/helpers.ts',
55
+ content: `
56
+ /**
57
+ * Safe utility functions
58
+ */
59
+
60
+ export function formatDate(date: Date): string {
61
+ return date.toISOString()
62
+ }
63
+
64
+ export function capitalize(str: string): string {
65
+ return str.charAt(0).toUpperCase() + str.slice(1)
66
+ }
67
+
68
+ export function clamp(value: number, min: number, max: number): number {
69
+ return Math.min(Math.max(value, min), max)
70
+ }
71
+ `,
72
+ language: 'typescript',
73
+ size: 300,
74
+ }
75
+
76
+ it('cheap scan should produce no findings', async () => {
77
+ const results = await runCheapScan(cleanFile)
78
+ expect(results).toMatchSnapshot()
79
+ })
80
+
81
+ it('full scan should produce no findings', async () => {
82
+ const results = await runFullScan(cleanFile)
83
+ expect(results).toMatchSnapshot()
84
+ })
85
+ })
86
+
87
+ describe('Hardcoded Secrets - Critical Findings', () => {
88
+ const secretsFile: ScanFile = {
89
+ path: 'src/config/api-keys.ts',
90
+ content: `
91
+ // API Keys - CRITICAL
92
+ const OPENAI_API_KEY = "sk-proj-abc123def456ghi789jkl012mno345pqr678stu901vwx"
93
+ const AWS_ACCESS_KEY_ID = "AKIAIOSFODNN7EXAMPLE"
94
+ const AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
95
+ `,
96
+ language: 'typescript',
97
+ size: 250,
98
+ }
99
+
100
+ it('cheap scan should detect hardcoded secrets', async () => {
101
+ const results = await runCheapScan(secretsFile)
102
+ expect(results).toMatchSnapshot()
103
+ })
104
+
105
+ it('full scan should detect hardcoded secrets', async () => {
106
+ const results = await runFullScan(secretsFile)
107
+ expect(results).toMatchSnapshot()
108
+ })
109
+ })
110
+
111
+ describe('Mixed Severity - Multiple Issue Types', () => {
112
+ const mixedFile: ScanFile = {
113
+ path: 'src/api/handler.ts',
114
+ content: `
115
+ import express from 'express'
116
+
117
+ const app = express()
118
+
119
+ // Hardcoded secret - CRITICAL
120
+ const API_KEY = "sk-live-1234567890abcdef"
121
+
122
+ // CORS wildcard - MEDIUM
123
+ app.use(cors({ origin: '*' }))
124
+
125
+ // Weak crypto - HIGH
126
+ const hash = crypto.createHash('md5')
127
+
128
+ // innerHTML with user input - HIGH
129
+ element.innerHTML = userInput
130
+
131
+ // Debug logging - LOW
132
+ console.log('Debug:', sensitiveData)
133
+ `,
134
+ language: 'typescript',
135
+ size: 400,
136
+ }
137
+
138
+ it('cheap scan should detect Layer 1 issues', async () => {
139
+ const results = await runCheapScan(mixedFile)
140
+ expect(results).toMatchSnapshot()
141
+ })
142
+
143
+ it('full scan should detect all issues', async () => {
144
+ const results = await runFullScan(mixedFile)
145
+ expect(results).toMatchSnapshot()
146
+ })
147
+ })
148
+
149
+ describe('AI-Era Patterns - Modern Security Issues', () => {
150
+ const aiEraFile: ScanFile = {
151
+ path: 'src/ai/chat-handler.ts',
152
+ content: `
153
+ import OpenAI from 'openai'
154
+
155
+ // User API key in request - transient BYOK
156
+ export async function handleChat(req: Request) {
157
+ const openai = new OpenAI({ apiKey: req.body.userApiKey })
158
+
159
+ // User input directly in prompt - prompt injection risk
160
+ const response = await openai.chat.completions.create({
161
+ model: 'gpt-4',
162
+ messages: [{ role: 'user', content: req.body.message }],
163
+ })
164
+
165
+ return response.choices[0].message
166
+ }
167
+ `,
168
+ language: 'typescript',
169
+ size: 400,
170
+ }
171
+
172
+ it('cheap scan should detect Layer 1 patterns', async () => {
173
+ const results = await runCheapScan(aiEraFile)
174
+ expect(results).toMatchSnapshot()
175
+ })
176
+
177
+ it('full scan should detect AI-era security patterns', async () => {
178
+ const results = await runFullScan(aiEraFile)
179
+ expect(results).toMatchSnapshot()
180
+ })
181
+ })
182
+
183
+ describe('Auth Patterns - Missing Authentication', () => {
184
+ const authFile: ScanFile = {
185
+ path: 'src/app/api/users/route.ts',
186
+ content: `
187
+ import { NextResponse } from 'next/server'
188
+ import { db } from '@/lib/db'
189
+
190
+ // API route without auth check
191
+ export async function GET(request: Request) {
192
+ const users = await db.user.findMany()
193
+ return NextResponse.json(users)
194
+ }
195
+
196
+ export async function DELETE(request: Request) {
197
+ const { id } = await request.json()
198
+ await db.user.delete({ where: { id } })
199
+ return NextResponse.json({ success: true })
200
+ }
201
+ `,
202
+ language: 'typescript',
203
+ size: 350,
204
+ }
205
+
206
+ it('cheap scan should detect basic patterns', async () => {
207
+ const results = await runCheapScan(authFile)
208
+ expect(results).toMatchSnapshot()
209
+ })
210
+
211
+ it('full scan should detect missing auth patterns', async () => {
212
+ const results = await runFullScan(authFile)
213
+ expect(results).toMatchSnapshot()
214
+ })
215
+ })
216
+
217
+ describe('Safe File - No False Positives', () => {
218
+ const safeFile: ScanFile = {
219
+ path: 'src/components/Dashboard.tsx',
220
+ content: `
221
+ import { useState, useEffect } from 'react'
222
+
223
+ // CSS classes - should NOT be flagged as high entropy
224
+ const styles = 'flex items-center justify-between p-4 bg-gray-100'
225
+
226
+ // Environment variable reference - should NOT be flagged
227
+ const apiUrl = process.env.API_URL
228
+
229
+ // UUID - should NOT be flagged as secret
230
+ const sessionId = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
231
+
232
+ export function Dashboard() {
233
+ const [data, setData] = useState(null)
234
+
235
+ useEffect(() => {
236
+ fetch(apiUrl + '/data')
237
+ .then(res => res.json())
238
+ .then(setData)
239
+ }, [])
240
+
241
+ return <div className={styles}>{data}</div>
242
+ }
243
+ `,
244
+ language: 'typescript',
245
+ size: 500,
246
+ }
247
+
248
+ it('cheap scan should produce minimal findings', async () => {
249
+ const results = await runCheapScan(safeFile)
250
+ expect(results).toMatchSnapshot()
251
+ })
252
+
253
+ it('full scan should produce minimal findings', async () => {
254
+ const results = await runFullScan(safeFile)
255
+ expect(results).toMatchSnapshot()
256
+ })
257
+ })
258
+ })