@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.
- package/dist/formatters/cli-terminal.d.ts +27 -0
- package/dist/formatters/cli-terminal.d.ts.map +1 -0
- package/dist/formatters/cli-terminal.js +412 -0
- package/dist/formatters/cli-terminal.js.map +1 -0
- package/dist/formatters/github-comment.d.ts +41 -0
- package/dist/formatters/github-comment.d.ts.map +1 -0
- package/dist/formatters/github-comment.js +306 -0
- package/dist/formatters/github-comment.js.map +1 -0
- package/dist/formatters/grouping.d.ts +52 -0
- package/dist/formatters/grouping.d.ts.map +1 -0
- package/dist/formatters/grouping.js +152 -0
- package/dist/formatters/grouping.js.map +1 -0
- package/dist/formatters/index.d.ts +9 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +35 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/vscode-diagnostic.d.ts +103 -0
- package/dist/formatters/vscode-diagnostic.d.ts.map +1 -0
- package/dist/formatters/vscode-diagnostic.js +151 -0
- package/dist/formatters/vscode-diagnostic.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +648 -0
- package/dist/index.js.map +1 -0
- package/dist/layer1/comments.d.ts +8 -0
- package/dist/layer1/comments.d.ts.map +1 -0
- package/dist/layer1/comments.js +203 -0
- package/dist/layer1/comments.js.map +1 -0
- package/dist/layer1/config-audit.d.ts +8 -0
- package/dist/layer1/config-audit.d.ts.map +1 -0
- package/dist/layer1/config-audit.js +252 -0
- package/dist/layer1/config-audit.js.map +1 -0
- package/dist/layer1/entropy.d.ts +8 -0
- package/dist/layer1/entropy.d.ts.map +1 -0
- package/dist/layer1/entropy.js +500 -0
- package/dist/layer1/entropy.js.map +1 -0
- package/dist/layer1/file-flags.d.ts +7 -0
- package/dist/layer1/file-flags.d.ts.map +1 -0
- package/dist/layer1/file-flags.js +112 -0
- package/dist/layer1/file-flags.js.map +1 -0
- package/dist/layer1/index.d.ts +36 -0
- package/dist/layer1/index.d.ts.map +1 -0
- package/dist/layer1/index.js +132 -0
- package/dist/layer1/index.js.map +1 -0
- package/dist/layer1/patterns.d.ts +8 -0
- package/dist/layer1/patterns.d.ts.map +1 -0
- package/dist/layer1/patterns.js +482 -0
- package/dist/layer1/patterns.js.map +1 -0
- package/dist/layer1/urls.d.ts +8 -0
- package/dist/layer1/urls.d.ts.map +1 -0
- package/dist/layer1/urls.js +296 -0
- package/dist/layer1/urls.js.map +1 -0
- package/dist/layer1/weak-crypto.d.ts +7 -0
- package/dist/layer1/weak-crypto.d.ts.map +1 -0
- package/dist/layer1/weak-crypto.js +291 -0
- package/dist/layer1/weak-crypto.js.map +1 -0
- package/dist/layer2/ai-agent-tools.d.ts +19 -0
- package/dist/layer2/ai-agent-tools.d.ts.map +1 -0
- package/dist/layer2/ai-agent-tools.js +528 -0
- package/dist/layer2/ai-agent-tools.js.map +1 -0
- package/dist/layer2/ai-endpoint-protection.d.ts +36 -0
- package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -0
- package/dist/layer2/ai-endpoint-protection.js +332 -0
- package/dist/layer2/ai-endpoint-protection.js.map +1 -0
- package/dist/layer2/ai-execution-sinks.d.ts +18 -0
- package/dist/layer2/ai-execution-sinks.d.ts.map +1 -0
- package/dist/layer2/ai-execution-sinks.js +496 -0
- package/dist/layer2/ai-execution-sinks.js.map +1 -0
- package/dist/layer2/ai-fingerprinting.d.ts +7 -0
- package/dist/layer2/ai-fingerprinting.d.ts.map +1 -0
- package/dist/layer2/ai-fingerprinting.js +654 -0
- package/dist/layer2/ai-fingerprinting.js.map +1 -0
- package/dist/layer2/ai-prompt-hygiene.d.ts +19 -0
- package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -0
- package/dist/layer2/ai-prompt-hygiene.js +356 -0
- package/dist/layer2/ai-prompt-hygiene.js.map +1 -0
- package/dist/layer2/ai-rag-safety.d.ts +21 -0
- package/dist/layer2/ai-rag-safety.d.ts.map +1 -0
- package/dist/layer2/ai-rag-safety.js +459 -0
- package/dist/layer2/ai-rag-safety.js.map +1 -0
- package/dist/layer2/ai-schema-validation.d.ts +25 -0
- package/dist/layer2/ai-schema-validation.d.ts.map +1 -0
- package/dist/layer2/ai-schema-validation.js +375 -0
- package/dist/layer2/ai-schema-validation.js.map +1 -0
- package/dist/layer2/auth-antipatterns.d.ts +20 -0
- package/dist/layer2/auth-antipatterns.d.ts.map +1 -0
- package/dist/layer2/auth-antipatterns.js +333 -0
- package/dist/layer2/auth-antipatterns.js.map +1 -0
- package/dist/layer2/byok-patterns.d.ts +12 -0
- package/dist/layer2/byok-patterns.d.ts.map +1 -0
- package/dist/layer2/byok-patterns.js +299 -0
- package/dist/layer2/byok-patterns.js.map +1 -0
- package/dist/layer2/dangerous-functions.d.ts +7 -0
- package/dist/layer2/dangerous-functions.d.ts.map +1 -0
- package/dist/layer2/dangerous-functions.js +1375 -0
- package/dist/layer2/dangerous-functions.js.map +1 -0
- package/dist/layer2/data-exposure.d.ts +16 -0
- package/dist/layer2/data-exposure.d.ts.map +1 -0
- package/dist/layer2/data-exposure.js +279 -0
- package/dist/layer2/data-exposure.js.map +1 -0
- package/dist/layer2/framework-checks.d.ts +7 -0
- package/dist/layer2/framework-checks.d.ts.map +1 -0
- package/dist/layer2/framework-checks.js +388 -0
- package/dist/layer2/framework-checks.js.map +1 -0
- package/dist/layer2/index.d.ts +58 -0
- package/dist/layer2/index.d.ts.map +1 -0
- package/dist/layer2/index.js +380 -0
- package/dist/layer2/index.js.map +1 -0
- package/dist/layer2/logic-gates.d.ts +7 -0
- package/dist/layer2/logic-gates.d.ts.map +1 -0
- package/dist/layer2/logic-gates.js +182 -0
- package/dist/layer2/logic-gates.js.map +1 -0
- package/dist/layer2/risky-imports.d.ts +7 -0
- package/dist/layer2/risky-imports.d.ts.map +1 -0
- package/dist/layer2/risky-imports.js +161 -0
- package/dist/layer2/risky-imports.js.map +1 -0
- package/dist/layer2/variables.d.ts +8 -0
- package/dist/layer2/variables.d.ts.map +1 -0
- package/dist/layer2/variables.js +152 -0
- package/dist/layer2/variables.js.map +1 -0
- package/dist/layer3/anthropic.d.ts +83 -0
- package/dist/layer3/anthropic.d.ts.map +1 -0
- package/dist/layer3/anthropic.js +1745 -0
- package/dist/layer3/anthropic.js.map +1 -0
- package/dist/layer3/index.d.ts +24 -0
- package/dist/layer3/index.d.ts.map +1 -0
- package/dist/layer3/index.js +119 -0
- package/dist/layer3/index.js.map +1 -0
- package/dist/layer3/openai.d.ts +25 -0
- package/dist/layer3/openai.d.ts.map +1 -0
- package/dist/layer3/openai.js +238 -0
- package/dist/layer3/openai.js.map +1 -0
- package/dist/layer3/package-check.d.ts +63 -0
- package/dist/layer3/package-check.d.ts.map +1 -0
- package/dist/layer3/package-check.js +508 -0
- package/dist/layer3/package-check.js.map +1 -0
- package/dist/modes/incremental.d.ts +66 -0
- package/dist/modes/incremental.d.ts.map +1 -0
- package/dist/modes/incremental.js +200 -0
- package/dist/modes/incremental.js.map +1 -0
- package/dist/tiers.d.ts +125 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +234 -0
- package/dist/tiers.js.map +1 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +50 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/auth-helper-detector.d.ts +56 -0
- package/dist/utils/auth-helper-detector.d.ts.map +1 -0
- package/dist/utils/auth-helper-detector.js +360 -0
- package/dist/utils/auth-helper-detector.js.map +1 -0
- package/dist/utils/context-helpers.d.ts +96 -0
- package/dist/utils/context-helpers.d.ts.map +1 -0
- package/dist/utils/context-helpers.js +493 -0
- package/dist/utils/context-helpers.js.map +1 -0
- package/dist/utils/diff-detector.d.ts +53 -0
- package/dist/utils/diff-detector.d.ts.map +1 -0
- package/dist/utils/diff-detector.js +104 -0
- package/dist/utils/diff-detector.js.map +1 -0
- package/dist/utils/diff-parser.d.ts +80 -0
- package/dist/utils/diff-parser.d.ts.map +1 -0
- package/dist/utils/diff-parser.js +202 -0
- package/dist/utils/diff-parser.js.map +1 -0
- package/dist/utils/imported-auth-detector.d.ts +37 -0
- package/dist/utils/imported-auth-detector.d.ts.map +1 -0
- package/dist/utils/imported-auth-detector.js +251 -0
- package/dist/utils/imported-auth-detector.js.map +1 -0
- package/dist/utils/middleware-detector.d.ts +55 -0
- package/dist/utils/middleware-detector.d.ts.map +1 -0
- package/dist/utils/middleware-detector.js +260 -0
- package/dist/utils/middleware-detector.js.map +1 -0
- package/dist/utils/oauth-flow-detector.d.ts +41 -0
- package/dist/utils/oauth-flow-detector.d.ts.map +1 -0
- package/dist/utils/oauth-flow-detector.js +202 -0
- package/dist/utils/oauth-flow-detector.js.map +1 -0
- package/dist/utils/path-exclusions.d.ts +55 -0
- package/dist/utils/path-exclusions.d.ts.map +1 -0
- package/dist/utils/path-exclusions.js +222 -0
- package/dist/utils/path-exclusions.js.map +1 -0
- package/dist/utils/project-context-builder.d.ts +119 -0
- package/dist/utils/project-context-builder.d.ts.map +1 -0
- package/dist/utils/project-context-builder.js +534 -0
- package/dist/utils/project-context-builder.js.map +1 -0
- package/dist/utils/registry-clients.d.ts +93 -0
- package/dist/utils/registry-clients.d.ts.map +1 -0
- package/dist/utils/registry-clients.js +273 -0
- package/dist/utils/registry-clients.js.map +1 -0
- package/dist/utils/trpc-analyzer.d.ts +78 -0
- package/dist/utils/trpc-analyzer.d.ts.map +1 -0
- package/dist/utils/trpc-analyzer.js +297 -0
- package/dist/utils/trpc-analyzer.js.map +1 -0
- package/package.json +45 -0
- package/src/__tests__/benchmark/fixtures/false-positives.ts +227 -0
- package/src/__tests__/benchmark/fixtures/index.ts +68 -0
- package/src/__tests__/benchmark/fixtures/layer1/config-audit.ts +364 -0
- package/src/__tests__/benchmark/fixtures/layer1/hardcoded-secrets.ts +173 -0
- package/src/__tests__/benchmark/fixtures/layer1/high-entropy.ts +234 -0
- package/src/__tests__/benchmark/fixtures/layer1/index.ts +31 -0
- package/src/__tests__/benchmark/fixtures/layer1/sensitive-urls.ts +90 -0
- package/src/__tests__/benchmark/fixtures/layer1/weak-crypto.ts +197 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-agent-tools.ts +170 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-endpoint-protection.ts +418 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +189 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-fingerprinting.ts +316 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +178 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +184 -0
- package/src/__tests__/benchmark/fixtures/layer2/ai-schema-validation.ts +434 -0
- package/src/__tests__/benchmark/fixtures/layer2/auth-antipatterns.ts +159 -0
- package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +112 -0
- package/src/__tests__/benchmark/fixtures/layer2/dangerous-functions.ts +246 -0
- package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +168 -0
- package/src/__tests__/benchmark/fixtures/layer2/framework-checks.ts +346 -0
- package/src/__tests__/benchmark/fixtures/layer2/index.ts +67 -0
- package/src/__tests__/benchmark/fixtures/layer2/injection-vulnerabilities.ts +239 -0
- package/src/__tests__/benchmark/fixtures/layer2/logic-gates.ts +246 -0
- package/src/__tests__/benchmark/fixtures/layer2/risky-imports.ts +231 -0
- package/src/__tests__/benchmark/fixtures/layer2/variables.ts +167 -0
- package/src/__tests__/benchmark/index.ts +29 -0
- package/src/__tests__/benchmark/run-benchmark.ts +144 -0
- package/src/__tests__/benchmark/run-depth-validation.ts +206 -0
- package/src/__tests__/benchmark/run-real-world-test.ts +243 -0
- package/src/__tests__/benchmark/security-benchmark-script.ts +1737 -0
- package/src/__tests__/benchmark/tier-integration-script.ts +177 -0
- package/src/__tests__/benchmark/types.ts +144 -0
- package/src/__tests__/benchmark/utils/test-runner.ts +475 -0
- package/src/__tests__/regression/known-false-positives.test.ts +467 -0
- package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +178 -0
- package/src/__tests__/snapshots/scan-depth.test.ts +258 -0
- package/src/__tests__/validation/analyze-results.ts +542 -0
- package/src/__tests__/validation/extract-for-triage.ts +146 -0
- package/src/__tests__/validation/fp-deep-analysis.ts +327 -0
- package/src/__tests__/validation/run-validation.ts +364 -0
- package/src/__tests__/validation/triage-template.md +132 -0
- package/src/formatters/cli-terminal.ts +446 -0
- package/src/formatters/github-comment.ts +382 -0
- package/src/formatters/grouping.ts +190 -0
- package/src/formatters/index.ts +47 -0
- package/src/formatters/vscode-diagnostic.ts +243 -0
- package/src/index.ts +823 -0
- package/src/layer1/comments.ts +218 -0
- package/src/layer1/config-audit.ts +289 -0
- package/src/layer1/entropy.ts +583 -0
- package/src/layer1/file-flags.ts +127 -0
- package/src/layer1/index.ts +181 -0
- package/src/layer1/patterns.ts +516 -0
- package/src/layer1/urls.ts +334 -0
- package/src/layer1/weak-crypto.ts +328 -0
- package/src/layer2/ai-agent-tools.ts +601 -0
- package/src/layer2/ai-endpoint-protection.ts +387 -0
- package/src/layer2/ai-execution-sinks.ts +580 -0
- package/src/layer2/ai-fingerprinting.ts +758 -0
- package/src/layer2/ai-prompt-hygiene.ts +411 -0
- package/src/layer2/ai-rag-safety.ts +511 -0
- package/src/layer2/ai-schema-validation.ts +421 -0
- package/src/layer2/auth-antipatterns.ts +394 -0
- package/src/layer2/byok-patterns.ts +336 -0
- package/src/layer2/dangerous-functions.ts +1563 -0
- package/src/layer2/data-exposure.ts +315 -0
- package/src/layer2/framework-checks.ts +433 -0
- package/src/layer2/index.ts +473 -0
- package/src/layer2/logic-gates.ts +206 -0
- package/src/layer2/risky-imports.ts +186 -0
- package/src/layer2/variables.ts +166 -0
- package/src/layer3/anthropic.ts +2030 -0
- package/src/layer3/index.ts +130 -0
- package/src/layer3/package-check.ts +604 -0
- package/src/modes/incremental.ts +293 -0
- package/src/tiers.ts +318 -0
- package/src/types.ts +284 -0
- package/src/utils/auth-helper-detector.ts +443 -0
- package/src/utils/context-helpers.ts +535 -0
- package/src/utils/diff-detector.ts +135 -0
- package/src/utils/diff-parser.ts +272 -0
- package/src/utils/imported-auth-detector.ts +320 -0
- package/src/utils/middleware-detector.ts +333 -0
- package/src/utils/oauth-flow-detector.ts +246 -0
- package/src/utils/path-exclusions.ts +266 -0
- package/src/utils/project-context-builder.ts +707 -0
- package/src/utils/registry-clients.ts +351 -0
- package/src/utils/trpc-analyzer.ts +382 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier System Integration Test
|
|
3
|
+
*
|
|
4
|
+
* This test validates that the detector tier system correctly filters
|
|
5
|
+
* findings based on scan depth (cheap/validated/deep).
|
|
6
|
+
*
|
|
7
|
+
* Run with: npx tsx src/lib/scanner/__tests__/tier-integration.test.ts
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { runLayer1Scan } from '../layer1'
|
|
11
|
+
import { runLayer2Scan } from '../layer2'
|
|
12
|
+
import type { ScanFile, Vulnerability } from '../types'
|
|
13
|
+
import {
|
|
14
|
+
getTierForCategory,
|
|
15
|
+
computeTierStats,
|
|
16
|
+
formatTierStats,
|
|
17
|
+
LAYER1_DETECTOR_TIERS,
|
|
18
|
+
LAYER2_DETECTOR_TIERS,
|
|
19
|
+
} from '../tiers'
|
|
20
|
+
|
|
21
|
+
// Mock files with various vulnerability patterns
|
|
22
|
+
const mockFiles: ScanFile[] = [
|
|
23
|
+
{
|
|
24
|
+
path: 'src/api/auth/route.ts',
|
|
25
|
+
content: `
|
|
26
|
+
// Tier A: Known secret (patterns.ts)
|
|
27
|
+
const API_KEY = "sk-ant-api03-abc123xyz456"
|
|
28
|
+
|
|
29
|
+
// Tier A: Dangerous function (dangerous-functions.ts)
|
|
30
|
+
const result = eval(userInput)
|
|
31
|
+
|
|
32
|
+
// Tier B: High entropy (entropy.ts)
|
|
33
|
+
const token = "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9"
|
|
34
|
+
|
|
35
|
+
// Tier C: Sensitive variable (variables.ts)
|
|
36
|
+
const password = getPassword()
|
|
37
|
+
|
|
38
|
+
// Tier C: Logic gate (logic-gates.ts)
|
|
39
|
+
if (isAdmin || bypassAuth) {
|
|
40
|
+
allowAccess()
|
|
41
|
+
}
|
|
42
|
+
`,
|
|
43
|
+
language: 'typescript',
|
|
44
|
+
size: 500,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
path: 'src/lib/ai/client.ts',
|
|
48
|
+
content: `
|
|
49
|
+
// Tier A: AI execution sink (ai-execution-sinks.ts)
|
|
50
|
+
const code = await openai.chat.completions.create({
|
|
51
|
+
model: "gpt-4",
|
|
52
|
+
messages: [{ role: "user", content: prompt }]
|
|
53
|
+
})
|
|
54
|
+
eval(code.choices[0].message.content)
|
|
55
|
+
|
|
56
|
+
// Tier B: AI fingerprint (ai-fingerprinting.ts)
|
|
57
|
+
function processData(data: any): any {
|
|
58
|
+
return data
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Tier A: BYOK pattern (byok-patterns.ts)
|
|
62
|
+
const apiKey = request.headers.get('x-api-key')
|
|
63
|
+
await client.chat({
|
|
64
|
+
apiKey: apiKey,
|
|
65
|
+
messages: []
|
|
66
|
+
})
|
|
67
|
+
`,
|
|
68
|
+
language: 'typescript',
|
|
69
|
+
size: 400,
|
|
70
|
+
},
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
async function runTest() {
|
|
74
|
+
console.log('='.repeat(60))
|
|
75
|
+
console.log('Tier System Integration Test')
|
|
76
|
+
console.log('='.repeat(60))
|
|
77
|
+
|
|
78
|
+
// Display tier mappings
|
|
79
|
+
console.log('\n📋 Layer 1 Detector Tiers:')
|
|
80
|
+
for (const [detector, tier] of Object.entries(LAYER1_DETECTOR_TIERS)) {
|
|
81
|
+
console.log(` - ${detector}: ${tier}`)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log('\n📋 Layer 2 Detector Tiers:')
|
|
85
|
+
for (const [detector, tier] of Object.entries(LAYER2_DETECTOR_TIERS)) {
|
|
86
|
+
console.log(` - ${detector}: ${tier}`)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Run Layer 1
|
|
90
|
+
console.log('\n' + '='.repeat(60))
|
|
91
|
+
console.log('Running Layer 1 Scan...')
|
|
92
|
+
console.log('='.repeat(60))
|
|
93
|
+
|
|
94
|
+
const layer1Result = await runLayer1Scan(mockFiles)
|
|
95
|
+
console.log(`\nLayer 1 found ${layer1Result.vulnerabilities.length} vulnerabilities`)
|
|
96
|
+
console.log(`Tier stats: ${formatTierStats(layer1Result.stats.tiers)}`)
|
|
97
|
+
|
|
98
|
+
// Group Layer 1 findings by tier
|
|
99
|
+
const layer1ByTier = groupByTier(layer1Result.vulnerabilities)
|
|
100
|
+
console.log('\nLayer 1 by tier:')
|
|
101
|
+
console.log(` - Core (A): ${layer1ByTier.core.length} findings`)
|
|
102
|
+
console.log(` - AI-Assisted (B): ${layer1ByTier.ai_assisted.length} findings`)
|
|
103
|
+
console.log(` - Experimental (C): ${layer1ByTier.experimental.length} findings`)
|
|
104
|
+
|
|
105
|
+
// Run Layer 2
|
|
106
|
+
console.log('\n' + '='.repeat(60))
|
|
107
|
+
console.log('Running Layer 2 Scan...')
|
|
108
|
+
console.log('='.repeat(60))
|
|
109
|
+
|
|
110
|
+
const layer2Result = await runLayer2Scan(mockFiles)
|
|
111
|
+
console.log(`\nLayer 2 found ${layer2Result.vulnerabilities.length} vulnerabilities`)
|
|
112
|
+
console.log(`Tier stats: ${formatTierStats(layer2Result.stats.tiers)}`)
|
|
113
|
+
|
|
114
|
+
// Group Layer 2 findings by tier
|
|
115
|
+
const layer2ByTier = groupByTier(layer2Result.vulnerabilities)
|
|
116
|
+
console.log('\nLayer 2 by tier:')
|
|
117
|
+
console.log(` - Core (A): ${layer2ByTier.core.length} findings`)
|
|
118
|
+
console.log(` - AI-Assisted (B): ${layer2ByTier.ai_assisted.length} findings`)
|
|
119
|
+
console.log(` - Experimental (C): ${layer2ByTier.experimental.length} findings`)
|
|
120
|
+
|
|
121
|
+
// Print all findings with their tiers
|
|
122
|
+
console.log('\n' + '='.repeat(60))
|
|
123
|
+
console.log('All Findings with Tier Classification')
|
|
124
|
+
console.log('='.repeat(60))
|
|
125
|
+
|
|
126
|
+
const allFindings = [...layer1Result.vulnerabilities, ...layer2Result.vulnerabilities]
|
|
127
|
+
for (const finding of allFindings) {
|
|
128
|
+
const tier = getTierForCategory(finding.category, finding.layer)
|
|
129
|
+
console.log(`\n[${tier.toUpperCase()}] ${finding.title}`)
|
|
130
|
+
console.log(` Category: ${finding.category}`)
|
|
131
|
+
console.log(` Layer: ${finding.layer}`)
|
|
132
|
+
console.log(` Severity: ${finding.severity}`)
|
|
133
|
+
console.log(` File: ${finding.filePath}:${finding.lineNumber}`)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Summary
|
|
137
|
+
console.log('\n' + '='.repeat(60))
|
|
138
|
+
console.log('Scan Depth Behavior Summary')
|
|
139
|
+
console.log('='.repeat(60))
|
|
140
|
+
|
|
141
|
+
const totalStats = computeTierStats(
|
|
142
|
+
allFindings.map(v => ({ category: v.category, layer: v.layer }))
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
console.log(`\nTotal findings: ${allFindings.length}`)
|
|
146
|
+
console.log(` ${formatTierStats(totalStats)}`)
|
|
147
|
+
|
|
148
|
+
console.log('\nBehavior by scan depth:')
|
|
149
|
+
console.log(` • cheap: Would surface ${totalStats.core} findings (Tier A only)`)
|
|
150
|
+
console.log(` • validated: Would surface ${totalStats.core} + up to ${totalStats.ai_assisted} (after AI validation)`)
|
|
151
|
+
console.log(` • deep: Same as validated + Layer 3 semantic analysis`)
|
|
152
|
+
console.log(` • hidden: ${totalStats.experimental} findings never surfaced (Tier C)`)
|
|
153
|
+
|
|
154
|
+
console.log('\n✅ Test completed successfully!')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function groupByTier(vulnerabilities: Vulnerability[]): {
|
|
158
|
+
core: Vulnerability[]
|
|
159
|
+
ai_assisted: Vulnerability[]
|
|
160
|
+
experimental: Vulnerability[]
|
|
161
|
+
} {
|
|
162
|
+
const result = { core: [], ai_assisted: [], experimental: [] } as {
|
|
163
|
+
core: Vulnerability[]
|
|
164
|
+
ai_assisted: Vulnerability[]
|
|
165
|
+
experimental: Vulnerability[]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (const vuln of vulnerabilities) {
|
|
169
|
+
const tier = getTierForCategory(vuln.category, vuln.layer)
|
|
170
|
+
result[tier].push(vuln)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return result
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Run the test
|
|
177
|
+
runTest().catch(console.error)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the security benchmark test suite
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ScanFile, Vulnerability, VulnerabilityCategory, VulnerabilitySeverity } from '../../types'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A test fixture containing a file to scan and expected results
|
|
9
|
+
*/
|
|
10
|
+
export interface TestFixture {
|
|
11
|
+
/** Descriptive name for the test */
|
|
12
|
+
name: string
|
|
13
|
+
/** The file to scan */
|
|
14
|
+
file: ScanFile
|
|
15
|
+
/** Whether findings are expected (true positive test) or not (false negative test) */
|
|
16
|
+
expectFindings: boolean
|
|
17
|
+
/** Categories expected to be found (for true positive tests) */
|
|
18
|
+
expectedCategories?: VulnerabilityCategory[]
|
|
19
|
+
/** Description of what this test validates */
|
|
20
|
+
description?: string
|
|
21
|
+
/**
|
|
22
|
+
* For false negative tests: Allow specific low-severity findings
|
|
23
|
+
* Some edge cases may generate info findings (e.g., test files with eval())
|
|
24
|
+
* By default, false negative tests fail on medium+ severity
|
|
25
|
+
*/
|
|
26
|
+
allowedInfoFindings?: {
|
|
27
|
+
category: VulnerabilityCategory
|
|
28
|
+
maxCount: number
|
|
29
|
+
reason: string
|
|
30
|
+
}[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Result from running a single test
|
|
35
|
+
*/
|
|
36
|
+
export interface TestResult {
|
|
37
|
+
name: string
|
|
38
|
+
file: ScanFile
|
|
39
|
+
layer1Findings: Vulnerability[]
|
|
40
|
+
layer2Findings: Vulnerability[]
|
|
41
|
+
expectedCategories: VulnerabilityCategory[]
|
|
42
|
+
unexpectedCategories: VulnerabilityCategory[]
|
|
43
|
+
passed: boolean
|
|
44
|
+
failureReason?: string
|
|
45
|
+
/** Findings that were unexpected but acceptable (info severity) */
|
|
46
|
+
acceptableInfoFindings?: Vulnerability[]
|
|
47
|
+
/** Findings that caused the test to fail (medium+) */
|
|
48
|
+
problematicFindings?: Vulnerability[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* A group of related test fixtures
|
|
53
|
+
*/
|
|
54
|
+
export interface TestGroup {
|
|
55
|
+
/** Name of the test group (e.g., "Hardcoded Secrets") */
|
|
56
|
+
name: string
|
|
57
|
+
/** Tier classification */
|
|
58
|
+
tier: 'A' | 'B' | 'C'
|
|
59
|
+
/** Layer this test group primarily targets */
|
|
60
|
+
layer: 1 | 2
|
|
61
|
+
/** Description of the test group */
|
|
62
|
+
description: string
|
|
63
|
+
/** True positive test fixtures */
|
|
64
|
+
truePositives: TestFixture[]
|
|
65
|
+
/** False negative test fixtures (should NOT flag) */
|
|
66
|
+
falseNegatives: TestFixture[]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Detector performance metrics
|
|
71
|
+
*/
|
|
72
|
+
export interface DetectorMetrics {
|
|
73
|
+
/** Detector/category name */
|
|
74
|
+
name: string
|
|
75
|
+
/** True positives detected */
|
|
76
|
+
truePositives: number
|
|
77
|
+
/** False positives (unexpected findings on safe code) */
|
|
78
|
+
falsePositives: number
|
|
79
|
+
/** False negatives (missed detections) */
|
|
80
|
+
falseNegatives: number
|
|
81
|
+
/** Precision: TP / (TP + FP) */
|
|
82
|
+
precision: number
|
|
83
|
+
/** Recall: TP / (TP + FN) */
|
|
84
|
+
recall: number
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Severity distribution metrics
|
|
89
|
+
*/
|
|
90
|
+
export interface SeverityMetrics {
|
|
91
|
+
critical: number
|
|
92
|
+
high: number
|
|
93
|
+
medium: number
|
|
94
|
+
low: number
|
|
95
|
+
info: number
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Detailed benchmark metrics
|
|
100
|
+
*/
|
|
101
|
+
export interface BenchmarkMetrics {
|
|
102
|
+
/** Overall detection statistics */
|
|
103
|
+
detection: {
|
|
104
|
+
totalVulnerabilitiesDetected: number
|
|
105
|
+
truePositiveDetections: number
|
|
106
|
+
falsePositiveDetections: number
|
|
107
|
+
missedVulnerabilities: number
|
|
108
|
+
}
|
|
109
|
+
/** Performance by detector/category */
|
|
110
|
+
byDetector: DetectorMetrics[]
|
|
111
|
+
/** Severity distribution of all findings */
|
|
112
|
+
severityDistribution: SeverityMetrics
|
|
113
|
+
/** Severity distribution of false positives */
|
|
114
|
+
falsePositiveSeverity: SeverityMetrics
|
|
115
|
+
/** Coverage statistics */
|
|
116
|
+
coverage: {
|
|
117
|
+
totalCategories: number
|
|
118
|
+
categoriesTested: number
|
|
119
|
+
coveragePercent: number
|
|
120
|
+
untestedCategories: string[]
|
|
121
|
+
}
|
|
122
|
+
/** Tier statistics */
|
|
123
|
+
byTier: {
|
|
124
|
+
tierA: { tested: number; passed: number }
|
|
125
|
+
tierB: { tested: number; passed: number }
|
|
126
|
+
tierC: { tested: number; passed: number }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Summary of benchmark results
|
|
132
|
+
*/
|
|
133
|
+
export interface BenchmarkSummary {
|
|
134
|
+
truePositivePassed: number
|
|
135
|
+
truePositiveFailed: number
|
|
136
|
+
falseNegativePassed: number
|
|
137
|
+
falseNegativeFailed: number
|
|
138
|
+
totalTests: number
|
|
139
|
+
passedTests: number
|
|
140
|
+
passRate: number
|
|
141
|
+
results: TestResult[]
|
|
142
|
+
/** Detailed performance metrics */
|
|
143
|
+
metrics: BenchmarkMetrics
|
|
144
|
+
}
|