vaspera 2.9.0 → 2.10.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/CHANGELOG.md +122 -7
- package/README.md +58 -1
- package/dist/__tests__/autofix/branch-manager.test.d.ts +2 -0
- package/dist/__tests__/autofix/branch-manager.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/branch-manager.test.js +60 -0
- package/dist/__tests__/autofix/branch-manager.test.js.map +1 -0
- package/dist/__tests__/autofix/commit-generator.test.d.ts +2 -0
- package/dist/__tests__/autofix/commit-generator.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/commit-generator.test.js +147 -0
- package/dist/__tests__/autofix/commit-generator.test.js.map +1 -0
- package/dist/__tests__/autofix/constitution.test.d.ts +9 -0
- package/dist/__tests__/autofix/constitution.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/constitution.test.js +421 -0
- package/dist/__tests__/autofix/constitution.test.js.map +1 -0
- package/dist/__tests__/autofix/pr-generator.test.d.ts +2 -0
- package/dist/__tests__/autofix/pr-generator.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/pr-generator.test.js +152 -0
- package/dist/__tests__/autofix/pr-generator.test.js.map +1 -0
- package/dist/__tests__/property-test-helpers.d.ts +87 -0
- package/dist/__tests__/property-test-helpers.d.ts.map +1 -0
- package/dist/__tests__/property-test-helpers.js +136 -0
- package/dist/__tests__/property-test-helpers.js.map +1 -0
- package/dist/__tests__/scanners/dast/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/index.test.js +183 -0
- package/dist/__tests__/scanners/dast/index.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/nuclei.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/nuclei.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/nuclei.test.js +166 -0
- package/dist/__tests__/scanners/dast/nuclei.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/zap.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/zap.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/zap.test.js +158 -0
- package/dist/__tests__/scanners/dast/zap.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-feedback.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.js +202 -0
- package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-filter.property.test.d.ts +9 -0
- package/dist/__tests__/scanners/fp-filter.property.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-filter.property.test.js +253 -0
- package/dist/__tests__/scanners/fp-filter.property.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-filter.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-filter.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-filter.test.js +234 -0
- package/dist/__tests__/scanners/fp-filter.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-tracker.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-tracker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-tracker.test.js +262 -0
- package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts +10 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js +238 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js +55 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/index.test.js +165 -0
- package/dist/__tests__/scanners/logic/index.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/types.test.js +85 -0
- package/dist/__tests__/scanners/logic/types.test.js.map +1 -0
- package/dist/action/pr-comment.test.js +4 -0
- package/dist/action/pr-comment.test.js.map +1 -1
- package/dist/action/sarif-upload.test.js +4 -0
- package/dist/action/sarif-upload.test.js.map +1 -1
- package/dist/autofix/branch-manager.d.ts +115 -0
- package/dist/autofix/branch-manager.d.ts.map +1 -0
- package/dist/autofix/branch-manager.js +308 -0
- package/dist/autofix/branch-manager.js.map +1 -0
- package/dist/autofix/commit-generator.d.ts +55 -0
- package/dist/autofix/commit-generator.d.ts.map +1 -0
- package/dist/autofix/commit-generator.js +277 -0
- package/dist/autofix/commit-generator.js.map +1 -0
- package/dist/autofix/constitution.d.ts +77 -0
- package/dist/autofix/constitution.d.ts.map +1 -0
- package/dist/autofix/constitution.js +261 -0
- package/dist/autofix/constitution.js.map +1 -0
- package/dist/autofix/constitution.schema.d.ts +441 -0
- package/dist/autofix/constitution.schema.d.ts.map +1 -0
- package/dist/autofix/constitution.schema.js +144 -0
- package/dist/autofix/constitution.schema.js.map +1 -0
- package/dist/autofix/index.d.ts +13 -0
- package/dist/autofix/index.d.ts.map +1 -0
- package/dist/autofix/index.js +15 -0
- package/dist/autofix/index.js.map +1 -0
- package/dist/autofix/pr-generator.d.ts +57 -0
- package/dist/autofix/pr-generator.d.ts.map +1 -0
- package/dist/autofix/pr-generator.js +597 -0
- package/dist/autofix/pr-generator.js.map +1 -0
- package/dist/autofix/types.d.ts +151 -0
- package/dist/autofix/types.d.ts.map +1 -0
- package/dist/autofix/types.js +22 -0
- package/dist/autofix/types.js.map +1 -0
- package/dist/eval/fixtures.d.ts +20 -0
- package/dist/eval/fixtures.d.ts.map +1 -1
- package/dist/eval/fixtures.js +430 -0
- package/dist/eval/fixtures.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +84 -1
- package/dist/index.js.map +1 -1
- package/dist/scanners/cache.d.ts.map +1 -1
- package/dist/scanners/cache.js +4 -0
- package/dist/scanners/cache.js.map +1 -1
- package/dist/scanners/dast/index.d.ts +39 -0
- package/dist/scanners/dast/index.d.ts.map +1 -0
- package/dist/scanners/dast/index.js +259 -0
- package/dist/scanners/dast/index.js.map +1 -0
- package/dist/scanners/dast/nuclei.d.ts +26 -0
- package/dist/scanners/dast/nuclei.d.ts.map +1 -0
- package/dist/scanners/dast/nuclei.js +354 -0
- package/dist/scanners/dast/nuclei.js.map +1 -0
- package/dist/scanners/dast/types.d.ts +306 -0
- package/dist/scanners/dast/types.d.ts.map +1 -0
- package/dist/scanners/dast/types.js +52 -0
- package/dist/scanners/dast/types.js.map +1 -0
- package/dist/scanners/dast/zap.d.ts +26 -0
- package/dist/scanners/dast/zap.d.ts.map +1 -0
- package/dist/scanners/dast/zap.js +453 -0
- package/dist/scanners/dast/zap.js.map +1 -0
- package/dist/scanners/fp-feedback.d.ts +140 -0
- package/dist/scanners/fp-feedback.d.ts.map +1 -0
- package/dist/scanners/fp-feedback.js +292 -0
- package/dist/scanners/fp-feedback.js.map +1 -0
- package/dist/scanners/fp-filter.d.ts +94 -0
- package/dist/scanners/fp-filter.d.ts.map +1 -0
- package/dist/scanners/fp-filter.js +397 -0
- package/dist/scanners/fp-filter.js.map +1 -0
- package/dist/scanners/fp-tracker.d.ts +125 -0
- package/dist/scanners/fp-tracker.d.ts.map +1 -0
- package/dist/scanners/fp-tracker.js +330 -0
- package/dist/scanners/fp-tracker.js.map +1 -0
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +56 -0
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/index.test.js +6 -6
- package/dist/scanners/index.test.js.map +1 -1
- package/dist/scanners/logic/auth-flow-analyzer.d.ts +18 -0
- package/dist/scanners/logic/auth-flow-analyzer.d.ts.map +1 -0
- package/dist/scanners/logic/auth-flow-analyzer.js +384 -0
- package/dist/scanners/logic/auth-flow-analyzer.js.map +1 -0
- package/dist/scanners/logic/endpoint-analyzer.d.ts +29 -0
- package/dist/scanners/logic/endpoint-analyzer.d.ts.map +1 -0
- package/dist/scanners/logic/endpoint-analyzer.js +528 -0
- package/dist/scanners/logic/endpoint-analyzer.js.map +1 -0
- package/dist/scanners/logic/index.d.ts +41 -0
- package/dist/scanners/logic/index.d.ts.map +1 -0
- package/dist/scanners/logic/index.js +268 -0
- package/dist/scanners/logic/index.js.map +1 -0
- package/dist/scanners/logic/types.d.ts +254 -0
- package/dist/scanners/logic/types.d.ts.map +1 -0
- package/dist/scanners/logic/types.js +142 -0
- package/dist/scanners/logic/types.js.map +1 -0
- package/dist/scanners/types.d.ts +1 -1
- package/dist/scanners/types.d.ts.map +1 -1
- package/dist/scanners/types.js +4 -0
- package/dist/scanners/types.js.map +1 -1
- package/dist/telemetry/usage.d.ts +1 -1
- package/dist/telemetry/usage.d.ts.map +1 -1
- package/dist/telemetry/usage.js +14 -6
- package/dist/telemetry/usage.js.map +1 -1
- package/package.json +6 -8
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* False Positive Filter
|
|
3
|
+
*
|
|
4
|
+
* Context-aware filtering to reduce false positives from scanners.
|
|
5
|
+
* Analyzes code context, semantic patterns, and historical data.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/fp-filter
|
|
8
|
+
*/
|
|
9
|
+
import { readFile } from "fs/promises";
|
|
10
|
+
import { join, basename } from "path";
|
|
11
|
+
import { logger } from "../logger.js";
|
|
12
|
+
/**
|
|
13
|
+
* Patterns that indicate test files
|
|
14
|
+
*/
|
|
15
|
+
const TEST_FILE_PATTERNS = [
|
|
16
|
+
/\.test\.[jt]sx?$/,
|
|
17
|
+
/\.spec\.[jt]sx?$/,
|
|
18
|
+
/__tests__\//,
|
|
19
|
+
/__mocks__\//,
|
|
20
|
+
/(?:^|\/)test\//,
|
|
21
|
+
/(?:^|\/)tests\//,
|
|
22
|
+
/\.stories\.[jt]sx?$/,
|
|
23
|
+
/\.mock\.[jt]sx?$/,
|
|
24
|
+
/(?:^|\/)cypress\//,
|
|
25
|
+
/(?:^|\/)e2e\//,
|
|
26
|
+
/(?:^|\/)playwright\//,
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Patterns that indicate generated code
|
|
30
|
+
*/
|
|
31
|
+
const GENERATED_CODE_PATTERNS = [
|
|
32
|
+
/\.generated\.[jt]sx?$/,
|
|
33
|
+
/\.gen\.[jt]sx?$/,
|
|
34
|
+
/generated\//,
|
|
35
|
+
/__generated__\//,
|
|
36
|
+
/\.d\.ts$/,
|
|
37
|
+
/swagger-client/,
|
|
38
|
+
/openapi-client/,
|
|
39
|
+
/graphql\.ts$/,
|
|
40
|
+
/prisma\/client/,
|
|
41
|
+
];
|
|
42
|
+
/**
|
|
43
|
+
* Patterns that indicate vendored/third-party code
|
|
44
|
+
*/
|
|
45
|
+
const VENDOR_PATTERNS = [
|
|
46
|
+
/node_modules\//,
|
|
47
|
+
/vendor\//,
|
|
48
|
+
/third[_-]?party\//,
|
|
49
|
+
/external\//,
|
|
50
|
+
/lib\/vendor/,
|
|
51
|
+
/\.min\.js$/,
|
|
52
|
+
/bundle\.js$/,
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* Patterns that indicate fixture/example files
|
|
56
|
+
*/
|
|
57
|
+
const FIXTURE_PATTERNS = [
|
|
58
|
+
/fixtures?\//,
|
|
59
|
+
/samples?\//,
|
|
60
|
+
/examples?\//,
|
|
61
|
+
/demo\//,
|
|
62
|
+
/seed\//,
|
|
63
|
+
/seeds\//,
|
|
64
|
+
/mock[_-]?data/,
|
|
65
|
+
];
|
|
66
|
+
/**
|
|
67
|
+
* Rules that are commonly false positives in certain contexts
|
|
68
|
+
*/
|
|
69
|
+
const CONTEXT_SENSITIVE_RULES = {
|
|
70
|
+
"hardcoded-secret": {
|
|
71
|
+
filterInTests: true,
|
|
72
|
+
filterInGenerated: false,
|
|
73
|
+
filterIfConstant: false,
|
|
74
|
+
filterIfEnvVar: true,
|
|
75
|
+
},
|
|
76
|
+
"sql-injection": {
|
|
77
|
+
filterInTests: true,
|
|
78
|
+
filterInGenerated: true,
|
|
79
|
+
filterIfConstant: true,
|
|
80
|
+
filterIfEnvVar: false,
|
|
81
|
+
},
|
|
82
|
+
"xss": {
|
|
83
|
+
filterInTests: true,
|
|
84
|
+
filterInGenerated: true,
|
|
85
|
+
filterIfConstant: true,
|
|
86
|
+
filterIfEnvVar: false,
|
|
87
|
+
},
|
|
88
|
+
"command-injection": {
|
|
89
|
+
filterInTests: true,
|
|
90
|
+
filterInGenerated: true,
|
|
91
|
+
filterIfConstant: true,
|
|
92
|
+
filterIfEnvVar: false,
|
|
93
|
+
},
|
|
94
|
+
"path-traversal": {
|
|
95
|
+
filterInTests: true,
|
|
96
|
+
filterInGenerated: true,
|
|
97
|
+
filterIfConstant: true,
|
|
98
|
+
filterIfEnvVar: false,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Analyze file path to determine code context
|
|
103
|
+
*/
|
|
104
|
+
export function analyzeFilePath(filePath) {
|
|
105
|
+
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
106
|
+
const fileName = basename(filePath);
|
|
107
|
+
return {
|
|
108
|
+
isTestFile: TEST_FILE_PATTERNS.some((p) => p.test(normalizedPath)),
|
|
109
|
+
isGeneratedCode: GENERATED_CODE_PATTERNS.some((p) => p.test(normalizedPath)),
|
|
110
|
+
isThirdPartyVendored: VENDOR_PATTERNS.some((p) => p.test(normalizedPath)),
|
|
111
|
+
isMockFile: /\.mock\.[jt]sx?$/.test(fileName) || /mocks?\//i.test(normalizedPath),
|
|
112
|
+
isFixtureFile: FIXTURE_PATTERNS.some((p) => p.test(normalizedPath)),
|
|
113
|
+
isExampleFile: /examples?\//i.test(normalizedPath) || /demo\//i.test(normalizedPath),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Analyze code content for semantic context
|
|
118
|
+
*/
|
|
119
|
+
export async function analyzeCodeContext(projectPath, finding) {
|
|
120
|
+
const defaultContext = {
|
|
121
|
+
hasValidation: false,
|
|
122
|
+
hasEncoding: false,
|
|
123
|
+
isSanitized: false,
|
|
124
|
+
isConstant: false,
|
|
125
|
+
isEnvironmentVariable: false,
|
|
126
|
+
};
|
|
127
|
+
if (!finding.file) {
|
|
128
|
+
return defaultContext;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const filePath = join(projectPath, finding.file);
|
|
132
|
+
const content = await readFile(filePath, "utf-8");
|
|
133
|
+
const lines = content.split("\n");
|
|
134
|
+
// Get surrounding context (5 lines before and after)
|
|
135
|
+
const startLine = Math.max(0, (finding.line || 1) - 6);
|
|
136
|
+
const endLine = Math.min(lines.length, (finding.line || 1) + 5);
|
|
137
|
+
const context = lines.slice(startLine, endLine).join("\n");
|
|
138
|
+
// Check for validation patterns
|
|
139
|
+
const validationPatterns = [
|
|
140
|
+
/validate/i,
|
|
141
|
+
/sanitize/i,
|
|
142
|
+
/escape/i,
|
|
143
|
+
/encode/i,
|
|
144
|
+
/\.parse\(/,
|
|
145
|
+
/z\.\w+\(/, // Zod validation
|
|
146
|
+
/yup\.\w+/, // Yup validation
|
|
147
|
+
/joi\.\w+/, // Joi validation
|
|
148
|
+
/validator\./,
|
|
149
|
+
];
|
|
150
|
+
const hasValidation = validationPatterns.some((p) => p.test(context));
|
|
151
|
+
// Check for encoding patterns
|
|
152
|
+
const encodingPatterns = [
|
|
153
|
+
/encodeURIComponent/,
|
|
154
|
+
/encodeURI/,
|
|
155
|
+
/htmlEncode/,
|
|
156
|
+
/escapeHtml/,
|
|
157
|
+
/DOMPurify/,
|
|
158
|
+
/sanitizeHtml/,
|
|
159
|
+
];
|
|
160
|
+
const hasEncoding = encodingPatterns.some((p) => p.test(context));
|
|
161
|
+
// Check for sanitization
|
|
162
|
+
const sanitizationPatterns = [
|
|
163
|
+
/sanitize/i,
|
|
164
|
+
/clean/i,
|
|
165
|
+
/purify/i,
|
|
166
|
+
/strip/i,
|
|
167
|
+
/filter\s*\(/,
|
|
168
|
+
];
|
|
169
|
+
const isSanitized = sanitizationPatterns.some((p) => p.test(context));
|
|
170
|
+
// Check if value is constant
|
|
171
|
+
const line = lines[(finding.line || 1) - 1] || "";
|
|
172
|
+
const isConstant = /const\s+\w+\s*=\s*["'`]/.test(line) ||
|
|
173
|
+
/readonly\s/.test(line) ||
|
|
174
|
+
/as\s+const/.test(line);
|
|
175
|
+
// Check if value comes from environment variable
|
|
176
|
+
const isEnvironmentVariable = /process\.env\./i.test(context) ||
|
|
177
|
+
/import\.meta\.env/i.test(context) ||
|
|
178
|
+
/\$\{.*ENV.*\}/i.test(context);
|
|
179
|
+
return {
|
|
180
|
+
hasValidation,
|
|
181
|
+
hasEncoding,
|
|
182
|
+
isSanitized,
|
|
183
|
+
isConstant,
|
|
184
|
+
isEnvironmentVariable,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
logger.debug("fp_filter.analyze_failed", {
|
|
189
|
+
file: finding.file,
|
|
190
|
+
error: String(error),
|
|
191
|
+
});
|
|
192
|
+
return defaultContext;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Determine if a finding should be filtered as a false positive
|
|
197
|
+
*/
|
|
198
|
+
export function shouldFilter(finding, context) {
|
|
199
|
+
const { codeContext, semanticContext, historicalContext } = context;
|
|
200
|
+
// Always filter vendored/third-party code
|
|
201
|
+
if (codeContext.isThirdPartyVendored) {
|
|
202
|
+
return {
|
|
203
|
+
filter: true,
|
|
204
|
+
reason: "Third-party/vendored code",
|
|
205
|
+
confidence: 95,
|
|
206
|
+
suggestion: "suppress",
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// Get rule-specific filtering rules
|
|
210
|
+
const category = finding.category || extractCategory(finding.ruleId);
|
|
211
|
+
const ruleConfig = CONTEXT_SENSITIVE_RULES[category];
|
|
212
|
+
if (ruleConfig) {
|
|
213
|
+
// Filter in test files for certain rules
|
|
214
|
+
if (ruleConfig.filterInTests && codeContext.isTestFile) {
|
|
215
|
+
return {
|
|
216
|
+
filter: true,
|
|
217
|
+
reason: "Test file - rule typically FP in tests",
|
|
218
|
+
confidence: 85,
|
|
219
|
+
suggestion: "suppress",
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
// Filter in generated code
|
|
223
|
+
if (ruleConfig.filterInGenerated && codeContext.isGeneratedCode) {
|
|
224
|
+
return {
|
|
225
|
+
filter: true,
|
|
226
|
+
reason: "Generated code",
|
|
227
|
+
confidence: 90,
|
|
228
|
+
suggestion: "suppress",
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// Filter if value is constant
|
|
232
|
+
if (ruleConfig.filterIfConstant && semanticContext.isConstant) {
|
|
233
|
+
return {
|
|
234
|
+
filter: true,
|
|
235
|
+
reason: "Constant value - not user-controlled",
|
|
236
|
+
confidence: 75,
|
|
237
|
+
suggestion: "review",
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
// Filter if environment variable
|
|
241
|
+
if (ruleConfig.filterIfEnvVar && semanticContext.isEnvironmentVariable) {
|
|
242
|
+
return {
|
|
243
|
+
filter: true,
|
|
244
|
+
reason: "Environment variable reference",
|
|
245
|
+
confidence: 80,
|
|
246
|
+
suggestion: "review",
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Filter fixture/example files with lower confidence
|
|
251
|
+
if (codeContext.isFixtureFile || codeContext.isExampleFile) {
|
|
252
|
+
return {
|
|
253
|
+
filter: true,
|
|
254
|
+
reason: "Fixture/example file",
|
|
255
|
+
confidence: 70,
|
|
256
|
+
suggestion: "review",
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
// Check if sanitization is present
|
|
260
|
+
if (semanticContext.isSanitized || semanticContext.hasValidation || semanticContext.hasEncoding) {
|
|
261
|
+
return {
|
|
262
|
+
filter: false,
|
|
263
|
+
reason: "Sanitization detected but manual review recommended",
|
|
264
|
+
confidence: 60,
|
|
265
|
+
suggestion: "review",
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// Check historical suppressions
|
|
269
|
+
if (historicalContext.suppressions.includes(finding.ruleId)) {
|
|
270
|
+
return {
|
|
271
|
+
filter: true,
|
|
272
|
+
reason: "Previously suppressed rule",
|
|
273
|
+
confidence: 70,
|
|
274
|
+
suggestion: "review",
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
// Check historical accuracy
|
|
278
|
+
if (historicalContext.ruleAccuracy < 0.3) {
|
|
279
|
+
return {
|
|
280
|
+
filter: false,
|
|
281
|
+
reason: `Low historical accuracy (${Math.round(historicalContext.ruleAccuracy * 100)}%)`,
|
|
282
|
+
confidence: 50,
|
|
283
|
+
suggestion: "review",
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
// No filtering
|
|
287
|
+
return {
|
|
288
|
+
filter: false,
|
|
289
|
+
confidence: 100,
|
|
290
|
+
suggestion: "confirm",
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Extract category from rule ID
|
|
295
|
+
*/
|
|
296
|
+
function extractCategory(ruleId) {
|
|
297
|
+
// Common patterns: "scanner:category.rule" or "category-rule"
|
|
298
|
+
const colonMatch = ruleId.match(/^[^:]+:([^.]+)/);
|
|
299
|
+
if (colonMatch) {
|
|
300
|
+
return colonMatch[1];
|
|
301
|
+
}
|
|
302
|
+
const dashMatch = ruleId.match(/^([a-z-]+)-\d+$/i);
|
|
303
|
+
if (dashMatch) {
|
|
304
|
+
return dashMatch[1];
|
|
305
|
+
}
|
|
306
|
+
return ruleId;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Filter findings and return filtered results with reasons
|
|
310
|
+
*/
|
|
311
|
+
export async function filterFindings(projectPath, findings, options) {
|
|
312
|
+
const minConfidence = options?.minConfidence ?? 70;
|
|
313
|
+
const historicalData = options?.historicalData ?? new Map();
|
|
314
|
+
const filtered = [];
|
|
315
|
+
const removed = [];
|
|
316
|
+
const byReason = {};
|
|
317
|
+
for (const finding of findings) {
|
|
318
|
+
// Build context
|
|
319
|
+
const codeContext = analyzeFilePath(finding.file);
|
|
320
|
+
const semanticContext = await analyzeCodeContext(projectPath, finding);
|
|
321
|
+
const ruleHistory = historicalData.get(finding.ruleId);
|
|
322
|
+
const historicalContext = {
|
|
323
|
+
previousFPs: [],
|
|
324
|
+
ruleAccuracy: ruleHistory?.fpRate ?? 1.0,
|
|
325
|
+
suppressions: ruleHistory?.suppressions ?? [],
|
|
326
|
+
};
|
|
327
|
+
const context = {
|
|
328
|
+
codeContext,
|
|
329
|
+
semanticContext,
|
|
330
|
+
historicalContext,
|
|
331
|
+
};
|
|
332
|
+
const result = shouldFilter(finding, context);
|
|
333
|
+
if (result.filter && result.confidence >= minConfidence) {
|
|
334
|
+
removed.push({
|
|
335
|
+
finding,
|
|
336
|
+
reason: result.reason || "Filtered",
|
|
337
|
+
confidence: result.confidence,
|
|
338
|
+
});
|
|
339
|
+
byReason[result.reason || "Unknown"] = (byReason[result.reason || "Unknown"] || 0) + 1;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
filtered.push(finding);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
logger.info("fp_filter.complete", {
|
|
346
|
+
total: findings.length,
|
|
347
|
+
kept: filtered.length,
|
|
348
|
+
filtered: removed.length,
|
|
349
|
+
});
|
|
350
|
+
return {
|
|
351
|
+
filtered,
|
|
352
|
+
removed,
|
|
353
|
+
stats: {
|
|
354
|
+
total: findings.length,
|
|
355
|
+
kept: filtered.length,
|
|
356
|
+
filtered: removed.length,
|
|
357
|
+
byReason,
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Get suggested suppressions for a finding
|
|
363
|
+
*/
|
|
364
|
+
export function getSuppressSuggestion(finding, context) {
|
|
365
|
+
const scanner = finding.scanner;
|
|
366
|
+
const ruleId = finding.ruleId;
|
|
367
|
+
// Generate scanner-specific suppression comments
|
|
368
|
+
let inlineComment;
|
|
369
|
+
let fileComment;
|
|
370
|
+
switch (scanner) {
|
|
371
|
+
case "semgrep":
|
|
372
|
+
inlineComment = `// nosemgrep: ${ruleId}`;
|
|
373
|
+
fileComment = `// nosemgrep`;
|
|
374
|
+
break;
|
|
375
|
+
case "eslint":
|
|
376
|
+
inlineComment = `// eslint-disable-next-line ${ruleId}`;
|
|
377
|
+
fileComment = `/* eslint-disable ${ruleId} */`;
|
|
378
|
+
break;
|
|
379
|
+
case "gitleaks":
|
|
380
|
+
inlineComment = `// gitleaks:allow`;
|
|
381
|
+
fileComment = `# gitleaks:allow`;
|
|
382
|
+
break;
|
|
383
|
+
case "bandit":
|
|
384
|
+
inlineComment = `# nosec ${ruleId}`;
|
|
385
|
+
fileComment = `# nosec`;
|
|
386
|
+
break;
|
|
387
|
+
default:
|
|
388
|
+
inlineComment = `// @suppress ${ruleId}`;
|
|
389
|
+
fileComment = `// @suppress-file ${ruleId}`;
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
suppressionComment: `Suppressed: ${finding.message} (${context.codeContext.isTestFile ? "test file" : "reviewed"})`,
|
|
393
|
+
inlineSuppress: inlineComment,
|
|
394
|
+
fileSuppress: fileComment,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
//# sourceMappingURL=fp-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fp-filter.js","sourceRoot":"","sources":["../../src/scanners/fp-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAW,MAAM,MAAM,CAAC;AAE/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAkDtC;;GAEG;AACH,MAAM,kBAAkB,GAAG;IACzB,kBAAkB;IAClB,kBAAkB;IAClB,aAAa;IACb,aAAa;IACb,gBAAgB;IAChB,iBAAiB;IACjB,qBAAqB;IACrB,kBAAkB;IAClB,mBAAmB;IACnB,eAAe;IACf,sBAAsB;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,uBAAuB,GAAG;IAC9B,uBAAuB;IACvB,iBAAiB;IACjB,aAAa;IACb,iBAAiB;IACjB,UAAU;IACV,gBAAgB;IAChB,gBAAgB;IAChB,cAAc;IACd,gBAAgB;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,eAAe,GAAG;IACtB,gBAAgB;IAChB,UAAU;IACV,mBAAmB;IACnB,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,aAAa;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,gBAAgB,GAAG;IACvB,aAAa;IACb,YAAY;IACZ,aAAa;IACb,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,eAAe;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,uBAAuB,GAKxB;IACH,kBAAkB,EAAE;QAClB,aAAa,EAAE,IAAI;QACnB,iBAAiB,EAAE,KAAK;QACxB,gBAAgB,EAAE,KAAK;QACvB,cAAc,EAAE,IAAI;KACrB;IACD,eAAe,EAAE;QACf,aAAa,EAAE,IAAI;QACnB,iBAAiB,EAAE,IAAI;QACvB,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,KAAK;KACtB;IACD,KAAK,EAAE;QACL,aAAa,EAAE,IAAI;QACnB,iBAAiB,EAAE,IAAI;QACvB,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,KAAK;KACtB;IACD,mBAAmB,EAAE;QACnB,aAAa,EAAE,IAAI;QACnB,iBAAiB,EAAE,IAAI;QACvB,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,KAAK;KACtB;IACD,gBAAgB,EAAE;QAChB,aAAa,EAAE,IAAI;QACnB,iBAAiB,EAAE,IAAI;QACvB,gBAAgB,EAAE,IAAI;QACtB,cAAc,EAAE,KAAK;KACtB;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEpC,OAAO;QACL,UAAU,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAClE,eAAe,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5E,oBAAoB,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACzE,UAAU,EAAE,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC;QACjF,aAAa,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACnE,aAAa,EAAE,cAAc,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC;KACrF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,OAA6B;IAE7B,MAAM,cAAc,GAAuC;QACzD,aAAa,EAAE,KAAK;QACpB,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,KAAK;QAClB,UAAU,EAAE,KAAK;QACjB,qBAAqB,EAAE,KAAK;KAC7B,CAAC;IAEF,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAElC,qDAAqD;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE3D,gCAAgC;QAChC,MAAM,kBAAkB,GAAG;YACzB,WAAW;YACX,WAAW;YACX,SAAS;YACT,SAAS;YACT,WAAW;YACX,UAAU,EAAG,iBAAiB;YAC9B,UAAU,EAAG,iBAAiB;YAC9B,UAAU,EAAG,iBAAiB;YAC9B,aAAa;SACd,CAAC;QACF,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAEtE,8BAA8B;QAC9B,MAAM,gBAAgB,GAAG;YACvB,oBAAoB;YACpB,WAAW;YACX,YAAY;YACZ,YAAY;YACZ,WAAW;YACX,cAAc;SACf,CAAC;QACF,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAElE,yBAAyB;QACzB,MAAM,oBAAoB,GAAG;YAC3B,WAAW;YACX,QAAQ;YACR,SAAS;YACT,QAAQ;YACR,aAAa;SACd,CAAC;QACF,MAAM,WAAW,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAEtE,6BAA6B;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;YACpC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YACvB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE3C,iDAAiD;QACjD,MAAM,qBAAqB,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC;YAC9B,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC;YAClC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE9D,OAAO;YACL,aAAa;YACb,WAAW;YACX,WAAW;YACX,UAAU;YACV,qBAAqB;SACtB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE;YACvC,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;SACrB,CAAC,CAAC;QACH,OAAO,cAAc,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,OAA6B,EAC7B,OAAwB;IAExB,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;IAEpE,0CAA0C;IAC1C,IAAI,WAAW,CAAC,oBAAoB,EAAE,CAAC;QACrC,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,2BAA2B;YACnC,UAAU,EAAE,EAAE;YACd,UAAU,EAAE,UAAU;SACvB,CAAC;IACJ,CAAC;IAED,oCAAoC;IACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAErD,IAAI,UAAU,EAAE,CAAC;QACf,yCAAyC;QACzC,IAAI,UAAU,CAAC,aAAa,IAAI,WAAW,CAAC,UAAU,EAAE,CAAC;YACvD,OAAO;gBACL,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,wCAAwC;gBAChD,UAAU,EAAE,EAAE;gBACd,UAAU,EAAE,UAAU;aACvB,CAAC;QACJ,CAAC;QAED,2BAA2B;QAC3B,IAAI,UAAU,CAAC,iBAAiB,IAAI,WAAW,CAAC,eAAe,EAAE,CAAC;YAChE,OAAO;gBACL,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,gBAAgB;gBACxB,UAAU,EAAE,EAAE;gBACd,UAAU,EAAE,UAAU;aACvB,CAAC;QACJ,CAAC;QAED,8BAA8B;QAC9B,IAAI,UAAU,CAAC,gBAAgB,IAAI,eAAe,CAAC,UAAU,EAAE,CAAC;YAC9D,OAAO;gBACL,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,sCAAsC;gBAC9C,UAAU,EAAE,EAAE;gBACd,UAAU,EAAE,QAAQ;aACrB,CAAC;QACJ,CAAC;QAED,iCAAiC;QACjC,IAAI,UAAU,CAAC,cAAc,IAAI,eAAe,CAAC,qBAAqB,EAAE,CAAC;YACvE,OAAO;gBACL,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,gCAAgC;gBACxC,UAAU,EAAE,EAAE;gBACd,UAAU,EAAE,QAAQ;aACrB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,IAAI,WAAW,CAAC,aAAa,IAAI,WAAW,CAAC,aAAa,EAAE,CAAC;QAC3D,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,sBAAsB;YAC9B,UAAU,EAAE,EAAE;YACd,UAAU,EAAE,QAAQ;SACrB,CAAC;IACJ,CAAC;IAED,mCAAmC;IACnC,IAAI,eAAe,CAAC,WAAW,IAAI,eAAe,CAAC,aAAa,IAAI,eAAe,CAAC,WAAW,EAAE,CAAC;QAChG,OAAO;YACL,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,qDAAqD;YAC7D,UAAU,EAAE,EAAE;YACd,UAAU,EAAE,QAAQ;SACrB,CAAC;IACJ,CAAC;IAED,gCAAgC;IAChC,IAAI,iBAAiB,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,4BAA4B;YACpC,UAAU,EAAE,EAAE;YACd,UAAU,EAAE,QAAQ;SACrB,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,IAAI,iBAAiB,CAAC,YAAY,GAAG,GAAG,EAAE,CAAC;QACzC,OAAO;YACL,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,4BAA4B,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,YAAY,GAAG,GAAG,CAAC,IAAI;YACxF,UAAU,EAAE,EAAE;YACd,UAAU,EAAE,QAAQ;SACrB,CAAC;IACJ,CAAC;IAED,eAAe;IACf,OAAO;QACL,MAAM,EAAE,KAAK;QACb,UAAU,EAAE,GAAG;QACf,UAAU,EAAE,SAAS;KACtB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,8DAA8D;IAC9D,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAClD,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACnD,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,QAAgC,EAChC,OAGC;IAWD,MAAM,aAAa,GAAG,OAAO,EAAE,aAAa,IAAI,EAAE,CAAC;IACnD,MAAM,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,IAAI,GAAG,EAAE,CAAC;IAE5D,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAiF,EAAE,CAAC;IACjG,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAE5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,gBAAgB;QAChB,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,eAAe,GAAG,MAAM,kBAAkB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAEvE,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,iBAAiB,GAAyC;YAC9D,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,WAAW,EAAE,MAAM,IAAI,GAAG;YACxC,YAAY,EAAE,WAAW,EAAE,YAAY,IAAI,EAAE;SAC9C,CAAC;QAEF,MAAM,OAAO,GAAoB;YAC/B,WAAW;YACX,eAAe;YACf,iBAAiB;SAClB,CAAC;QAEF,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAE9C,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,UAAU,IAAI,aAAa,EAAE,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC;gBACX,OAAO;gBACP,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,UAAU;gBACnC,UAAU,EAAE,MAAM,CAAC,UAAU;aAC9B,CAAC,CAAC;YACH,QAAQ,CAAC,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACzF,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE;QAChC,KAAK,EAAE,QAAQ,CAAC,MAAM;QACtB,IAAI,EAAE,QAAQ,CAAC,MAAM;QACrB,QAAQ,EAAE,OAAO,CAAC,MAAM;KACzB,CAAC,CAAC;IAEH,OAAO;QACL,QAAQ;QACR,OAAO;QACP,KAAK,EAAE;YACL,KAAK,EAAE,QAAQ,CAAC,MAAM;YACtB,IAAI,EAAE,QAAQ,CAAC,MAAM;YACrB,QAAQ,EAAE,OAAO,CAAC,MAAM;YACxB,QAAQ;SACT;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAA6B,EAC7B,OAAwB;IAMxB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAE9B,iDAAiD;IACjD,IAAI,aAAqB,CAAC;IAC1B,IAAI,WAAmB,CAAC;IAExB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,SAAS;YACZ,aAAa,GAAG,iBAAiB,MAAM,EAAE,CAAC;YAC1C,WAAW,GAAG,cAAc,CAAC;YAC7B,MAAM;QACR,KAAK,QAAQ;YACX,aAAa,GAAG,+BAA+B,MAAM,EAAE,CAAC;YACxD,WAAW,GAAG,qBAAqB,MAAM,KAAK,CAAC;YAC/C,MAAM;QACR,KAAK,UAAU;YACb,aAAa,GAAG,mBAAmB,CAAC;YACpC,WAAW,GAAG,kBAAkB,CAAC;YACjC,MAAM;QACR,KAAK,QAAQ;YACX,aAAa,GAAG,WAAW,MAAM,EAAE,CAAC;YACpC,WAAW,GAAG,SAAS,CAAC;YACxB,MAAM;QACR;YACE,aAAa,GAAG,gBAAgB,MAAM,EAAE,CAAC;YACzC,WAAW,GAAG,qBAAqB,MAAM,EAAE,CAAC;IAChD,CAAC;IAED,OAAO;QACL,kBAAkB,EAAE,eAAe,OAAO,CAAC,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,GAAG;QACnH,cAAc,EAAE,aAAa;QAC7B,YAAY,EAAE,WAAW;KAC1B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* False Positive Tracker
|
|
3
|
+
*
|
|
4
|
+
* Tracks false positive rates per scanner/rule and adjusts
|
|
5
|
+
* finding confidence accordingly.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/fp-tracker
|
|
8
|
+
*/
|
|
9
|
+
import type { ScannerType, DeterministicFinding } from "./types.js";
|
|
10
|
+
import type { Severity } from "../certification/types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Metrics for a specific rule
|
|
13
|
+
*/
|
|
14
|
+
export interface RuleMetrics {
|
|
15
|
+
/** Scanner that generated this rule */
|
|
16
|
+
scanner: ScannerType;
|
|
17
|
+
/** Rule ID */
|
|
18
|
+
ruleId: string;
|
|
19
|
+
/** Total findings reported by this rule */
|
|
20
|
+
totalReported: number;
|
|
21
|
+
/** Number confirmed as true positives */
|
|
22
|
+
confirmedTP: number;
|
|
23
|
+
/** Number confirmed as false positives */
|
|
24
|
+
confirmedFP: number;
|
|
25
|
+
/** Number still pending review */
|
|
26
|
+
pendingReview: number;
|
|
27
|
+
/** Calculated FP rate (0-1) */
|
|
28
|
+
fpRate: number;
|
|
29
|
+
/** Calculated TP rate (0-1) */
|
|
30
|
+
tpRate: number;
|
|
31
|
+
/** Confidence adjustment factor based on history */
|
|
32
|
+
adjustmentFactor: number;
|
|
33
|
+
/** Last updated timestamp */
|
|
34
|
+
lastUpdated: string;
|
|
35
|
+
/** Severity distribution of findings */
|
|
36
|
+
severityDistribution: Partial<Record<Severity, number>>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Aggregated scanner metrics
|
|
40
|
+
*/
|
|
41
|
+
export interface ScannerMetrics {
|
|
42
|
+
scanner: ScannerType;
|
|
43
|
+
totalRules: number;
|
|
44
|
+
totalFindings: number;
|
|
45
|
+
overallFPRate: number;
|
|
46
|
+
overallTPRate: number;
|
|
47
|
+
ruleMetrics: Map<string, RuleMetrics>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* FP tracking data store
|
|
51
|
+
*/
|
|
52
|
+
export interface FPTrackingData {
|
|
53
|
+
version: string;
|
|
54
|
+
lastUpdated: string;
|
|
55
|
+
projectPath: string;
|
|
56
|
+
scanners: Record<string, ScannerMetrics>;
|
|
57
|
+
globalStats: {
|
|
58
|
+
totalFindings: number;
|
|
59
|
+
totalTP: number;
|
|
60
|
+
totalFP: number;
|
|
61
|
+
totalPending: number;
|
|
62
|
+
overallAccuracy: number;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Load FP tracking data from disk
|
|
67
|
+
*/
|
|
68
|
+
export declare function loadTrackingData(projectPath: string): Promise<FPTrackingData>;
|
|
69
|
+
/**
|
|
70
|
+
* Save FP tracking data to disk
|
|
71
|
+
*/
|
|
72
|
+
export declare function saveTrackingData(projectPath: string, data: FPTrackingData): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Record a new finding for tracking
|
|
75
|
+
*/
|
|
76
|
+
export declare function recordFinding(projectPath: string, finding: DeterministicFinding): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Mark a finding as true positive
|
|
79
|
+
*/
|
|
80
|
+
export declare function markTruePositive(projectPath: string, scanner: ScannerType, ruleId: string): Promise<RuleMetrics | undefined>;
|
|
81
|
+
/**
|
|
82
|
+
* Mark a finding as false positive
|
|
83
|
+
*/
|
|
84
|
+
export declare function markFalsePositive(projectPath: string, scanner: ScannerType, ruleId: string, reason?: string): Promise<RuleMetrics | undefined>;
|
|
85
|
+
/**
|
|
86
|
+
* Adjust finding confidence based on historical FP rates
|
|
87
|
+
*/
|
|
88
|
+
export declare function adjustFindingConfidence(finding: DeterministicFinding, metrics: RuleMetrics | undefined): number;
|
|
89
|
+
/**
|
|
90
|
+
* Get metrics for a specific rule
|
|
91
|
+
*/
|
|
92
|
+
export declare function getRuleMetrics(projectPath: string, scanner: ScannerType, ruleId: string): Promise<RuleMetrics | undefined>;
|
|
93
|
+
/**
|
|
94
|
+
* Get all scanner metrics
|
|
95
|
+
*/
|
|
96
|
+
export declare function getAllMetrics(projectPath: string): Promise<FPTrackingData>;
|
|
97
|
+
/**
|
|
98
|
+
* Get rules with high FP rates
|
|
99
|
+
*/
|
|
100
|
+
export declare function getHighFPRules(projectPath: string, threshold?: number, minSampleSize?: number): Promise<RuleMetrics[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Generate FP tracking report
|
|
103
|
+
*/
|
|
104
|
+
export declare function generateFPReport(projectPath: string, options?: {
|
|
105
|
+
minSampleSize?: number;
|
|
106
|
+
includeAllRules?: boolean;
|
|
107
|
+
}): Promise<{
|
|
108
|
+
summary: {
|
|
109
|
+
totalScanners: number;
|
|
110
|
+
totalRules: number;
|
|
111
|
+
totalFindings: number;
|
|
112
|
+
overallAccuracy: number;
|
|
113
|
+
highFPRuleCount: number;
|
|
114
|
+
};
|
|
115
|
+
scannerBreakdown: Array<{
|
|
116
|
+
scanner: ScannerType;
|
|
117
|
+
totalFindings: number;
|
|
118
|
+
fpRate: number;
|
|
119
|
+
tpRate: number;
|
|
120
|
+
ruleCount: number;
|
|
121
|
+
}>;
|
|
122
|
+
highFPRules: RuleMetrics[];
|
|
123
|
+
recommendations: string[];
|
|
124
|
+
}>;
|
|
125
|
+
//# sourceMappingURL=fp-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fp-tracker.d.ts","sourceRoot":"","sources":["../../src/scanners/fp-tracker.ts"],"names":[],"mappings":"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"}
|