@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
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scanner Types and Interfaces
|
|
3
|
+
* Defines the core data structures for the security scanning engine
|
|
4
|
+
*/
|
|
5
|
+
export type VulnerabilitySeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
6
|
+
export type VulnerabilityCategory = 'hardcoded_secret' | 'high_entropy_string' | 'sensitive_variable' | 'security_bypass' | 'dangerous_function' | 'sql_injection' | 'xss' | 'command_injection' | 'insecure_config' | 'missing_auth' | 'suspicious_package' | 'cors_misconfiguration' | 'root_container' | 'dangerous_file' | 'ai_pattern' | 'sensitive_url' | 'weak_crypto' | 'data_exposure' | 'ai_prompt_injection' | 'ai_unsafe_execution' | 'ai_overpermissive_tool' | 'ai_rag_exfiltration' | 'ai_endpoint_unprotected' | 'ai_schema_mismatch';
|
|
7
|
+
export type ValidationStatus = 'confirmed' | 'downgraded' | 'dismissed' | 'not_validated';
|
|
8
|
+
export interface Vulnerability {
|
|
9
|
+
id: string;
|
|
10
|
+
filePath: string;
|
|
11
|
+
lineNumber: number;
|
|
12
|
+
lineContent: string;
|
|
13
|
+
severity: VulnerabilitySeverity;
|
|
14
|
+
category: VulnerabilityCategory;
|
|
15
|
+
title: string;
|
|
16
|
+
description: string;
|
|
17
|
+
suggestedFix?: string;
|
|
18
|
+
confidence: 'high' | 'medium' | 'low';
|
|
19
|
+
layer: 1 | 2 | 3;
|
|
20
|
+
requiresAIValidation?: boolean;
|
|
21
|
+
validatedByAI?: boolean;
|
|
22
|
+
validationStatus?: ValidationStatus;
|
|
23
|
+
validationNotes?: string;
|
|
24
|
+
originalSeverity?: VulnerabilitySeverity;
|
|
25
|
+
}
|
|
26
|
+
export interface ScanFile {
|
|
27
|
+
path: string;
|
|
28
|
+
content: string;
|
|
29
|
+
language: string;
|
|
30
|
+
size: number;
|
|
31
|
+
}
|
|
32
|
+
export interface SeverityCounts {
|
|
33
|
+
critical: number;
|
|
34
|
+
high: number;
|
|
35
|
+
medium: number;
|
|
36
|
+
low: number;
|
|
37
|
+
info: number;
|
|
38
|
+
}
|
|
39
|
+
export type CategoryCounts = Partial<Record<VulnerabilityCategory, number>>;
|
|
40
|
+
export interface ScanResult {
|
|
41
|
+
repoName: string;
|
|
42
|
+
repoUrl: string;
|
|
43
|
+
branch: string;
|
|
44
|
+
filesScanned: number;
|
|
45
|
+
filesSkipped: number;
|
|
46
|
+
vulnerabilities: Vulnerability[];
|
|
47
|
+
severityCounts: SeverityCounts;
|
|
48
|
+
categoryCounts: CategoryCounts;
|
|
49
|
+
hasBlockingIssues: boolean;
|
|
50
|
+
scanDuration: number;
|
|
51
|
+
timestamp: string;
|
|
52
|
+
validationStats?: {
|
|
53
|
+
totalFindings: number;
|
|
54
|
+
validatedFindings: number;
|
|
55
|
+
confirmedFindings: number;
|
|
56
|
+
dismissedFindings: number;
|
|
57
|
+
downgradedFindings: number;
|
|
58
|
+
autoDismissedFindings: number;
|
|
59
|
+
estimatedInputTokens: number;
|
|
60
|
+
estimatedOutputTokens: number;
|
|
61
|
+
estimatedCost: number;
|
|
62
|
+
apiCalls: number;
|
|
63
|
+
cacheCreationTokens: number;
|
|
64
|
+
cacheReadTokens: number;
|
|
65
|
+
cacheHitRate: number;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export interface ScanProgress {
|
|
69
|
+
status: 'fetching' | 'scanning_layer1' | 'scanning_layer2' | 'scanning_layer3' | 'complete' | 'failed';
|
|
70
|
+
currentFile?: string;
|
|
71
|
+
filesProcessed: number;
|
|
72
|
+
totalFiles: number;
|
|
73
|
+
vulnerabilitiesFound: number;
|
|
74
|
+
}
|
|
75
|
+
export interface SecretPattern {
|
|
76
|
+
name: string;
|
|
77
|
+
pattern: RegExp;
|
|
78
|
+
severity: VulnerabilitySeverity;
|
|
79
|
+
description: string;
|
|
80
|
+
}
|
|
81
|
+
export interface ConfigRule {
|
|
82
|
+
name: string;
|
|
83
|
+
filePatterns: string[];
|
|
84
|
+
check: (content: string, filePath: string) => ConfigViolation[];
|
|
85
|
+
}
|
|
86
|
+
export interface ConfigViolation {
|
|
87
|
+
line: number;
|
|
88
|
+
lineContent: string;
|
|
89
|
+
message: string;
|
|
90
|
+
severity: VulnerabilitySeverity;
|
|
91
|
+
}
|
|
92
|
+
export interface SensitiveVariablePattern {
|
|
93
|
+
pattern: RegExp;
|
|
94
|
+
severity: VulnerabilitySeverity;
|
|
95
|
+
description: string;
|
|
96
|
+
}
|
|
97
|
+
export interface AIAnalysisRequest {
|
|
98
|
+
filePath: string;
|
|
99
|
+
content: string;
|
|
100
|
+
context: string;
|
|
101
|
+
}
|
|
102
|
+
export interface AIFinding {
|
|
103
|
+
lineNumber: number;
|
|
104
|
+
lineContent: string;
|
|
105
|
+
severity: VulnerabilitySeverity;
|
|
106
|
+
category: VulnerabilityCategory;
|
|
107
|
+
title: string;
|
|
108
|
+
description: string;
|
|
109
|
+
suggestedFix: string;
|
|
110
|
+
}
|
|
111
|
+
export declare const SCANNABLE_EXTENSIONS: string[];
|
|
112
|
+
export declare const SPECIAL_FILES: string[];
|
|
113
|
+
export declare const MAX_FILE_SIZE: number;
|
|
114
|
+
/**
|
|
115
|
+
* Scan mode determines the depth and cost of the scan
|
|
116
|
+
*
|
|
117
|
+
* - full: Complete scan with AI validation on all files (initial onboarding, deep audits)
|
|
118
|
+
* - incremental: Focused scan on changed files only (CI/CD, fast feedback)
|
|
119
|
+
*/
|
|
120
|
+
export type ScanMode = 'full' | 'incremental';
|
|
121
|
+
/**
|
|
122
|
+
* Scan depth controls AI usage independent of full vs incremental mode
|
|
123
|
+
*
|
|
124
|
+
* - cheap: Layer 1 + Layer 2 only. No AI validation, no Layer 3.
|
|
125
|
+
* Only Tier A (core) findings are surfaced.
|
|
126
|
+
* Target: <5s for typical PR scans.
|
|
127
|
+
*
|
|
128
|
+
* - validated: Layer 1 + Layer 2 + AI validation on selected findings. No Layer 3.
|
|
129
|
+
* Tier A is surfaced directly, Tier B goes through AI validation.
|
|
130
|
+
* Target: <15s with <10 AI calls.
|
|
131
|
+
*
|
|
132
|
+
* - deep: Layer 1 + Layer 2 + AI validation + Layer 3 semantic analysis.
|
|
133
|
+
* Full analysis for initial onboarding or deep security audits.
|
|
134
|
+
* Target: Complete thoroughness, cost secondary.
|
|
135
|
+
*
|
|
136
|
+
* ## Workflow Profile Recommendations:
|
|
137
|
+
*
|
|
138
|
+
* | Workflow | Default Depth | Rationale |
|
|
139
|
+
* |----------------|---------------|--------------------------------------|
|
|
140
|
+
* | GitHub PR | cheap | Fast feedback, high-signal findings |
|
|
141
|
+
* | VS Code | validated | Interactive, balance depth + speed |
|
|
142
|
+
* | CLI (default) | cheap | Fast local scans |
|
|
143
|
+
* | CLI --deep | deep | Thorough analysis when requested |
|
|
144
|
+
* | Onboarding | deep | Full picture on first scan |
|
|
145
|
+
*/
|
|
146
|
+
export type ScanDepth = 'cheap' | 'validated' | 'deep';
|
|
147
|
+
export interface ScanModeConfig {
|
|
148
|
+
/** The scan mode */
|
|
149
|
+
mode: ScanMode;
|
|
150
|
+
/** For incremental scans: paths of changed files */
|
|
151
|
+
changedFiles?: string[];
|
|
152
|
+
/** For incremental scans: base commit/branch to diff against */
|
|
153
|
+
baseBranch?: string;
|
|
154
|
+
/** Whether to skip AI validation entirely (for very fast scans) */
|
|
155
|
+
skipAIValidation?: boolean;
|
|
156
|
+
/** Whether to skip Layer 3 deep analysis (reduces cost) */
|
|
157
|
+
skipLayer3?: boolean;
|
|
158
|
+
/** Maximum files to send to AI validation (cost control) */
|
|
159
|
+
maxAIValidationFiles?: number;
|
|
160
|
+
/** Maximum files for Layer 3 analysis (cost control) */
|
|
161
|
+
maxLayer3Files?: number;
|
|
162
|
+
/** Scan depth mode (cheap/validated/deep) - controls AI usage */
|
|
163
|
+
scanDepth?: ScanDepth;
|
|
164
|
+
/** Whether to exclude test files from scanning (default: true) */
|
|
165
|
+
excludeTestFiles?: boolean;
|
|
166
|
+
/** Whether to exclude seed files from scanning (default: true) */
|
|
167
|
+
excludeSeedFiles?: boolean;
|
|
168
|
+
/** Custom file path patterns to exclude (glob format) */
|
|
169
|
+
customExclusions?: string[];
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Default configurations for each scan mode
|
|
173
|
+
*/
|
|
174
|
+
export declare const SCAN_MODE_DEFAULTS: Record<ScanMode, Partial<ScanModeConfig>>;
|
|
175
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Scanner Types and Interfaces
|
|
4
|
+
* Defines the core data structures for the security scanning engine
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SCAN_MODE_DEFAULTS = exports.MAX_FILE_SIZE = exports.SPECIAL_FILES = exports.SCANNABLE_EXTENSIONS = void 0;
|
|
8
|
+
// Supported file extensions for scanning
|
|
9
|
+
exports.SCANNABLE_EXTENSIONS = [
|
|
10
|
+
'.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
|
|
11
|
+
'.py', '.rb', '.php', '.go', '.java', '.cs',
|
|
12
|
+
'.env', '.yaml', '.yml', '.json', '.toml',
|
|
13
|
+
'.dockerfile', '.sh', '.bash',
|
|
14
|
+
];
|
|
15
|
+
// Files to always scan regardless of extension
|
|
16
|
+
exports.SPECIAL_FILES = [
|
|
17
|
+
'Dockerfile',
|
|
18
|
+
'docker-compose.yml',
|
|
19
|
+
'docker-compose.yaml',
|
|
20
|
+
'.env',
|
|
21
|
+
'.env.local',
|
|
22
|
+
'.env.production',
|
|
23
|
+
'.env.development',
|
|
24
|
+
'package.json',
|
|
25
|
+
'requirements.txt',
|
|
26
|
+
'Gemfile',
|
|
27
|
+
'go.mod',
|
|
28
|
+
];
|
|
29
|
+
// Max file size to scan (50KB as per PRD)
|
|
30
|
+
exports.MAX_FILE_SIZE = 50 * 1024;
|
|
31
|
+
/**
|
|
32
|
+
* Default configurations for each scan mode
|
|
33
|
+
*/
|
|
34
|
+
exports.SCAN_MODE_DEFAULTS = {
|
|
35
|
+
full: {
|
|
36
|
+
mode: 'full',
|
|
37
|
+
skipAIValidation: false,
|
|
38
|
+
skipLayer3: false,
|
|
39
|
+
maxAIValidationFiles: 50,
|
|
40
|
+
maxLayer3Files: 15,
|
|
41
|
+
},
|
|
42
|
+
incremental: {
|
|
43
|
+
mode: 'incremental',
|
|
44
|
+
skipAIValidation: false,
|
|
45
|
+
skipLayer3: true, // Skip expensive Layer 3 for incremental
|
|
46
|
+
maxAIValidationFiles: 20,
|
|
47
|
+
maxLayer3Files: 5,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAkKH,yCAAyC;AAC5B,QAAA,oBAAoB,GAAG;IAClC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC5C,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK;IAC3C,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACzC,aAAa,EAAE,KAAK,EAAE,OAAO;CAC9B,CAAA;AAED,+CAA+C;AAClC,QAAA,aAAa,GAAG;IAC3B,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,MAAM;IACN,YAAY;IACZ,iBAAiB;IACjB,kBAAkB;IAClB,cAAc;IACd,kBAAkB;IAClB,SAAS;IACT,QAAQ;CACT,CAAA;AAED,0CAA0C;AAC7B,QAAA,aAAa,GAAG,EAAE,GAAG,IAAI,CAAA;AA4EtC;;GAEG;AACU,QAAA,kBAAkB,GAA8C;IAC3E,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,gBAAgB,EAAE,KAAK;QACvB,UAAU,EAAE,KAAK;QACjB,oBAAoB,EAAE,EAAE;QACxB,cAAc,EAAE,EAAE;KACnB;IACD,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,gBAAgB,EAAE,KAAK;QACvB,UAAU,EAAE,IAAI,EAAE,yCAAyC;QAC3D,oBAAoB,EAAE,EAAE;QACxB,cAAc,EAAE,CAAC;KAClB;CACF,CAAA"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Helper Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects authentication helper functions that throw on missing auth,
|
|
5
|
+
* return non-null types, and provide security guarantees.
|
|
6
|
+
*
|
|
7
|
+
* When these helpers are called, subsequent code is GUARANTEED to have
|
|
8
|
+
* an authenticated user - no additional `if (!userId)` checks are needed.
|
|
9
|
+
*/
|
|
10
|
+
import type { ScanFile } from '../types';
|
|
11
|
+
export interface AuthHelper {
|
|
12
|
+
/** Name of the helper function */
|
|
13
|
+
name: string;
|
|
14
|
+
/** File where it's defined (if detected) */
|
|
15
|
+
definedIn?: string;
|
|
16
|
+
/** Whether it throws on missing auth (vs returning null) */
|
|
17
|
+
throwsOnMissing: boolean;
|
|
18
|
+
/** Return type if detected (e.g., 'string', 'User', 'Promise<string>') */
|
|
19
|
+
returnType?: string;
|
|
20
|
+
/** Whether return type is non-null */
|
|
21
|
+
returnsNonNull: boolean;
|
|
22
|
+
/** Pattern that matches calls to this helper */
|
|
23
|
+
callPattern: RegExp;
|
|
24
|
+
}
|
|
25
|
+
export interface AuthHelperContext {
|
|
26
|
+
/** All detected auth helpers */
|
|
27
|
+
helpers: AuthHelper[];
|
|
28
|
+
/** Whether the project has any throwing auth helpers */
|
|
29
|
+
hasThrowingHelpers: boolean;
|
|
30
|
+
/** Summary for AI validation */
|
|
31
|
+
summary: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Detect auth helper functions in the codebase
|
|
35
|
+
*/
|
|
36
|
+
export declare function detectAuthHelpers(files: ScanFile[]): AuthHelperContext;
|
|
37
|
+
/**
|
|
38
|
+
* Check if a code line uses a throwing auth helper
|
|
39
|
+
* Returns the helper if found, undefined otherwise
|
|
40
|
+
*/
|
|
41
|
+
export declare function usesThrowingAuthHelper(lineContent: string, surroundingContent: string, helpers: AuthHelper[]): AuthHelper | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Check if a file has auth helper calls before a given line
|
|
44
|
+
* This indicates the code after the call is in authenticated context
|
|
45
|
+
*/
|
|
46
|
+
export declare function hasAuthHelperCallBefore(content: string, lineNumber: number, helpers: AuthHelper[]): {
|
|
47
|
+
hasCall: boolean;
|
|
48
|
+
helper?: AuthHelper;
|
|
49
|
+
callLine?: number;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Check if code suggests user ID is already validated
|
|
53
|
+
* Detects patterns like: const userId = await getCurrentUserId()
|
|
54
|
+
*/
|
|
55
|
+
export declare function isUserIdAlreadyValidated(content: string, lineNumber: number, helpers: AuthHelper[]): boolean;
|
|
56
|
+
//# sourceMappingURL=auth-helper-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-helper-detector.d.ts","sourceRoot":"","sources":["../../src/utils/auth-helper-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAMxC,MAAM,WAAW,UAAU;IACzB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4DAA4D;IAC5D,eAAe,EAAE,OAAO,CAAA;IACxB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,cAAc,EAAE,OAAO,CAAA;IACvB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,OAAO,EAAE,UAAU,EAAE,CAAA;IACrB,wDAAwD;IACxD,kBAAkB,EAAE,OAAO,CAAA;IAC3B,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAA;CAChB;AA6ED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,iBAAiB,CA6CtE;AAuFD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,EAC1B,OAAO,EAAE,UAAU,EAAE,GACpB,UAAU,GAAG,SAAS,CAYxB;AA+BD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,EAAE,GACpB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAkE9D;AAoCD;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,UAAU,EAAE,GACpB,OAAO,CAuBT"}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auth Helper Detector
|
|
4
|
+
*
|
|
5
|
+
* Detects authentication helper functions that throw on missing auth,
|
|
6
|
+
* return non-null types, and provide security guarantees.
|
|
7
|
+
*
|
|
8
|
+
* When these helpers are called, subsequent code is GUARANTEED to have
|
|
9
|
+
* an authenticated user - no additional `if (!userId)` checks are needed.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.detectAuthHelpers = detectAuthHelpers;
|
|
13
|
+
exports.usesThrowingAuthHelper = usesThrowingAuthHelper;
|
|
14
|
+
exports.hasAuthHelperCallBefore = hasAuthHelperCallBefore;
|
|
15
|
+
exports.isUserIdAlreadyValidated = isUserIdAlreadyValidated;
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Well-Known Auth Helper Patterns
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Common patterns for auth helpers that THROW on missing auth
|
|
21
|
+
* These are functions that guarantee authenticated context after call
|
|
22
|
+
*/
|
|
23
|
+
const THROWING_AUTH_HELPER_PATTERNS = [
|
|
24
|
+
// Generic patterns
|
|
25
|
+
{
|
|
26
|
+
namePattern: /^(get|fetch|require|ensure)(Current)?(User|UserId|Auth|Session|Principal)(Id)?$/i,
|
|
27
|
+
callPattern: /\b(get|fetch|require|ensure)(Current)?(User|UserId|Auth|Session|Principal)(Id)?\s*\(/gi,
|
|
28
|
+
description: 'Auth helper that retrieves authenticated user',
|
|
29
|
+
},
|
|
30
|
+
// Clerk patterns
|
|
31
|
+
{
|
|
32
|
+
namePattern: /^auth$/,
|
|
33
|
+
callPattern: /\bauth\s*\(\s*\)/gi,
|
|
34
|
+
description: 'Clerk auth() helper',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
namePattern: /^currentUser$/,
|
|
38
|
+
callPattern: /\bcurrentUser\s*\(\s*\)/gi,
|
|
39
|
+
description: 'Clerk currentUser() helper',
|
|
40
|
+
},
|
|
41
|
+
// NextAuth patterns
|
|
42
|
+
{
|
|
43
|
+
namePattern: /^getServerSession$/,
|
|
44
|
+
callPattern: /\bgetServerSession\s*\(/gi,
|
|
45
|
+
description: 'NextAuth getServerSession()',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
namePattern: /^getSession$/,
|
|
49
|
+
callPattern: /\bgetSession\s*\(/gi,
|
|
50
|
+
description: 'Session helper',
|
|
51
|
+
},
|
|
52
|
+
// Supabase patterns
|
|
53
|
+
{
|
|
54
|
+
namePattern: /^getUser$/,
|
|
55
|
+
callPattern: /\bsupabase\.auth\.getUser\s*\(/gi,
|
|
56
|
+
description: 'Supabase getUser()',
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
/**
|
|
60
|
+
* Patterns that indicate a function THROWS on missing auth
|
|
61
|
+
*/
|
|
62
|
+
const THROWING_INDICATORS = [
|
|
63
|
+
/throw\s+new\s+(Error|UnauthorizedError|AuthError|HttpException)/i,
|
|
64
|
+
/throw\s+.*401/i,
|
|
65
|
+
/throw\s+.*unauthorized/i,
|
|
66
|
+
/throw\s+.*unauthenticated/i,
|
|
67
|
+
/return\s+.*401/i,
|
|
68
|
+
/NextResponse\.json\s*\([^)]*401/i,
|
|
69
|
+
/res\.status\s*\(\s*401\s*\)/i,
|
|
70
|
+
/redirect\s*\(\s*['"`].*login/i,
|
|
71
|
+
];
|
|
72
|
+
/**
|
|
73
|
+
* Patterns that indicate NON-NULL return type
|
|
74
|
+
*/
|
|
75
|
+
const NON_NULL_RETURN_PATTERNS = [
|
|
76
|
+
/:\s*Promise<string>/i, // : Promise<string>
|
|
77
|
+
/:\s*string(?!\s*\|)/i, // : string (not string | null)
|
|
78
|
+
/:\s*Promise<User>/i, // : Promise<User>
|
|
79
|
+
/:\s*User(?!\s*\|)/i, // : User (not User | null)
|
|
80
|
+
/:\s*Promise<\w+>(?!\s*\|)/i, // : Promise<SomeType>
|
|
81
|
+
/\w+!$/i, // Non-null assertion in return
|
|
82
|
+
];
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Detection Functions
|
|
85
|
+
// ============================================================================
|
|
86
|
+
/**
|
|
87
|
+
* Detect auth helper functions in the codebase
|
|
88
|
+
*/
|
|
89
|
+
function detectAuthHelpers(files) {
|
|
90
|
+
const helpers = [];
|
|
91
|
+
const detectedNames = new Set();
|
|
92
|
+
// First pass: find auth helper definitions
|
|
93
|
+
for (const file of files) {
|
|
94
|
+
// Skip non-code files
|
|
95
|
+
if (!/\.(ts|tsx|js|jsx)$/i.test(file.path))
|
|
96
|
+
continue;
|
|
97
|
+
// Look for function definitions that look like auth helpers
|
|
98
|
+
const functionMatches = findAuthHelperDefinitions(file.content, file.path);
|
|
99
|
+
for (const helper of functionMatches) {
|
|
100
|
+
if (!detectedNames.has(helper.name)) {
|
|
101
|
+
detectedNames.add(helper.name);
|
|
102
|
+
helpers.push(helper);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Add well-known helpers if not already detected
|
|
107
|
+
for (const pattern of THROWING_AUTH_HELPER_PATTERNS) {
|
|
108
|
+
const nameMatch = pattern.namePattern.source.replace(/[\^\$\\b]/g, '');
|
|
109
|
+
if (!detectedNames.has(nameMatch)) {
|
|
110
|
+
// Check if this pattern is used in any file
|
|
111
|
+
const isUsed = files.some(f => pattern.callPattern.test(f.content));
|
|
112
|
+
if (isUsed) {
|
|
113
|
+
helpers.push({
|
|
114
|
+
name: nameMatch,
|
|
115
|
+
throwsOnMissing: true, // Assume throwing for well-known patterns
|
|
116
|
+
returnsNonNull: true,
|
|
117
|
+
callPattern: pattern.callPattern,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Generate summary
|
|
123
|
+
const throwingHelpers = helpers.filter(h => h.throwsOnMissing);
|
|
124
|
+
const summary = generateAuthHelperSummary(helpers);
|
|
125
|
+
return {
|
|
126
|
+
helpers,
|
|
127
|
+
hasThrowingHelpers: throwingHelpers.length > 0,
|
|
128
|
+
summary,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Find auth helper function definitions in a file
|
|
133
|
+
*/
|
|
134
|
+
function findAuthHelperDefinitions(content, filePath) {
|
|
135
|
+
const helpers = [];
|
|
136
|
+
const lines = content.split('\n');
|
|
137
|
+
// Patterns for function definitions
|
|
138
|
+
const funcDefPatterns = [
|
|
139
|
+
// async function getCurrentUserId(): Promise<string> { ... throw
|
|
140
|
+
/(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\([^)]*\)\s*(?::\s*([^{]+))?\s*\{/gi,
|
|
141
|
+
// const getCurrentUserId = async (): Promise<string> => { ... throw
|
|
142
|
+
/(?:export\s+)?const\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*(?::\s*([^=]+))?\s*=>/gi,
|
|
143
|
+
];
|
|
144
|
+
for (let i = 0; i < lines.length; i++) {
|
|
145
|
+
const line = lines[i];
|
|
146
|
+
for (const pattern of funcDefPatterns) {
|
|
147
|
+
pattern.lastIndex = 0;
|
|
148
|
+
const match = pattern.exec(line);
|
|
149
|
+
if (!match)
|
|
150
|
+
continue;
|
|
151
|
+
const funcName = match[1];
|
|
152
|
+
const returnType = match[2]?.trim();
|
|
153
|
+
// Check if this looks like an auth helper by name
|
|
154
|
+
const isAuthHelperName = THROWING_AUTH_HELPER_PATTERNS.some(p => p.namePattern.test(funcName));
|
|
155
|
+
if (!isAuthHelperName)
|
|
156
|
+
continue;
|
|
157
|
+
// Look ahead for throwing patterns and return type
|
|
158
|
+
const functionBody = extractFunctionBody(lines, i);
|
|
159
|
+
const throwsOnMissing = THROWING_INDICATORS.some(p => p.test(functionBody));
|
|
160
|
+
const returnsNonNull = returnType
|
|
161
|
+
? NON_NULL_RETURN_PATTERNS.some(p => p.test(`: ${returnType}`))
|
|
162
|
+
: false;
|
|
163
|
+
// Create call pattern for this helper
|
|
164
|
+
const callPattern = new RegExp(`\\b${escapeRegex(funcName)}\\s*\\(`, 'gi');
|
|
165
|
+
helpers.push({
|
|
166
|
+
name: funcName,
|
|
167
|
+
definedIn: filePath,
|
|
168
|
+
throwsOnMissing,
|
|
169
|
+
returnType,
|
|
170
|
+
returnsNonNull: returnsNonNull || throwsOnMissing, // If it throws, the return is non-null
|
|
171
|
+
callPattern,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return helpers;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Extract function body for analysis (up to closing brace)
|
|
179
|
+
*/
|
|
180
|
+
function extractFunctionBody(lines, startLine, maxLines = 50) {
|
|
181
|
+
let braceCount = 0;
|
|
182
|
+
let started = false;
|
|
183
|
+
const bodyLines = [];
|
|
184
|
+
for (let i = startLine; i < Math.min(lines.length, startLine + maxLines); i++) {
|
|
185
|
+
const line = lines[i];
|
|
186
|
+
bodyLines.push(line);
|
|
187
|
+
for (const char of line) {
|
|
188
|
+
if (char === '{') {
|
|
189
|
+
braceCount++;
|
|
190
|
+
started = true;
|
|
191
|
+
}
|
|
192
|
+
else if (char === '}') {
|
|
193
|
+
braceCount--;
|
|
194
|
+
if (started && braceCount === 0) {
|
|
195
|
+
return bodyLines.join('\n');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return bodyLines.join('\n');
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Check if a code line uses a throwing auth helper
|
|
204
|
+
* Returns the helper if found, undefined otherwise
|
|
205
|
+
*/
|
|
206
|
+
function usesThrowingAuthHelper(lineContent, surroundingContent, helpers) {
|
|
207
|
+
// Check if any throwing helper is called in the surrounding context
|
|
208
|
+
const throwingHelpers = helpers.filter(h => h.throwsOnMissing);
|
|
209
|
+
for (const helper of throwingHelpers) {
|
|
210
|
+
helper.callPattern.lastIndex = 0;
|
|
211
|
+
if (helper.callPattern.test(surroundingContent)) {
|
|
212
|
+
return helper;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Well-known auth helper call patterns - used as fallback when no helpers are detected
|
|
219
|
+
* These patterns are common across frameworks and should be recognized even without project analysis
|
|
220
|
+
*/
|
|
221
|
+
const WELL_KNOWN_AUTH_CALL_PATTERNS = [
|
|
222
|
+
// Generic throwing auth patterns
|
|
223
|
+
{ pattern: /\bgetCurrentUserId\s*\(/i, name: 'getCurrentUserId' },
|
|
224
|
+
{ pattern: /\bgetCurrentUser\s*\(/i, name: 'getCurrentUser' },
|
|
225
|
+
{ pattern: /\brequireAuth\s*\(/i, name: 'requireAuth' },
|
|
226
|
+
{ pattern: /\brequireUser\s*\(/i, name: 'requireUser' },
|
|
227
|
+
{ pattern: /\bensureAuth\s*\(/i, name: 'ensureAuth' },
|
|
228
|
+
{ pattern: /\bensureAuthenticated\s*\(/i, name: 'ensureAuthenticated' },
|
|
229
|
+
{ pattern: /\bverifyAuth\s*\(/i, name: 'verifyAuth' },
|
|
230
|
+
{ pattern: /\bcheckAuth\s*\(/i, name: 'checkAuth' },
|
|
231
|
+
{ pattern: /\bvalidateAuth\s*\(/i, name: 'validateAuth' },
|
|
232
|
+
{ pattern: /\bassertAuth\s*\(/i, name: 'assertAuth' },
|
|
233
|
+
{ pattern: /\bgetAuth\s*\(/i, name: 'getAuth' },
|
|
234
|
+
{ pattern: /\bfetchCurrentUser\s*\(/i, name: 'fetchCurrentUser' },
|
|
235
|
+
// Clerk
|
|
236
|
+
{ pattern: /\bauth\s*\(\s*\)\.protect\s*\(/i, name: 'auth().protect' },
|
|
237
|
+
{ pattern: /\bcurrentUser\s*\(\s*\)/i, name: 'currentUser' },
|
|
238
|
+
// NextAuth
|
|
239
|
+
{ pattern: /\bgetServerSession\s*\(/i, name: 'getServerSession' },
|
|
240
|
+
// Supabase
|
|
241
|
+
{ pattern: /\bsupabase\.auth\.getUser\s*\(/i, name: 'supabase.auth.getUser' },
|
|
242
|
+
// Destructuring pattern
|
|
243
|
+
{ pattern: /const\s+\{\s*user\s*\}\s*=\s*await\s+auth/i, name: 'destructured auth' },
|
|
244
|
+
];
|
|
245
|
+
/**
|
|
246
|
+
* Check if a file has auth helper calls before a given line
|
|
247
|
+
* This indicates the code after the call is in authenticated context
|
|
248
|
+
*/
|
|
249
|
+
function hasAuthHelperCallBefore(content, lineNumber, helpers) {
|
|
250
|
+
const lines = content.split('\n');
|
|
251
|
+
const throwingHelpers = helpers.filter(h => h.throwsOnMissing);
|
|
252
|
+
// Increase search window from 30 to 100 lines for better coverage
|
|
253
|
+
const searchStart = Math.max(0, lineNumber - 100);
|
|
254
|
+
// Look backwards from the current line
|
|
255
|
+
for (let i = lineNumber - 1; i >= searchStart; i--) {
|
|
256
|
+
const line = lines[i];
|
|
257
|
+
// Check detected helpers first
|
|
258
|
+
for (const helper of throwingHelpers) {
|
|
259
|
+
helper.callPattern.lastIndex = 0;
|
|
260
|
+
if (helper.callPattern.test(line)) {
|
|
261
|
+
return { hasCall: true, helper, callLine: i + 1 };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// Stop at function boundaries (for module-level helpers, we still check inside function)
|
|
265
|
+
if (/\b(function|async function|=>|export\s+default)\b/.test(line) && /\{/.test(line)) {
|
|
266
|
+
// If this is the route handler definition line, continue checking inside it
|
|
267
|
+
if (i !== lineNumber - 1) {
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// FORWARD SEARCH: Always search forward into the function body
|
|
273
|
+
// This catches auth helpers called INSIDE the route handler, not just before it
|
|
274
|
+
// Example: export async function GET() { const userId = await getCurrentUserId(); ... }
|
|
275
|
+
const endLine = Math.min(lines.length, lineNumber + 30);
|
|
276
|
+
for (let i = lineNumber; i < endLine; i++) {
|
|
277
|
+
const line = lines[i];
|
|
278
|
+
// Check detected helpers
|
|
279
|
+
for (const helper of throwingHelpers) {
|
|
280
|
+
helper.callPattern.lastIndex = 0;
|
|
281
|
+
if (helper.callPattern.test(line)) {
|
|
282
|
+
return { hasCall: true, helper, callLine: i + 1 };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// Also check well-known patterns (fallback for single-file scans)
|
|
286
|
+
for (const known of WELL_KNOWN_AUTH_CALL_PATTERNS) {
|
|
287
|
+
if (known.pattern.test(line)) {
|
|
288
|
+
return {
|
|
289
|
+
hasCall: true,
|
|
290
|
+
helper: {
|
|
291
|
+
name: known.name,
|
|
292
|
+
throwsOnMissing: true,
|
|
293
|
+
returnsNonNull: true,
|
|
294
|
+
callPattern: known.pattern,
|
|
295
|
+
},
|
|
296
|
+
callLine: i + 1
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Stop at another function boundary (but not the current line)
|
|
301
|
+
if (i > lineNumber && /\bexport\s+(async\s+)?function\s+(GET|POST|PUT|DELETE|PATCH)\s*\(/i.test(line)) {
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return { hasCall: false };
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Generate summary for AI validation
|
|
309
|
+
*/
|
|
310
|
+
function generateAuthHelperSummary(helpers) {
|
|
311
|
+
if (helpers.length === 0) {
|
|
312
|
+
return 'No auth helper functions detected.';
|
|
313
|
+
}
|
|
314
|
+
const throwing = helpers.filter(h => h.throwsOnMissing);
|
|
315
|
+
const lines = [];
|
|
316
|
+
lines.push('### Auth Helper Functions');
|
|
317
|
+
lines.push('');
|
|
318
|
+
if (throwing.length > 0) {
|
|
319
|
+
lines.push('**Throwing auth helpers** (guarantee authenticated context when called):');
|
|
320
|
+
for (const h of throwing) {
|
|
321
|
+
const location = h.definedIn ? ` (defined in ${h.definedIn})` : '';
|
|
322
|
+
lines.push(`- \`${h.name}()\`${location}`);
|
|
323
|
+
}
|
|
324
|
+
lines.push('');
|
|
325
|
+
lines.push('When these helpers are called at the start of a function, subsequent code is GUARANTEED to have an authenticated user. Do NOT flag "missing auth" or suggest `if (!userId)` checks after these calls.');
|
|
326
|
+
}
|
|
327
|
+
return lines.join('\n');
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Escape special regex characters
|
|
331
|
+
*/
|
|
332
|
+
function escapeRegex(str) {
|
|
333
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Check if code suggests user ID is already validated
|
|
337
|
+
* Detects patterns like: const userId = await getCurrentUserId()
|
|
338
|
+
*/
|
|
339
|
+
function isUserIdAlreadyValidated(content, lineNumber, helpers) {
|
|
340
|
+
const lines = content.split('\n');
|
|
341
|
+
const contextStart = Math.max(0, lineNumber - 20);
|
|
342
|
+
const context = lines.slice(contextStart, lineNumber).join('\n');
|
|
343
|
+
// Check for throwing helper calls
|
|
344
|
+
const throwingHelpers = helpers.filter(h => h.throwsOnMissing);
|
|
345
|
+
for (const helper of throwingHelpers) {
|
|
346
|
+
helper.callPattern.lastIndex = 0;
|
|
347
|
+
if (helper.callPattern.test(context)) {
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Check for common validation patterns
|
|
352
|
+
const validationPatterns = [
|
|
353
|
+
/const\s+(?:userId|user_id|currentUserId)\s*=\s*await/i,
|
|
354
|
+
/if\s*\(\s*!(?:userId|user_id|user|session)\s*\)/i, // Already has the check
|
|
355
|
+
/(?:userId|user_id)\s*\|\|\s*throw/i,
|
|
356
|
+
/auth\(\)\.protect\(\)/i, // Clerk protect
|
|
357
|
+
];
|
|
358
|
+
return validationPatterns.some(p => p.test(context));
|
|
359
|
+
}
|
|
360
|
+
//# sourceMappingURL=auth-helper-detector.js.map
|