codeslick-cli 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/__tests__/threshold-handler.test.ts +175 -0
  2. package/dist/packages/cli/src/commands/scan.d.ts +11 -0
  3. package/dist/packages/cli/src/commands/scan.d.ts.map +1 -1
  4. package/dist/packages/cli/src/commands/scan.js +74 -5
  5. package/dist/packages/cli/src/commands/scan.js.map +1 -1
  6. package/dist/packages/cli/src/config/config-loader.d.ts +11 -0
  7. package/dist/packages/cli/src/config/config-loader.d.ts.map +1 -1
  8. package/dist/packages/cli/src/config/config-loader.js.map +1 -1
  9. package/dist/packages/cli/src/reporters/cli-reporter.d.ts +18 -0
  10. package/dist/packages/cli/src/reporters/cli-reporter.d.ts.map +1 -1
  11. package/dist/packages/cli/src/reporters/cli-reporter.js +115 -0
  12. package/dist/packages/cli/src/reporters/cli-reporter.js.map +1 -1
  13. package/dist/packages/cli/src/utils/test-runner.d.ts +84 -0
  14. package/dist/packages/cli/src/utils/test-runner.d.ts.map +1 -0
  15. package/dist/packages/cli/src/utils/test-runner.js +209 -0
  16. package/dist/packages/cli/src/utils/test-runner.js.map +1 -0
  17. package/dist/packages/cli/src/utils/threshold-handler.d.ts +40 -0
  18. package/dist/packages/cli/src/utils/threshold-handler.d.ts.map +1 -0
  19. package/dist/packages/cli/src/utils/threshold-handler.js +85 -0
  20. package/dist/packages/cli/src/utils/threshold-handler.js.map +1 -0
  21. package/dist/src/lib/analyzers/go-analyzer.d.ts +5 -0
  22. package/dist/src/lib/analyzers/go-analyzer.d.ts.map +1 -1
  23. package/dist/src/lib/analyzers/go-analyzer.js +47 -0
  24. package/dist/src/lib/analyzers/go-analyzer.js.map +1 -1
  25. package/dist/src/lib/analyzers/java-analyzer.d.ts +5 -0
  26. package/dist/src/lib/analyzers/java-analyzer.d.ts.map +1 -1
  27. package/dist/src/lib/analyzers/java-analyzer.js +48 -0
  28. package/dist/src/lib/analyzers/java-analyzer.js.map +1 -1
  29. package/dist/src/lib/analyzers/javascript-analyzer.d.ts +5 -0
  30. package/dist/src/lib/analyzers/javascript-analyzer.d.ts.map +1 -1
  31. package/dist/src/lib/analyzers/javascript-analyzer.js +48 -0
  32. package/dist/src/lib/analyzers/javascript-analyzer.js.map +1 -1
  33. package/dist/src/lib/analyzers/python-analyzer.d.ts +5 -0
  34. package/dist/src/lib/analyzers/python-analyzer.d.ts.map +1 -1
  35. package/dist/src/lib/analyzers/python-analyzer.js +55 -0
  36. package/dist/src/lib/analyzers/python-analyzer.js.map +1 -1
  37. package/dist/src/lib/analyzers/types.d.ts +4 -0
  38. package/dist/src/lib/analyzers/types.d.ts.map +1 -1
  39. package/dist/src/lib/analyzers/typescript-analyzer.d.ts +5 -0
  40. package/dist/src/lib/analyzers/typescript-analyzer.d.ts.map +1 -1
  41. package/dist/src/lib/analyzers/typescript-analyzer.js +48 -0
  42. package/dist/src/lib/analyzers/typescript-analyzer.js.map +1 -1
  43. package/dist/src/lib/github/types.d.ts +112 -0
  44. package/dist/src/lib/github/types.d.ts.map +1 -0
  45. package/dist/src/lib/github/types.js +34 -0
  46. package/dist/src/lib/github/types.js.map +1 -0
  47. package/dist/src/lib/security/epss-service.d.ts +63 -0
  48. package/dist/src/lib/security/epss-service.d.ts.map +1 -0
  49. package/dist/src/lib/security/epss-service.js +256 -0
  50. package/dist/src/lib/security/epss-service.js.map +1 -0
  51. package/dist/src/lib/security/threshold-evaluator.d.ts +73 -0
  52. package/dist/src/lib/security/threshold-evaluator.d.ts.map +1 -0
  53. package/dist/src/lib/security/threshold-evaluator.js +234 -0
  54. package/dist/src/lib/security/threshold-evaluator.js.map +1 -0
  55. package/dist/src/lib/security/triage-service.d.ts +76 -0
  56. package/dist/src/lib/security/triage-service.d.ts.map +1 -0
  57. package/dist/src/lib/security/triage-service.js +318 -0
  58. package/dist/src/lib/security/triage-service.js.map +1 -0
  59. package/dist/src/lib/types/index.d.ts +4 -0
  60. package/dist/src/lib/types/index.d.ts.map +1 -1
  61. package/package.json +1 -1
  62. package/src/commands/scan.ts +100 -7
  63. package/src/config/config-loader.ts +15 -0
  64. package/src/reporters/cli-reporter.ts +132 -0
  65. package/src/utils/test-runner.ts +249 -0
  66. package/src/utils/threshold-handler.ts +99 -0
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ /**
3
+ * EPSS (Exploit Prediction Scoring System) Service
4
+ *
5
+ * Fetches exploit prediction scores from FIRST.org EPSS API
6
+ * Used for smart triage and vulnerability prioritization
7
+ *
8
+ * Feature 1 Phase 1 (Q1 2026): Alert Deduplication & AutoTriage
9
+ *
10
+ * API: https://api.first.org/data/v1/epss
11
+ * Docs: https://www.first.org/epss/api
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.getEPSSScores = getEPSSScores;
15
+ exports.getEPSSScore = getEPSSScore;
16
+ exports.clearEPSSCache = clearEPSSCache;
17
+ exports.getEPSSCacheStats = getEPSSCacheStats;
18
+ exports.interpretEPSSScore = interpretEPSSScore;
19
+ exports.getEPSSScoresBatch = getEPSSScoresBatch;
20
+ /**
21
+ * In-memory cache for EPSS scores
22
+ * TTL: 24 hours (EPSS data updates daily)
23
+ */
24
+ const epssCache = new Map();
25
+ const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours
26
+ /**
27
+ * Rate limiting: Max 1 request per second to FIRST.org API
28
+ */
29
+ let lastRequestTime = 0;
30
+ const MIN_REQUEST_INTERVAL = 1000; // 1 second
31
+ /**
32
+ * Fetch EPSS scores for given CVE IDs
33
+ *
34
+ * @param cveIds - Array of CVE IDs (e.g., ["CVE-2021-44228", "CVE-2022-12345"])
35
+ * @returns Array of EPSS scores (0 if not found or error)
36
+ */
37
+ async function getEPSSScores(cveIds) {
38
+ console.log('[EPSS] getEPSSScores called with', cveIds.length, 'CVE IDs:', cveIds);
39
+ if (!cveIds || cveIds.length === 0) {
40
+ console.log('[EPSS] No CVE IDs provided, returning empty array');
41
+ return [];
42
+ }
43
+ // Filter out invalid CVE IDs and deduplicate
44
+ const validCveIds = [...new Set(cveIds.filter(isValidCveId))];
45
+ console.log('[EPSS] Valid CVE IDs after filtering:', validCveIds);
46
+ if (validCveIds.length === 0) {
47
+ console.log('[EPSS] No valid CVE IDs found, returning empty array');
48
+ return [];
49
+ }
50
+ const results = [];
51
+ const cveIdsToFetch = [];
52
+ // Check cache first
53
+ for (const cveId of validCveIds) {
54
+ const cached = epssCache.get(cveId);
55
+ if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
56
+ results.push({ ...cached.score, cached: true });
57
+ }
58
+ else {
59
+ cveIdsToFetch.push(cveId);
60
+ }
61
+ }
62
+ // If all results are cached, return immediately
63
+ if (cveIdsToFetch.length === 0) {
64
+ return results;
65
+ }
66
+ // Fetch from API
67
+ try {
68
+ // Rate limiting: wait if needed
69
+ const now = Date.now();
70
+ const timeSinceLastRequest = now - lastRequestTime;
71
+ if (timeSinceLastRequest < MIN_REQUEST_INTERVAL) {
72
+ await new Promise(resolve => setTimeout(resolve, MIN_REQUEST_INTERVAL - timeSinceLastRequest));
73
+ }
74
+ lastRequestTime = Date.now();
75
+ // FIRST.org EPSS API supports bulk queries
76
+ // Format: ?cve=CVE-2021-44228,CVE-2022-12345
77
+ const cveParam = cveIdsToFetch.join(',');
78
+ const url = `https://api.first.org/data/v1/epss?cve=${encodeURIComponent(cveParam)}`;
79
+ const response = await fetch(url, {
80
+ method: 'GET',
81
+ headers: {
82
+ 'Accept': 'application/json',
83
+ 'User-Agent': 'CodeSlick/1.0 (Security Analysis Tool)',
84
+ },
85
+ // 10 second timeout
86
+ signal: AbortSignal.timeout(10000),
87
+ });
88
+ if (!response.ok) {
89
+ console.warn(`[EPSS] API returned ${response.status}: ${response.statusText}`);
90
+ // Return default scores for unfetched CVEs
91
+ return [
92
+ ...results,
93
+ ...cveIdsToFetch.map(cveId => createDefaultScore(cveId)),
94
+ ];
95
+ }
96
+ const data = await response.json();
97
+ if (data.status !== 'OK') {
98
+ console.warn(`[EPSS] API status: ${data.status}`);
99
+ return [
100
+ ...results,
101
+ ...cveIdsToFetch.map(cveId => createDefaultScore(cveId)),
102
+ ];
103
+ }
104
+ // Parse and cache results
105
+ for (const item of data.data) {
106
+ const score = {
107
+ cve: item.cve,
108
+ epssScore: parseFloat(item.epss),
109
+ percentile: parseFloat(item.percentile),
110
+ date: item.date,
111
+ cached: false,
112
+ };
113
+ // Cache the result
114
+ epssCache.set(item.cve, {
115
+ score,
116
+ timestamp: Date.now(),
117
+ });
118
+ results.push(score);
119
+ }
120
+ // Add default scores for CVEs not found in API response
121
+ const foundCves = new Set(data.data.map(item => item.cve.toUpperCase()));
122
+ for (const cveId of cveIdsToFetch) {
123
+ if (!foundCves.has(cveId.toUpperCase())) {
124
+ const defaultScore = createDefaultScore(cveId);
125
+ // Cache default score (shorter TTL)
126
+ epssCache.set(cveId, {
127
+ score: defaultScore,
128
+ timestamp: Date.now(),
129
+ });
130
+ results.push(defaultScore);
131
+ }
132
+ }
133
+ return results;
134
+ }
135
+ catch (error) {
136
+ console.error('[EPSS] Error fetching scores:', error);
137
+ // Return default scores on error
138
+ return [
139
+ ...results,
140
+ ...cveIdsToFetch.map(cveId => createDefaultScore(cveId)),
141
+ ];
142
+ }
143
+ }
144
+ /**
145
+ * Fetch EPSS score for a single CVE
146
+ *
147
+ * @param cveId - CVE ID (e.g., "CVE-2021-44228")
148
+ * @returns EPSS score or null if not found
149
+ */
150
+ async function getEPSSScore(cveId) {
151
+ const scores = await getEPSSScores([cveId]);
152
+ return scores.length > 0 ? scores[0] : null;
153
+ }
154
+ /**
155
+ * Validate CVE ID format
156
+ *
157
+ * @param cveId - CVE ID to validate
158
+ * @returns true if valid format
159
+ */
160
+ function isValidCveId(cveId) {
161
+ if (!cveId || typeof cveId !== 'string') {
162
+ return false;
163
+ }
164
+ // CVE format: CVE-YYYY-NNNNN (year can be 1999-2999, number can be 1-99999)
165
+ return /^CVE-\d{4}-\d{1,7}$/i.test(cveId.trim());
166
+ }
167
+ /**
168
+ * Create default EPSS score for CVEs not found in API
169
+ *
170
+ * @param cveId - CVE ID
171
+ * @returns Default EPSS score (0.0)
172
+ */
173
+ function createDefaultScore(cveId) {
174
+ return {
175
+ cve: cveId,
176
+ epssScore: 0.0, // Assume low exploit probability if not in EPSS database
177
+ percentile: 0.0,
178
+ date: new Date().toISOString().split('T')[0],
179
+ cached: false,
180
+ };
181
+ }
182
+ /**
183
+ * Clear EPSS cache (useful for testing or manual refresh)
184
+ */
185
+ function clearEPSSCache() {
186
+ epssCache.clear();
187
+ console.log('[EPSS] Cache cleared');
188
+ }
189
+ /**
190
+ * Get cache statistics
191
+ */
192
+ function getEPSSCacheStats() {
193
+ let oldestTimestamp = null;
194
+ for (const entry of epssCache.values()) {
195
+ if (oldestTimestamp === null || entry.timestamp < oldestTimestamp) {
196
+ oldestTimestamp = entry.timestamp;
197
+ }
198
+ }
199
+ return {
200
+ size: epssCache.size,
201
+ oldestEntry: oldestTimestamp,
202
+ };
203
+ }
204
+ /**
205
+ * Interpret EPSS score for human-readable risk level
206
+ *
207
+ * @param epssScore - EPSS score (0.0-1.0)
208
+ * @returns Human-readable risk level
209
+ */
210
+ function interpretEPSSScore(epssScore) {
211
+ if (epssScore >= 0.7) {
212
+ return {
213
+ risk: 'critical',
214
+ description: 'Very high probability of exploitation (top 30% of all CVEs)',
215
+ };
216
+ }
217
+ else if (epssScore >= 0.3) {
218
+ return {
219
+ risk: 'high',
220
+ description: 'High probability of exploitation',
221
+ };
222
+ }
223
+ else if (epssScore >= 0.1) {
224
+ return {
225
+ risk: 'medium',
226
+ description: 'Moderate probability of exploitation',
227
+ };
228
+ }
229
+ else {
230
+ return {
231
+ risk: 'low',
232
+ description: 'Low probability of exploitation',
233
+ };
234
+ }
235
+ }
236
+ /**
237
+ * Batch fetch EPSS scores with chunking for large CVE lists
238
+ * FIRST.org API supports up to 100 CVEs per request
239
+ *
240
+ * @param cveIds - Array of CVE IDs
241
+ * @param chunkSize - Number of CVEs per API call (default: 50)
242
+ * @returns Array of EPSS scores
243
+ */
244
+ async function getEPSSScoresBatch(cveIds, chunkSize = 50) {
245
+ const chunks = [];
246
+ for (let i = 0; i < cveIds.length; i += chunkSize) {
247
+ chunks.push(cveIds.slice(i, i + chunkSize));
248
+ }
249
+ const allScores = [];
250
+ for (const chunk of chunks) {
251
+ const scores = await getEPSSScores(chunk);
252
+ allScores.push(...scores);
253
+ }
254
+ return allScores;
255
+ }
256
+ //# sourceMappingURL=epss-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epss-service.js","sourceRoot":"","sources":["../../../../../../src/lib/security/epss-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Threshold Evaluator - Pass/Fail Security Gates
3
+ *
4
+ * Evaluates whether analysis results meet configured security thresholds.
5
+ * Used by:
6
+ * - GitHub PR checks (block merges)
7
+ * - CLI scans (exit codes)
8
+ * - Team dashboard (preview feature)
9
+ *
10
+ * Winter Roadmap WR2: Pass/Fail Thresholds
11
+ */
12
+ import type { AggregatedResults } from '../github/types';
13
+ /**
14
+ * Threshold configuration (from team settings)
15
+ */
16
+ export interface ThresholdConfig {
17
+ enabled: boolean;
18
+ blockOnCritical: boolean;
19
+ blockOnHigh: boolean;
20
+ maxVulnerabilities: number;
21
+ maxEpss: number;
22
+ exemptPaths: string[];
23
+ failureMessage?: string;
24
+ }
25
+ /**
26
+ * Threshold evaluation result
27
+ */
28
+ export interface ThresholdResult {
29
+ passed: boolean;
30
+ reason: string;
31
+ blockedBy: 'critical' | 'high' | 'count' | 'epss' | null;
32
+ vulnerabilityCount: number;
33
+ criticalCount: number;
34
+ highCount: number;
35
+ maxEpssFound: number;
36
+ exemptedCount: number;
37
+ }
38
+ /**
39
+ * Default threshold configuration
40
+ */
41
+ export declare const DEFAULT_THRESHOLD_CONFIG: ThresholdConfig;
42
+ /**
43
+ * Evaluate security thresholds against analysis results
44
+ *
45
+ * @param results - Aggregated analysis results
46
+ * @param config - Threshold configuration
47
+ * @returns Threshold evaluation result
48
+ *
49
+ * @example
50
+ * const result = evaluateThresholds(analysisResults, {
51
+ * enabled: true,
52
+ * blockOnCritical: true,
53
+ * blockOnHigh: false,
54
+ * maxVulnerabilities: 10,
55
+ * maxEpss: 70,
56
+ * exemptPaths: ['/test/ **', '** /*.test.ts'] // (remove spaces)
57
+ * });
58
+ *
59
+ * if (!result.passed) {
60
+ * console.log('Threshold failed:', result.reason);
61
+ * process.exit(1);
62
+ * }
63
+ */
64
+ export declare function evaluateThresholds(results: AggregatedResults, config: ThresholdConfig): ThresholdResult;
65
+ /**
66
+ * Format threshold result as GitHub status message (140 char limit)
67
+ */
68
+ export declare function formatGitHubStatusMessage(result: ThresholdResult, customMessage?: string): string;
69
+ /**
70
+ * Format threshold result for CLI output
71
+ */
72
+ export declare function formatCLIOutput(result: ThresholdResult): string;
73
+ //# sourceMappingURL=threshold-evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-evaluator.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/security/threshold-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;IACzD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAOtC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,eAAe,GACtB,eAAe,CAqEjB;AA0GD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,eAAe,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CASjG;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAqB/D"}
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ /**
3
+ * Threshold Evaluator - Pass/Fail Security Gates
4
+ *
5
+ * Evaluates whether analysis results meet configured security thresholds.
6
+ * Used by:
7
+ * - GitHub PR checks (block merges)
8
+ * - CLI scans (exit codes)
9
+ * - Team dashboard (preview feature)
10
+ *
11
+ * Winter Roadmap WR2: Pass/Fail Thresholds
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.DEFAULT_THRESHOLD_CONFIG = void 0;
15
+ exports.evaluateThresholds = evaluateThresholds;
16
+ exports.formatGitHubStatusMessage = formatGitHubStatusMessage;
17
+ exports.formatCLIOutput = formatCLIOutput;
18
+ const minimatch_1 = require("minimatch");
19
+ /**
20
+ * Default threshold configuration
21
+ */
22
+ exports.DEFAULT_THRESHOLD_CONFIG = {
23
+ enabled: false,
24
+ blockOnCritical: true,
25
+ blockOnHigh: false,
26
+ maxVulnerabilities: 50,
27
+ maxEpss: 70, // 70%
28
+ exemptPaths: [],
29
+ };
30
+ /**
31
+ * Evaluate security thresholds against analysis results
32
+ *
33
+ * @param results - Aggregated analysis results
34
+ * @param config - Threshold configuration
35
+ * @returns Threshold evaluation result
36
+ *
37
+ * @example
38
+ * const result = evaluateThresholds(analysisResults, {
39
+ * enabled: true,
40
+ * blockOnCritical: true,
41
+ * blockOnHigh: false,
42
+ * maxVulnerabilities: 10,
43
+ * maxEpss: 70,
44
+ * exemptPaths: ['/test/ **', '** /*.test.ts'] // (remove spaces)
45
+ * });
46
+ *
47
+ * if (!result.passed) {
48
+ * console.log('Threshold failed:', result.reason);
49
+ * process.exit(1);
50
+ * }
51
+ */
52
+ function evaluateThresholds(results, config) {
53
+ // If thresholds disabled, always pass
54
+ if (!config.enabled) {
55
+ return {
56
+ passed: true,
57
+ reason: 'Thresholds disabled',
58
+ blockedBy: null,
59
+ vulnerabilityCount: results.totalVulnerabilities,
60
+ criticalCount: results.criticalCount,
61
+ highCount: results.highCount,
62
+ maxEpssFound: 0,
63
+ exemptedCount: 0,
64
+ };
65
+ }
66
+ // Filter vulnerabilities by exempt paths
67
+ const { filteredResults, exemptedCount } = filterExemptPaths(results, config.exemptPaths);
68
+ // Calculate max EPSS score found
69
+ const maxEpssFound = calculateMaxEpss(filteredResults);
70
+ // Build result object
71
+ const result = {
72
+ passed: true,
73
+ reason: '',
74
+ blockedBy: null,
75
+ vulnerabilityCount: filteredResults.totalVulnerabilities,
76
+ criticalCount: filteredResults.criticalCount,
77
+ highCount: filteredResults.highCount,
78
+ maxEpssFound,
79
+ exemptedCount,
80
+ };
81
+ // Check 1: Block on critical
82
+ if (config.blockOnCritical && filteredResults.criticalCount > 0) {
83
+ result.passed = false;
84
+ result.blockedBy = 'critical';
85
+ result.reason = `${filteredResults.criticalCount} critical vulnerabilit${filteredResults.criticalCount !== 1 ? 'ies' : 'y'} found`;
86
+ return result;
87
+ }
88
+ // Check 2: Block on high
89
+ if (config.blockOnHigh && filteredResults.highCount > 0) {
90
+ result.passed = false;
91
+ result.blockedBy = 'high';
92
+ result.reason = `${filteredResults.highCount} high priority vulnerabilit${filteredResults.highCount !== 1 ? 'ies' : 'y'} found`;
93
+ return result;
94
+ }
95
+ // Check 3: Max vulnerability count
96
+ if (config.maxVulnerabilities > 0 && filteredResults.totalVulnerabilities > config.maxVulnerabilities) {
97
+ result.passed = false;
98
+ result.blockedBy = 'count';
99
+ result.reason = `${filteredResults.totalVulnerabilities} vulnerabilities exceed limit of ${config.maxVulnerabilities}`;
100
+ return result;
101
+ }
102
+ // Check 4: EPSS threshold
103
+ if (config.maxEpss > 0 && maxEpssFound > config.maxEpss / 100) {
104
+ result.passed = false;
105
+ result.blockedBy = 'epss';
106
+ result.reason = `EPSS ${(maxEpssFound * 100).toFixed(1)}% exceeds threshold of ${config.maxEpss}%`;
107
+ return result;
108
+ }
109
+ // All checks passed
110
+ result.passed = true;
111
+ result.reason = formatPassReason(filteredResults);
112
+ return result;
113
+ }
114
+ /**
115
+ * Filter vulnerabilities by exempt paths (glob patterns)
116
+ */
117
+ function filterExemptPaths(results, exemptPaths) {
118
+ // If no exempt paths, return original results
119
+ if (!exemptPaths || exemptPaths.length === 0) {
120
+ return { filteredResults: results, exemptedCount: 0 };
121
+ }
122
+ let exemptedCount = 0;
123
+ let criticalCount = 0;
124
+ let highCount = 0;
125
+ let mediumCount = 0;
126
+ let lowCount = 0;
127
+ // Filter file results
128
+ const filteredFileResults = results.fileResults.map(fileResult => {
129
+ const filteredVulnerabilities = fileResult.vulnerabilities.filter(vuln => {
130
+ // Check if file matches any exempt pattern
131
+ const isExempt = exemptPaths.some(pattern => (0, minimatch_1.minimatch)(fileResult.filename, pattern, { matchBase: true }));
132
+ if (isExempt) {
133
+ exemptedCount++;
134
+ return false; // Skip this vulnerability
135
+ }
136
+ // Count by severity
137
+ switch (vuln.severity) {
138
+ case 'critical':
139
+ criticalCount++;
140
+ break;
141
+ case 'high':
142
+ highCount++;
143
+ break;
144
+ case 'medium':
145
+ mediumCount++;
146
+ break;
147
+ case 'low':
148
+ lowCount++;
149
+ break;
150
+ }
151
+ return true; // Include this vulnerability
152
+ });
153
+ return {
154
+ ...fileResult,
155
+ vulnerabilities: filteredVulnerabilities,
156
+ };
157
+ });
158
+ // Build filtered results
159
+ const filteredResults = {
160
+ ...results,
161
+ fileResults: filteredFileResults,
162
+ totalVulnerabilities: criticalCount + highCount + mediumCount + lowCount,
163
+ criticalCount,
164
+ highCount,
165
+ mediumCount,
166
+ lowCount,
167
+ };
168
+ return { filteredResults, exemptedCount };
169
+ }
170
+ /**
171
+ * Calculate maximum EPSS score from all vulnerabilities
172
+ */
173
+ function calculateMaxEpss(results) {
174
+ let maxEpss = 0;
175
+ for (const fileResult of results.fileResults) {
176
+ for (const vuln of fileResult.vulnerabilities) {
177
+ if (vuln.epssScore !== undefined && vuln.epssScore > maxEpss) {
178
+ maxEpss = vuln.epssScore;
179
+ }
180
+ }
181
+ }
182
+ return maxEpss;
183
+ }
184
+ /**
185
+ * Format pass reason (summary of results)
186
+ */
187
+ function formatPassReason(results) {
188
+ if (results.totalVulnerabilities === 0) {
189
+ return 'No security vulnerabilities found';
190
+ }
191
+ const parts = [];
192
+ if (results.criticalCount > 0)
193
+ parts.push(`${results.criticalCount} critical`);
194
+ if (results.highCount > 0)
195
+ parts.push(`${results.highCount} high`);
196
+ if (results.mediumCount > 0)
197
+ parts.push(`${results.mediumCount} medium`);
198
+ if (results.lowCount > 0)
199
+ parts.push(`${results.lowCount} low`);
200
+ return `${results.totalVulnerabilities} vulnerabilities found (${parts.join(', ')})`;
201
+ }
202
+ /**
203
+ * Format threshold result as GitHub status message (140 char limit)
204
+ */
205
+ function formatGitHubStatusMessage(result, customMessage) {
206
+ if (!result.passed && customMessage) {
207
+ return customMessage.substring(0, 140);
208
+ }
209
+ const prefix = result.passed ? '✅' : '❌';
210
+ const message = `${prefix} ${result.reason}`;
211
+ return message.substring(0, 140);
212
+ }
213
+ /**
214
+ * Format threshold result for CLI output
215
+ */
216
+ function formatCLIOutput(result) {
217
+ if (result.passed) {
218
+ return `\n✅ THRESHOLD PASSED\n${result.reason}\n`;
219
+ }
220
+ let output = `\n❌ THRESHOLD FAILED\n`;
221
+ output += `Reason: ${result.reason}\n`;
222
+ output += `\nVulnerabilities (after exemptions):\n`;
223
+ output += ` Critical: ${result.criticalCount}\n`;
224
+ output += ` High: ${result.highCount}\n`;
225
+ output += ` Total: ${result.vulnerabilityCount}\n`;
226
+ if (result.exemptedCount > 0) {
227
+ output += `\nExempted: ${result.exemptedCount} vulnerabilities in exempt paths\n`;
228
+ }
229
+ if (result.maxEpssFound > 0) {
230
+ output += `Max EPSS: ${(result.maxEpssFound * 100).toFixed(1)}%\n`;
231
+ }
232
+ return output;
233
+ }
234
+ //# sourceMappingURL=threshold-evaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threshold-evaluator.js","sourceRoot":"","sources":["../../../../../../src/lib/security/threshold-evaluator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Smart Triage Service
3
+ *
4
+ * Computes priority scores for security issues using multiple signals:
5
+ * - CVSS Score (base severity)
6
+ * - EPSS Score (exploit prediction)
7
+ * - OWASP Category (criticality weight)
8
+ * - Environment Context (production vs dev)
9
+ *
10
+ * Feature 1 Phase 1 (Q1 2026): Alert Deduplication & AutoTriage
11
+ *
12
+ * Priority Formula:
13
+ * priority = cvss * 0.5 + epss * 0.3 + owasp_weight * 0.2
14
+ */
15
+ import { SecurityVulnerability } from '../analyzers/types';
16
+ /**
17
+ * Environment context for triage
18
+ * Production issues get higher priority
19
+ */
20
+ export interface EnvironmentContext {
21
+ isProduction?: boolean;
22
+ hasPublicExposure?: boolean;
23
+ hasSensitiveData?: boolean;
24
+ }
25
+ /**
26
+ * Triage configuration
27
+ */
28
+ export interface TriageConfig {
29
+ cvssWeight?: number;
30
+ epssWeight?: number;
31
+ owaspWeight?: number;
32
+ environmentContext?: EnvironmentContext;
33
+ }
34
+ /**
35
+ * Triage result with priority and reasoning
36
+ */
37
+ export interface TriageResult {
38
+ issue: SecurityVulnerability;
39
+ priorityScore: number;
40
+ priority: 'critical' | 'high' | 'medium' | 'low' | 'info';
41
+ triageReason: string;
42
+ epssScore?: number;
43
+ }
44
+ /**
45
+ * Triage multiple security issues with smart prioritization
46
+ *
47
+ * @param issues - Array of security issues to triage
48
+ * @param config - Triage configuration
49
+ * @returns Array of triage results sorted by priority (highest first)
50
+ */
51
+ export declare function triageSecurityIssues(issues: SecurityVulnerability[], config?: TriageConfig): Promise<TriageResult[]>;
52
+ /**
53
+ * Get triage statistics for a set of results
54
+ *
55
+ * @param results - Triage results
56
+ * @returns Triage statistics
57
+ */
58
+ export declare function getTriageStats(results: TriageResult[]): {
59
+ total: number;
60
+ critical: number;
61
+ high: number;
62
+ medium: number;
63
+ low: number;
64
+ info: number;
65
+ withEPSS: number;
66
+ averagePriority: number;
67
+ };
68
+ /**
69
+ * Filter triage results by minimum priority level
70
+ *
71
+ * @param results - Triage results
72
+ * @param minPriority - Minimum priority level ('critical' | 'high' | 'medium' | 'low')
73
+ * @returns Filtered results
74
+ */
75
+ export declare function filterByPriority(results: TriageResult[], minPriority: 'critical' | 'high' | 'medium' | 'low'): TriageResult[];
76
+ //# sourceMappingURL=triage-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage-service.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/security/triage-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AA4B3D;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,qBAAqB,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC1D,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkOD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,qBAAqB,EAAE,EAC/B,MAAM,GAAE,YAAiB,GACxB,OAAO,CAAC,YAAY,EAAE,CAAC,CA6CzB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAyBA;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,YAAY,EAAE,EACvB,WAAW,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAClD,YAAY,EAAE,CAKhB"}