@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,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Exclusion Utility
|
|
3
|
+
* Provides configurable exclusion of test files, seed files, examples, and fixtures
|
|
4
|
+
* to reduce false positives in security scans.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Vulnerability, VulnerabilityCategory } from '../types'
|
|
8
|
+
|
|
9
|
+
export interface ExclusionConfig {
|
|
10
|
+
testPatterns: string[]
|
|
11
|
+
seedPatterns: string[]
|
|
12
|
+
examplePatterns: string[]
|
|
13
|
+
fixturePatterns: string[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const DEFAULT_EXCLUSIONS: ExclusionConfig = {
|
|
17
|
+
testPatterns: [
|
|
18
|
+
'**/*.spec.ts',
|
|
19
|
+
'**/*.spec.js',
|
|
20
|
+
'**/*.test.ts',
|
|
21
|
+
'**/*.test.js',
|
|
22
|
+
'**/test/**',
|
|
23
|
+
'**/tests/**',
|
|
24
|
+
'**/__tests__/**',
|
|
25
|
+
'**/e2e/**',
|
|
26
|
+
'**/app-tests/**',
|
|
27
|
+
'**/*.spec.tsx',
|
|
28
|
+
'**/*.spec.jsx',
|
|
29
|
+
'**/*.test.tsx',
|
|
30
|
+
'**/*.test.jsx',
|
|
31
|
+
'**/cypress/**',
|
|
32
|
+
'**/playwright/**',
|
|
33
|
+
],
|
|
34
|
+
seedPatterns: [
|
|
35
|
+
'**/seed/**',
|
|
36
|
+
'**/seeds/**',
|
|
37
|
+
'**/prisma/seed/**',
|
|
38
|
+
'**/prisma/seed.ts',
|
|
39
|
+
'**/prisma/seed.js',
|
|
40
|
+
'**/db/seed/**',
|
|
41
|
+
'**/database/seed/**',
|
|
42
|
+
],
|
|
43
|
+
examplePatterns: [
|
|
44
|
+
'**/examples/**',
|
|
45
|
+
'**/demo/**',
|
|
46
|
+
'**/sample/**',
|
|
47
|
+
'**/samples/**',
|
|
48
|
+
'**/playground/**',
|
|
49
|
+
],
|
|
50
|
+
fixturePatterns: [
|
|
51
|
+
'**/fixtures/**',
|
|
52
|
+
'**/mocks/**',
|
|
53
|
+
'**/__mocks__/**',
|
|
54
|
+
'**/stubs/**',
|
|
55
|
+
'**/__fixtures__/**',
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Categories that should be SUPPRESSED in test/seed/example files
|
|
61
|
+
* These are typically false positives in non-production code
|
|
62
|
+
*/
|
|
63
|
+
const SUPPRESSIBLE_CATEGORIES: VulnerabilityCategory[] = [
|
|
64
|
+
'weak_crypto', // Math.random in tests is fine
|
|
65
|
+
'dangerous_function', // regex, eval in tests often intentional
|
|
66
|
+
'hardcoded_secret', // test fixtures have fake secrets
|
|
67
|
+
'high_entropy_string', // test data often looks like secrets
|
|
68
|
+
'sensitive_url', // localhost in test configs
|
|
69
|
+
'sensitive_variable', // test variables named 'password' etc.
|
|
70
|
+
'insecure_config', // test configs are intentionally loose
|
|
71
|
+
'ai_pattern', // AI patterns in test code
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Categories that should ALWAYS be scanned, even in test files
|
|
76
|
+
* These represent real vulnerabilities that matter in test code too
|
|
77
|
+
*/
|
|
78
|
+
const ALWAYS_SCAN_CATEGORIES: VulnerabilityCategory[] = [
|
|
79
|
+
'sql_injection',
|
|
80
|
+
'command_injection',
|
|
81
|
+
'xss',
|
|
82
|
+
'path_traversal' as VulnerabilityCategory, // Cast since not in original types
|
|
83
|
+
'missing_auth', // Keep but may downgrade
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
export type ExclusionReason = 'test_file' | 'seed_file' | 'example_file' | 'fixture_file' | null
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Convert glob pattern to regex for matching
|
|
90
|
+
*/
|
|
91
|
+
function globToRegex(pattern: string): RegExp {
|
|
92
|
+
// Escape special regex characters except * and **
|
|
93
|
+
let regexStr = pattern
|
|
94
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
95
|
+
.replace(/\*\*/g, '{{GLOBSTAR}}')
|
|
96
|
+
.replace(/\*/g, '[^/]*')
|
|
97
|
+
.replace(/\{\{GLOBSTAR\}\}/g, '.*')
|
|
98
|
+
|
|
99
|
+
return new RegExp(regexStr, 'i')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check if a file path matches any pattern in a list
|
|
104
|
+
*/
|
|
105
|
+
function matchesPatterns(filePath: string, patterns: string[]): boolean {
|
|
106
|
+
// Normalize path separators
|
|
107
|
+
const normalizedPath = filePath.replace(/\\/g, '/')
|
|
108
|
+
|
|
109
|
+
return patterns.some(pattern => {
|
|
110
|
+
const regex = globToRegex(pattern)
|
|
111
|
+
return regex.test(normalizedPath)
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Check if a file path should be excluded from scanning
|
|
117
|
+
* Returns the exclusion reason or null if not excluded
|
|
118
|
+
*/
|
|
119
|
+
export function getExclusionReason(
|
|
120
|
+
filePath: string,
|
|
121
|
+
config: ExclusionConfig = DEFAULT_EXCLUSIONS
|
|
122
|
+
): ExclusionReason {
|
|
123
|
+
const normalizedPath = filePath.replace(/\\/g, '/')
|
|
124
|
+
|
|
125
|
+
// Check test patterns
|
|
126
|
+
if (matchesPatterns(normalizedPath, config.testPatterns)) {
|
|
127
|
+
return 'test_file'
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check seed patterns
|
|
131
|
+
if (matchesPatterns(normalizedPath, config.seedPatterns)) {
|
|
132
|
+
return 'seed_file'
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check example patterns
|
|
136
|
+
if (matchesPatterns(normalizedPath, config.examplePatterns)) {
|
|
137
|
+
return 'example_file'
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Check fixture patterns
|
|
141
|
+
if (matchesPatterns(normalizedPath, config.fixturePatterns)) {
|
|
142
|
+
return 'fixture_file'
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return null
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Check if a file path should be excluded
|
|
150
|
+
*/
|
|
151
|
+
export function isExcludedPath(
|
|
152
|
+
filePath: string,
|
|
153
|
+
config?: Partial<ExclusionConfig>
|
|
154
|
+
): boolean {
|
|
155
|
+
const mergedConfig: ExclusionConfig = {
|
|
156
|
+
...DEFAULT_EXCLUSIONS,
|
|
157
|
+
...config,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return getExclusionReason(filePath, mergedConfig) !== null
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Determine if a finding should be suppressed based on file path and category
|
|
165
|
+
*
|
|
166
|
+
* @param finding - The vulnerability finding
|
|
167
|
+
* @param exclusionReason - The reason the file is excluded (if any)
|
|
168
|
+
* @returns true if the finding should be suppressed
|
|
169
|
+
*/
|
|
170
|
+
export function shouldSuppressFinding(
|
|
171
|
+
finding: Vulnerability,
|
|
172
|
+
exclusionReason: ExclusionReason
|
|
173
|
+
): boolean {
|
|
174
|
+
// If file is not excluded, don't suppress
|
|
175
|
+
if (!exclusionReason) {
|
|
176
|
+
return false
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Always scan certain critical categories even in test files
|
|
180
|
+
if (ALWAYS_SCAN_CATEGORIES.includes(finding.category)) {
|
|
181
|
+
return false
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Suppress suppressible categories in excluded files
|
|
185
|
+
if (SUPPRESSIBLE_CATEGORIES.includes(finding.category)) {
|
|
186
|
+
return true
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Default: don't suppress
|
|
190
|
+
return false
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get a human-readable description of the exclusion reason
|
|
195
|
+
*/
|
|
196
|
+
export function getExclusionDescription(reason: ExclusionReason): string {
|
|
197
|
+
switch (reason) {
|
|
198
|
+
case 'test_file':
|
|
199
|
+
return 'Finding in test file'
|
|
200
|
+
case 'seed_file':
|
|
201
|
+
return 'Finding in seed/fixture data file'
|
|
202
|
+
case 'example_file':
|
|
203
|
+
return 'Finding in example/demo file'
|
|
204
|
+
case 'fixture_file':
|
|
205
|
+
return 'Finding in mock/fixture file'
|
|
206
|
+
default:
|
|
207
|
+
return ''
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Filter findings based on path exclusions
|
|
213
|
+
* Returns findings that should be kept and a list of suppressed findings with reasons
|
|
214
|
+
*/
|
|
215
|
+
export function filterFindingsByPath(
|
|
216
|
+
findings: Vulnerability[],
|
|
217
|
+
config?: Partial<ExclusionConfig>
|
|
218
|
+
): {
|
|
219
|
+
kept: Vulnerability[]
|
|
220
|
+
suppressed: Array<{ finding: Vulnerability; reason: ExclusionReason; description: string }>
|
|
221
|
+
} {
|
|
222
|
+
const mergedConfig: ExclusionConfig = {
|
|
223
|
+
...DEFAULT_EXCLUSIONS,
|
|
224
|
+
...config,
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const kept: Vulnerability[] = []
|
|
228
|
+
const suppressed: Array<{ finding: Vulnerability; reason: ExclusionReason; description: string }> = []
|
|
229
|
+
|
|
230
|
+
for (const finding of findings) {
|
|
231
|
+
const exclusionReason = getExclusionReason(finding.filePath, mergedConfig)
|
|
232
|
+
|
|
233
|
+
if (shouldSuppressFinding(finding, exclusionReason)) {
|
|
234
|
+
suppressed.push({
|
|
235
|
+
finding,
|
|
236
|
+
reason: exclusionReason,
|
|
237
|
+
description: getExclusionDescription(exclusionReason),
|
|
238
|
+
})
|
|
239
|
+
} else {
|
|
240
|
+
kept.push(finding)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return { kept, suppressed }
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get the default exclusion configuration
|
|
249
|
+
*/
|
|
250
|
+
export function getDefaultExclusionConfig(): ExclusionConfig {
|
|
251
|
+
return { ...DEFAULT_EXCLUSIONS }
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Merge custom exclusion patterns with defaults
|
|
256
|
+
*/
|
|
257
|
+
export function mergeExclusionConfig(
|
|
258
|
+
custom: Partial<ExclusionConfig>
|
|
259
|
+
): ExclusionConfig {
|
|
260
|
+
return {
|
|
261
|
+
testPatterns: [...DEFAULT_EXCLUSIONS.testPatterns, ...(custom.testPatterns || [])],
|
|
262
|
+
seedPatterns: [...DEFAULT_EXCLUSIONS.seedPatterns, ...(custom.seedPatterns || [])],
|
|
263
|
+
examplePatterns: [...DEFAULT_EXCLUSIONS.examplePatterns, ...(custom.examplePatterns || [])],
|
|
264
|
+
fixturePatterns: [...DEFAULT_EXCLUSIONS.fixturePatterns, ...(custom.fixturePatterns || [])],
|
|
265
|
+
}
|
|
266
|
+
}
|