@nahisaho/musubix-security 1.8.0 → 1.8.5

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 (186) hide show
  1. package/README.md +27 -0
  2. package/dist/analyzers/ai/index.d.ts +6 -0
  3. package/dist/analyzers/ai/index.d.ts.map +1 -0
  4. package/dist/analyzers/ai/index.js +6 -0
  5. package/dist/analyzers/ai/index.js.map +1 -0
  6. package/dist/analyzers/ai/prompt-injection-detector.d.ts +152 -0
  7. package/dist/analyzers/ai/prompt-injection-detector.d.ts.map +1 -0
  8. package/dist/analyzers/ai/prompt-injection-detector.js +468 -0
  9. package/dist/analyzers/ai/prompt-injection-detector.js.map +1 -0
  10. package/dist/analyzers/api/api-security-analyzer.d.ts +263 -0
  11. package/dist/analyzers/api/api-security-analyzer.d.ts.map +1 -0
  12. package/dist/analyzers/api/api-security-analyzer.js +581 -0
  13. package/dist/analyzers/api/api-security-analyzer.js.map +1 -0
  14. package/dist/analyzers/compliance/compliance-checker.d.ts +201 -0
  15. package/dist/analyzers/compliance/compliance-checker.d.ts.map +1 -0
  16. package/dist/analyzers/compliance/compliance-checker.js +772 -0
  17. package/dist/analyzers/compliance/compliance-checker.js.map +1 -0
  18. package/dist/analyzers/container/image-scanner.d.ts +163 -0
  19. package/dist/analyzers/container/image-scanner.d.ts.map +1 -0
  20. package/dist/analyzers/container/image-scanner.js +459 -0
  21. package/dist/analyzers/container/image-scanner.js.map +1 -0
  22. package/dist/analyzers/container/index.d.ts +6 -0
  23. package/dist/analyzers/container/index.d.ts.map +1 -0
  24. package/dist/analyzers/container/index.js +6 -0
  25. package/dist/analyzers/container/index.js.map +1 -0
  26. package/dist/analyzers/dashboard/security-dashboard.d.ts +286 -0
  27. package/dist/analyzers/dashboard/security-dashboard.d.ts.map +1 -0
  28. package/dist/analyzers/dashboard/security-dashboard.js +796 -0
  29. package/dist/analyzers/dashboard/security-dashboard.js.map +1 -0
  30. package/dist/analyzers/iac/iac-checker.d.ts +124 -0
  31. package/dist/analyzers/iac/iac-checker.d.ts.map +1 -0
  32. package/dist/analyzers/iac/iac-checker.js +755 -0
  33. package/dist/analyzers/iac/iac-checker.js.map +1 -0
  34. package/dist/analyzers/iac/index.d.ts +6 -0
  35. package/dist/analyzers/iac/index.d.ts.map +1 -0
  36. package/dist/analyzers/iac/index.js +6 -0
  37. package/dist/analyzers/iac/index.js.map +1 -0
  38. package/dist/analyzers/index.d.ts +9 -0
  39. package/dist/analyzers/index.d.ts.map +1 -0
  40. package/dist/analyzers/index.js +13 -0
  41. package/dist/analyzers/index.js.map +1 -0
  42. package/dist/analyzers/monitor/realtime-monitor.d.ts +216 -0
  43. package/dist/analyzers/monitor/realtime-monitor.d.ts.map +1 -0
  44. package/dist/analyzers/monitor/realtime-monitor.js +601 -0
  45. package/dist/analyzers/monitor/realtime-monitor.js.map +1 -0
  46. package/dist/analyzers/sast/index.d.ts +7 -0
  47. package/dist/analyzers/sast/index.d.ts.map +1 -0
  48. package/dist/analyzers/sast/index.js +7 -0
  49. package/dist/analyzers/sast/index.js.map +1 -0
  50. package/dist/analyzers/sast/interprocedural-analyzer.d.ts +276 -0
  51. package/dist/analyzers/sast/interprocedural-analyzer.d.ts.map +1 -0
  52. package/dist/analyzers/sast/interprocedural-analyzer.js +635 -0
  53. package/dist/analyzers/sast/interprocedural-analyzer.js.map +1 -0
  54. package/dist/analyzers/sast/zero-day-detector.d.ts +183 -0
  55. package/dist/analyzers/sast/zero-day-detector.d.ts.map +1 -0
  56. package/dist/analyzers/sast/zero-day-detector.js +593 -0
  57. package/dist/analyzers/sast/zero-day-detector.js.map +1 -0
  58. package/dist/analyzers/sca/dependency-scanner.d.ts +275 -0
  59. package/dist/analyzers/sca/dependency-scanner.d.ts.map +1 -0
  60. package/dist/analyzers/sca/dependency-scanner.js +642 -0
  61. package/dist/analyzers/sca/dependency-scanner.js.map +1 -0
  62. package/dist/core/index.d.ts +8 -0
  63. package/dist/core/index.d.ts.map +1 -0
  64. package/dist/core/index.js +10 -0
  65. package/dist/core/index.js.map +1 -0
  66. package/dist/core/pipeline-manager.d.ts +105 -0
  67. package/dist/core/pipeline-manager.d.ts.map +1 -0
  68. package/dist/core/pipeline-manager.js +449 -0
  69. package/dist/core/pipeline-manager.js.map +1 -0
  70. package/dist/core/result-aggregator.d.ts +96 -0
  71. package/dist/core/result-aggregator.d.ts.map +1 -0
  72. package/dist/core/result-aggregator.js +462 -0
  73. package/dist/core/result-aggregator.js.map +1 -0
  74. package/dist/index.d.ts +15 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +68 -0
  77. package/dist/index.js.map +1 -1
  78. package/dist/integrations/ci-integration.d.ts +227 -0
  79. package/dist/integrations/ci-integration.d.ts.map +1 -0
  80. package/dist/integrations/ci-integration.js +472 -0
  81. package/dist/integrations/ci-integration.js.map +1 -0
  82. package/dist/integrations/git-hooks.d.ts +155 -0
  83. package/dist/integrations/git-hooks.d.ts.map +1 -0
  84. package/dist/integrations/git-hooks.js +425 -0
  85. package/dist/integrations/git-hooks.js.map +1 -0
  86. package/dist/integrations/index.d.ts +9 -0
  87. package/dist/integrations/index.d.ts.map +1 -0
  88. package/dist/integrations/index.js +9 -0
  89. package/dist/integrations/index.js.map +1 -0
  90. package/dist/integrations/report-aggregator.d.ts +250 -0
  91. package/dist/integrations/report-aggregator.d.ts.map +1 -0
  92. package/dist/integrations/report-aggregator.js +488 -0
  93. package/dist/integrations/report-aggregator.js.map +1 -0
  94. package/dist/integrations/vscode-integration.d.ts +245 -0
  95. package/dist/integrations/vscode-integration.d.ts.map +1 -0
  96. package/dist/integrations/vscode-integration.js +449 -0
  97. package/dist/integrations/vscode-integration.js.map +1 -0
  98. package/dist/intelligence/attack-pattern-matcher.d.ts +217 -0
  99. package/dist/intelligence/attack-pattern-matcher.d.ts.map +1 -0
  100. package/dist/intelligence/attack-pattern-matcher.js +887 -0
  101. package/dist/intelligence/attack-pattern-matcher.js.map +1 -0
  102. package/dist/intelligence/index.d.ts +12 -0
  103. package/dist/intelligence/index.d.ts.map +1 -0
  104. package/dist/intelligence/index.js +18 -0
  105. package/dist/intelligence/index.js.map +1 -0
  106. package/dist/intelligence/neuro-symbolic-core.d.ts +88 -0
  107. package/dist/intelligence/neuro-symbolic-core.d.ts.map +1 -0
  108. package/dist/intelligence/neuro-symbolic-core.js +403 -0
  109. package/dist/intelligence/neuro-symbolic-core.js.map +1 -0
  110. package/dist/intelligence/predictive-analyzer.d.ts +317 -0
  111. package/dist/intelligence/predictive-analyzer.d.ts.map +1 -0
  112. package/dist/intelligence/predictive-analyzer.js +714 -0
  113. package/dist/intelligence/predictive-analyzer.js.map +1 -0
  114. package/dist/intelligence/risk-scorer.d.ts +333 -0
  115. package/dist/intelligence/risk-scorer.d.ts.map +1 -0
  116. package/dist/intelligence/risk-scorer.js +824 -0
  117. package/dist/intelligence/risk-scorer.js.map +1 -0
  118. package/dist/intelligence/security-analytics.d.ts +349 -0
  119. package/dist/intelligence/security-analytics.d.ts.map +1 -0
  120. package/dist/intelligence/security-analytics.js +813 -0
  121. package/dist/intelligence/security-analytics.js.map +1 -0
  122. package/dist/intelligence/threat-intelligence.d.ts +288 -0
  123. package/dist/intelligence/threat-intelligence.d.ts.map +1 -0
  124. package/dist/intelligence/threat-intelligence.js +639 -0
  125. package/dist/intelligence/threat-intelligence.js.map +1 -0
  126. package/dist/policy/index.d.ts +6 -0
  127. package/dist/policy/index.d.ts.map +1 -0
  128. package/dist/policy/index.js +6 -0
  129. package/dist/policy/index.js.map +1 -0
  130. package/dist/policy/policy-engine.d.ts +254 -0
  131. package/dist/policy/policy-engine.d.ts.map +1 -0
  132. package/dist/policy/policy-engine.js +651 -0
  133. package/dist/policy/policy-engine.js.map +1 -0
  134. package/dist/remediation/auto-fixer.d.ts +179 -0
  135. package/dist/remediation/auto-fixer.d.ts.map +1 -0
  136. package/dist/remediation/auto-fixer.js +540 -0
  137. package/dist/remediation/auto-fixer.js.map +1 -0
  138. package/dist/remediation/fix-validator.d.ts +195 -0
  139. package/dist/remediation/fix-validator.d.ts.map +1 -0
  140. package/dist/remediation/fix-validator.js +462 -0
  141. package/dist/remediation/fix-validator.js.map +1 -0
  142. package/dist/remediation/index.d.ts +10 -0
  143. package/dist/remediation/index.d.ts.map +1 -0
  144. package/dist/remediation/index.js +15 -0
  145. package/dist/remediation/index.js.map +1 -0
  146. package/dist/remediation/patch-generator.d.ts +203 -0
  147. package/dist/remediation/patch-generator.d.ts.map +1 -0
  148. package/dist/remediation/patch-generator.js +533 -0
  149. package/dist/remediation/patch-generator.js.map +1 -0
  150. package/dist/remediation/remediation-planner.d.ts +262 -0
  151. package/dist/remediation/remediation-planner.d.ts.map +1 -0
  152. package/dist/remediation/remediation-planner.js +531 -0
  153. package/dist/remediation/remediation-planner.js.map +1 -0
  154. package/dist/remediation/secure-code-transformer.d.ts +222 -0
  155. package/dist/remediation/secure-code-transformer.d.ts.map +1 -0
  156. package/dist/remediation/secure-code-transformer.js +625 -0
  157. package/dist/remediation/secure-code-transformer.js.map +1 -0
  158. package/dist/types/fix.d.ts +3 -1
  159. package/dist/types/fix.d.ts.map +1 -1
  160. package/dist/types/index.d.ts +6 -0
  161. package/dist/types/index.d.ts.map +1 -1
  162. package/dist/types/index.js +1 -0
  163. package/dist/types/index.js.map +1 -1
  164. package/dist/types/interprocedural.d.ts +203 -0
  165. package/dist/types/interprocedural.d.ts.map +1 -0
  166. package/dist/types/interprocedural.js +7 -0
  167. package/dist/types/interprocedural.js.map +1 -0
  168. package/dist/types/neuro-symbolic.d.ts +179 -0
  169. package/dist/types/neuro-symbolic.d.ts.map +1 -0
  170. package/dist/types/neuro-symbolic.js +7 -0
  171. package/dist/types/neuro-symbolic.js.map +1 -0
  172. package/dist/types/pipeline.d.ts +173 -0
  173. package/dist/types/pipeline.d.ts.map +1 -0
  174. package/dist/types/pipeline.js +7 -0
  175. package/dist/types/pipeline.js.map +1 -0
  176. package/dist/types/result.d.ts +134 -0
  177. package/dist/types/result.d.ts.map +1 -0
  178. package/dist/types/result.js +25 -0
  179. package/dist/types/result.js.map +1 -0
  180. package/dist/types/vulnerability.d.ts +2 -2
  181. package/dist/types/vulnerability.d.ts.map +1 -1
  182. package/dist/types/zero-day.d.ts +146 -0
  183. package/dist/types/zero-day.d.ts.map +1 -0
  184. package/dist/types/zero-day.js +7 -0
  185. package/dist/types/zero-day.js.map +1 -0
  186. package/package.json +2 -2
@@ -0,0 +1,796 @@
1
+ /**
2
+ * @fileoverview Security Dashboard - Integrated security reporting and visualization
3
+ * @module @nahisaho/musubix-security/analyzers/dashboard/security-dashboard
4
+ * @trace DES-SEC3-DASH-001, REQ-SEC3-DASH-001
5
+ */
6
+ /**
7
+ * OWASP Top 10 2021 categories
8
+ */
9
+ const OWASP_TOP_10 = [
10
+ {
11
+ id: 'A01:2021',
12
+ name: 'Broken Access Control',
13
+ patterns: ['authorization', 'access-control', 'idor', 'privilege'],
14
+ },
15
+ {
16
+ id: 'A02:2021',
17
+ name: 'Cryptographic Failures',
18
+ patterns: ['crypto', 'encryption', 'weak-cipher', 'hardcoded-key'],
19
+ },
20
+ {
21
+ id: 'A03:2021',
22
+ name: 'Injection',
23
+ patterns: ['sql-injection', 'command-injection', 'xss', 'code-injection', 'ldap-injection'],
24
+ },
25
+ {
26
+ id: 'A04:2021',
27
+ name: 'Insecure Design',
28
+ patterns: ['insecure-design', 'missing-auth', 'business-logic'],
29
+ },
30
+ {
31
+ id: 'A05:2021',
32
+ name: 'Security Misconfiguration',
33
+ patterns: ['misconfiguration', 'default-credentials', 'verbose-errors'],
34
+ },
35
+ {
36
+ id: 'A06:2021',
37
+ name: 'Vulnerable and Outdated Components',
38
+ patterns: ['vulnerable-dependency', 'outdated', 'component'],
39
+ },
40
+ {
41
+ id: 'A07:2021',
42
+ name: 'Identification and Authentication Failures',
43
+ patterns: ['authentication', 'session', 'weak-password', 'brute-force'],
44
+ },
45
+ {
46
+ id: 'A08:2021',
47
+ name: 'Software and Data Integrity Failures',
48
+ patterns: ['integrity', 'deserialization', 'ci-cd', 'supply-chain'],
49
+ },
50
+ {
51
+ id: 'A09:2021',
52
+ name: 'Security Logging and Monitoring Failures',
53
+ patterns: ['logging', 'monitoring', 'audit'],
54
+ },
55
+ {
56
+ id: 'A10:2021',
57
+ name: 'Server-Side Request Forgery (SSRF)',
58
+ patterns: ['ssrf', 'request-forgery'],
59
+ },
60
+ ];
61
+ /**
62
+ * CWE names mapping (common ones)
63
+ */
64
+ const CWE_NAMES = {
65
+ 'CWE-20': 'Improper Input Validation',
66
+ 'CWE-22': 'Path Traversal',
67
+ 'CWE-78': 'OS Command Injection',
68
+ 'CWE-79': 'Cross-site Scripting (XSS)',
69
+ 'CWE-89': 'SQL Injection',
70
+ 'CWE-94': 'Code Injection',
71
+ 'CWE-200': 'Information Exposure',
72
+ 'CWE-287': 'Improper Authentication',
73
+ 'CWE-306': 'Missing Authentication',
74
+ 'CWE-311': 'Missing Encryption',
75
+ 'CWE-327': 'Weak Cryptography',
76
+ 'CWE-352': 'Cross-Site Request Forgery (CSRF)',
77
+ 'CWE-400': 'Resource Exhaustion',
78
+ 'CWE-502': 'Deserialization of Untrusted Data',
79
+ 'CWE-522': 'Insufficiently Protected Credentials',
80
+ 'CWE-601': 'Open Redirect',
81
+ 'CWE-611': 'XXE',
82
+ 'CWE-798': 'Hardcoded Credentials',
83
+ 'CWE-918': 'Server-Side Request Forgery (SSRF)',
84
+ };
85
+ /**
86
+ * Security Dashboard
87
+ * @trace DES-SEC3-DASH-001
88
+ */
89
+ export class SecurityDashboard {
90
+ config;
91
+ vulnerabilities = [];
92
+ scanResults = [];
93
+ trendHistory = [];
94
+ constructor(config) {
95
+ this.config = {
96
+ projectName: config.projectName,
97
+ format: config.format ?? 'json',
98
+ includeTrends: config.includeTrends ?? true,
99
+ includeRecommendations: config.includeRecommendations ?? true,
100
+ branding: config.branding ?? {},
101
+ };
102
+ }
103
+ /**
104
+ * Add scan results to dashboard
105
+ * @trace REQ-SEC3-DASH-001
106
+ */
107
+ addScanResult(result) {
108
+ this.scanResults.push(result);
109
+ this.vulnerabilities.push(...result.vulnerabilities);
110
+ // Add to trend history
111
+ this.trendHistory.push({
112
+ timestamp: result.scannedAt,
113
+ totalVulnerabilities: this.vulnerabilities.length,
114
+ critical: result.summary.critical,
115
+ high: result.summary.high,
116
+ medium: result.summary.medium,
117
+ low: result.summary.low,
118
+ securityScore: this.calculateSecurityScore(this.vulnerabilities),
119
+ });
120
+ }
121
+ /**
122
+ * Add vulnerabilities directly
123
+ */
124
+ addVulnerabilities(vulnerabilities) {
125
+ this.vulnerabilities.push(...vulnerabilities);
126
+ }
127
+ /**
128
+ * Clear all data
129
+ */
130
+ clear() {
131
+ this.vulnerabilities = [];
132
+ this.scanResults = [];
133
+ }
134
+ /**
135
+ * Generate dashboard report
136
+ */
137
+ generateReport() {
138
+ const metrics = this.calculateMetrics();
139
+ const topVulnerabilities = this.getTopVulnerabilities();
140
+ const componentRisks = this.calculateComponentRisks();
141
+ const summary = this.generateExecutiveSummary(metrics, topVulnerabilities);
142
+ const report = {
143
+ generatedAt: new Date(),
144
+ projectName: this.config.projectName,
145
+ summary,
146
+ metrics,
147
+ topVulnerabilities,
148
+ componentRisks,
149
+ vulnerabilities: this.vulnerabilities,
150
+ scanSummary: this.generateScanSummary(),
151
+ };
152
+ if (this.config.includeTrends) {
153
+ report.trends = this.calculateTrends();
154
+ }
155
+ if (this.config.includeRecommendations) {
156
+ report.recommendations = this.generateRecommendations(metrics, topVulnerabilities);
157
+ }
158
+ return report;
159
+ }
160
+ /**
161
+ * Export report in specified format
162
+ */
163
+ exportReport(format) {
164
+ const report = this.generateReport();
165
+ const outputFormat = format ?? this.config.format;
166
+ switch (outputFormat) {
167
+ case 'html':
168
+ return this.toHTML(report);
169
+ case 'markdown':
170
+ return this.toMarkdown(report);
171
+ default:
172
+ return JSON.stringify(report, null, 2);
173
+ }
174
+ }
175
+ /**
176
+ * Calculate security metrics
177
+ */
178
+ calculateMetrics() {
179
+ const bySeverity = {
180
+ critical: 0,
181
+ high: 0,
182
+ medium: 0,
183
+ low: 0,
184
+ info: 0,
185
+ };
186
+ const byType = {};
187
+ const byComponent = {};
188
+ const cweCount = {};
189
+ const owaspCount = {};
190
+ for (const vuln of this.vulnerabilities) {
191
+ // By severity
192
+ bySeverity[vuln.severity]++;
193
+ // By type
194
+ byType[vuln.type] = (byType[vuln.type] ?? 0) + 1;
195
+ // By component (file)
196
+ const component = vuln.location.file;
197
+ byComponent[component] = (byComponent[component] ?? 0) + 1;
198
+ // CWE distribution
199
+ for (const cwe of vuln.cwes ?? []) {
200
+ cweCount[cwe] = (cweCount[cwe] ?? 0) + 1;
201
+ }
202
+ // OWASP coverage
203
+ for (const owasp of vuln.owasp ?? []) {
204
+ owaspCount[owasp] = (owaspCount[owasp] ?? 0) + 1;
205
+ }
206
+ }
207
+ const total = this.vulnerabilities.length;
208
+ // Calculate OWASP coverage
209
+ const owaspCoverage = OWASP_TOP_10.map(owasp => ({
210
+ id: owasp.id,
211
+ name: owasp.name,
212
+ count: owaspCount[owasp.id] ?? 0,
213
+ percentage: total > 0 ? Math.round(((owaspCount[owasp.id] ?? 0) / total) * 100) : 0,
214
+ }));
215
+ // Calculate CWE distribution
216
+ const cweDistribution = Object.entries(cweCount)
217
+ .sort(([, a], [, b]) => b - a)
218
+ .slice(0, 10)
219
+ .map(([cwe, count]) => ({
220
+ cwe,
221
+ name: CWE_NAMES[cwe] ?? cwe,
222
+ count,
223
+ percentage: total > 0 ? Math.round((count / total) * 100) : 0,
224
+ }));
225
+ const securityScore = this.calculateSecurityScore(this.vulnerabilities);
226
+ const riskLevel = this.determineRiskLevel(bySeverity, securityScore);
227
+ return {
228
+ totalVulnerabilities: total,
229
+ bySeverity,
230
+ byType,
231
+ byComponent,
232
+ owaspCoverage,
233
+ cweDistribution,
234
+ securityScore,
235
+ riskLevel,
236
+ };
237
+ }
238
+ /**
239
+ * Calculate security score
240
+ */
241
+ calculateSecurityScore(vulnerabilities) {
242
+ let score = 100;
243
+ for (const vuln of vulnerabilities) {
244
+ switch (vuln.severity) {
245
+ case 'critical':
246
+ score -= 15;
247
+ break;
248
+ case 'high':
249
+ score -= 10;
250
+ break;
251
+ case 'medium':
252
+ score -= 5;
253
+ break;
254
+ case 'low':
255
+ score -= 2;
256
+ break;
257
+ case 'info':
258
+ score -= 1;
259
+ break;
260
+ }
261
+ }
262
+ return Math.max(0, Math.min(100, score));
263
+ }
264
+ /**
265
+ * Determine risk level
266
+ */
267
+ determineRiskLevel(bySeverity, score) {
268
+ if (bySeverity.critical > 0 || score < 30)
269
+ return 'critical';
270
+ if (bySeverity.high > 2 || score < 50)
271
+ return 'high';
272
+ if (bySeverity.high > 0 || bySeverity.medium > 5 || score < 70)
273
+ return 'medium';
274
+ if (bySeverity.medium > 0 || score < 90)
275
+ return 'low';
276
+ return 'minimal';
277
+ }
278
+ /**
279
+ * Get top vulnerabilities
280
+ */
281
+ getTopVulnerabilities() {
282
+ const typeMap = new Map();
283
+ for (const vuln of this.vulnerabilities) {
284
+ const existing = typeMap.get(vuln.type);
285
+ if (existing) {
286
+ existing.count++;
287
+ for (const cwe of vuln.cwes ?? []) {
288
+ existing.cwes.add(cwe);
289
+ }
290
+ // Keep highest severity
291
+ if (this.severityValue(vuln.severity) > this.severityValue(existing.severity)) {
292
+ existing.severity = vuln.severity;
293
+ }
294
+ }
295
+ else {
296
+ typeMap.set(vuln.type, {
297
+ count: 1,
298
+ severity: vuln.severity,
299
+ cwes: new Set(vuln.cwes ?? []),
300
+ recommendation: vuln.recommendation ?? 'Review and fix the vulnerability',
301
+ });
302
+ }
303
+ }
304
+ return Array.from(typeMap.entries())
305
+ .map(([type, data]) => ({
306
+ type,
307
+ count: data.count,
308
+ severity: data.severity,
309
+ cwes: Array.from(data.cwes),
310
+ recommendation: data.recommendation,
311
+ }))
312
+ .sort((a, b) => {
313
+ const severityDiff = this.severityValue(b.severity) - this.severityValue(a.severity);
314
+ return severityDiff !== 0 ? severityDiff : b.count - a.count;
315
+ })
316
+ .slice(0, 10);
317
+ }
318
+ /**
319
+ * Calculate component risks
320
+ */
321
+ calculateComponentRisks() {
322
+ const componentMap = new Map();
323
+ for (const vuln of this.vulnerabilities) {
324
+ const component = vuln.location.file;
325
+ const existing = componentMap.get(component) ?? { total: 0, critical: 0, high: 0 };
326
+ existing.total++;
327
+ if (vuln.severity === 'critical')
328
+ existing.critical++;
329
+ if (vuln.severity === 'high')
330
+ existing.high++;
331
+ componentMap.set(component, existing);
332
+ }
333
+ return Array.from(componentMap.entries())
334
+ .map(([component, data]) => ({
335
+ component,
336
+ vulnerabilityCount: data.total,
337
+ criticalCount: data.critical,
338
+ highCount: data.high,
339
+ riskScore: data.critical * 15 + data.high * 10 + (data.total - data.critical - data.high) * 3,
340
+ }))
341
+ .sort((a, b) => b.riskScore - a.riskScore)
342
+ .slice(0, 10);
343
+ }
344
+ /**
345
+ * Generate executive summary
346
+ */
347
+ generateExecutiveSummary(metrics, topVulns) {
348
+ const { bySeverity, securityScore, riskLevel } = metrics;
349
+ let status;
350
+ let statusMessage;
351
+ if (riskLevel === 'critical') {
352
+ status = 'critical';
353
+ statusMessage = `Critical security issues detected. Immediate attention required.`;
354
+ }
355
+ else if (riskLevel === 'high') {
356
+ status = 'warning';
357
+ statusMessage = `High-priority security issues found. Prompt remediation recommended.`;
358
+ }
359
+ else if (riskLevel === 'medium') {
360
+ status = 'attention';
361
+ statusMessage = `Medium-priority security issues identified. Plan for remediation.`;
362
+ }
363
+ else if (riskLevel === 'low') {
364
+ status = 'good';
365
+ statusMessage = `Security posture is good with minor issues to address.`;
366
+ }
367
+ else {
368
+ status = 'excellent';
369
+ statusMessage = `Excellent security posture. Continue monitoring.`;
370
+ }
371
+ const highlights = [];
372
+ highlights.push(`Security Score: ${securityScore}/100`);
373
+ highlights.push(`Total Vulnerabilities: ${metrics.totalVulnerabilities}`);
374
+ if (bySeverity.critical > 0) {
375
+ highlights.push(`⚠️ ${bySeverity.critical} critical issue(s) require immediate attention`);
376
+ }
377
+ if (bySeverity.high > 0) {
378
+ highlights.push(`🔴 ${bySeverity.high} high severity issue(s) found`);
379
+ }
380
+ const keyFindings = [];
381
+ for (const vuln of topVulns.slice(0, 3)) {
382
+ keyFindings.push(`${vuln.type}: ${vuln.count} occurrence(s) (${vuln.severity})`);
383
+ }
384
+ const immediateActions = [];
385
+ if (bySeverity.critical > 0) {
386
+ immediateActions.push('Address all critical vulnerabilities immediately');
387
+ }
388
+ if (bySeverity.high > 0) {
389
+ immediateActions.push('Prioritize remediation of high-severity issues');
390
+ }
391
+ const topType = topVulns[0];
392
+ if (topType) {
393
+ immediateActions.push(`Focus on most common issue type: ${topType.type}`);
394
+ }
395
+ return {
396
+ status,
397
+ statusMessage,
398
+ highlights,
399
+ keyFindings,
400
+ immediateActions,
401
+ };
402
+ }
403
+ /**
404
+ * Generate scan summary
405
+ */
406
+ generateScanSummary() {
407
+ const totalFiles = new Set(this.vulnerabilities.map(v => v.location.file)).size;
408
+ const lastScan = this.scanResults.length > 0
409
+ ? this.scanResults[this.scanResults.length - 1].scannedAt
410
+ : new Date();
411
+ return {
412
+ totalScans: this.scanResults.length,
413
+ filesScanned: this.scanResults.reduce((sum, r) => sum + r.filesScanned, 0) || totalFiles,
414
+ lastScanDate: lastScan,
415
+ coverage: 100, // Placeholder
416
+ };
417
+ }
418
+ /**
419
+ * Calculate trends
420
+ */
421
+ calculateTrends() {
422
+ const dataPoints = this.trendHistory.slice(-30); // Last 30 data points
423
+ const firstScore = dataPoints[0]?.securityScore ?? 100;
424
+ const lastScore = dataPoints[dataPoints.length - 1]?.securityScore ?? 100;
425
+ const improvement = lastScore - firstScore;
426
+ let direction;
427
+ if (improvement > 5)
428
+ direction = 'improving';
429
+ else if (improvement < -5)
430
+ direction = 'degrading';
431
+ else
432
+ direction = 'stable';
433
+ return {
434
+ period: 'day',
435
+ dataPoints,
436
+ improvement,
437
+ direction,
438
+ };
439
+ }
440
+ /**
441
+ * Generate recommendations
442
+ */
443
+ generateRecommendations(metrics, topVulns) {
444
+ const recommendations = [];
445
+ // Critical/High severity recommendations
446
+ if (metrics.bySeverity.critical > 0) {
447
+ recommendations.push({
448
+ priority: 'critical',
449
+ category: 'Remediation',
450
+ title: 'Address Critical Vulnerabilities',
451
+ description: `${metrics.bySeverity.critical} critical vulnerabilities require immediate attention`,
452
+ impact: 'System compromise, data breach risk',
453
+ effort: 'high',
454
+ affectedCount: metrics.bySeverity.critical,
455
+ });
456
+ }
457
+ if (metrics.bySeverity.high > 0) {
458
+ recommendations.push({
459
+ priority: 'high',
460
+ category: 'Remediation',
461
+ title: 'Fix High-Severity Issues',
462
+ description: `${metrics.bySeverity.high} high-severity vulnerabilities should be addressed promptly`,
463
+ impact: 'Significant security exposure',
464
+ effort: 'medium',
465
+ affectedCount: metrics.bySeverity.high,
466
+ });
467
+ }
468
+ // Type-specific recommendations
469
+ for (const vuln of topVulns.slice(0, 3)) {
470
+ if (vuln.count >= 3) {
471
+ recommendations.push({
472
+ priority: this.severityToPriority(vuln.severity),
473
+ category: 'Pattern',
474
+ title: `Reduce ${vuln.type} Vulnerabilities`,
475
+ description: vuln.recommendation,
476
+ impact: `${vuln.count} occurrences across the codebase`,
477
+ effort: 'medium',
478
+ affectedCount: vuln.count,
479
+ });
480
+ }
481
+ }
482
+ // General recommendations
483
+ if (metrics.securityScore < 80) {
484
+ recommendations.push({
485
+ priority: 'medium',
486
+ category: 'Process',
487
+ title: 'Implement Security Code Review',
488
+ description: 'Establish mandatory security review for all code changes',
489
+ impact: 'Prevent introduction of new vulnerabilities',
490
+ effort: 'medium',
491
+ affectedCount: 0,
492
+ });
493
+ }
494
+ if (metrics.totalVulnerabilities > 20) {
495
+ recommendations.push({
496
+ priority: 'medium',
497
+ category: 'Process',
498
+ title: 'Security Sprint Planning',
499
+ description: 'Dedicate engineering time specifically for security remediation',
500
+ impact: 'Systematic reduction of vulnerability backlog',
501
+ effort: 'high',
502
+ affectedCount: metrics.totalVulnerabilities,
503
+ });
504
+ }
505
+ return recommendations.slice(0, 10);
506
+ }
507
+ /**
508
+ * Convert severity to numeric value
509
+ */
510
+ severityValue(severity) {
511
+ const values = {
512
+ critical: 4,
513
+ high: 3,
514
+ medium: 2,
515
+ low: 1,
516
+ info: 0,
517
+ };
518
+ return values[severity];
519
+ }
520
+ /**
521
+ * Convert severity to priority
522
+ */
523
+ severityToPriority(severity) {
524
+ const mapping = {
525
+ critical: 'critical',
526
+ high: 'high',
527
+ medium: 'medium',
528
+ low: 'low',
529
+ info: 'low',
530
+ };
531
+ return mapping[severity];
532
+ }
533
+ /**
534
+ * Export to HTML format
535
+ */
536
+ toHTML(report) {
537
+ const colors = this.config.branding.colors ?? {
538
+ critical: '#dc2626',
539
+ high: '#ea580c',
540
+ medium: '#ca8a04',
541
+ low: '#16a34a',
542
+ info: '#2563eb',
543
+ };
544
+ return `<!DOCTYPE html>
545
+ <html lang="en">
546
+ <head>
547
+ <meta charset="UTF-8">
548
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
549
+ <title>${this.config.branding.title ?? 'Security Dashboard'} - ${report.projectName}</title>
550
+ <style>
551
+ * { box-sizing: border-box; margin: 0; padding: 0; }
552
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f3f4f6; color: #1f2937; line-height: 1.5; }
553
+ .container { max-width: 1200px; margin: 0 auto; padding: 2rem; }
554
+ .header { background: #1f2937; color: white; padding: 2rem; margin-bottom: 2rem; border-radius: 8px; }
555
+ .header h1 { font-size: 1.5rem; }
556
+ .header p { color: #9ca3af; margin-top: 0.5rem; }
557
+ .card { background: white; border-radius: 8px; padding: 1.5rem; margin-bottom: 1rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
558
+ .card h2 { font-size: 1.125rem; margin-bottom: 1rem; color: #374151; }
559
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; }
560
+ .metric { text-align: center; padding: 1rem; }
561
+ .metric .value { font-size: 2rem; font-weight: bold; }
562
+ .metric .label { color: #6b7280; font-size: 0.875rem; }
563
+ .severity-critical { color: ${colors.critical}; }
564
+ .severity-high { color: ${colors.high}; }
565
+ .severity-medium { color: ${colors.medium}; }
566
+ .severity-low { color: ${colors.low}; }
567
+ .severity-info { color: ${colors.info}; }
568
+ .badge { display: inline-block; padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-weight: 600; }
569
+ .badge-critical { background: ${colors.critical}20; color: ${colors.critical}; }
570
+ .badge-high { background: ${colors.high}20; color: ${colors.high}; }
571
+ .badge-medium { background: ${colors.medium}20; color: ${colors.medium}; }
572
+ .badge-low { background: ${colors.low}20; color: ${colors.low}; }
573
+ .badge-info { background: ${colors.info}20; color: ${colors.info}; }
574
+ table { width: 100%; border-collapse: collapse; }
575
+ th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #e5e7eb; }
576
+ th { background: #f9fafb; font-weight: 600; }
577
+ .status-${report.summary.status} { border-left: 4px solid ${this.getStatusColor(report.summary.status, colors)}; }
578
+ .score-circle { width: 120px; height: 120px; border-radius: 50%; background: conic-gradient(#10b981 ${report.metrics.securityScore * 3.6}deg, #e5e7eb 0deg); display: flex; align-items: center; justify-content: center; margin: 0 auto; }
579
+ .score-inner { width: 100px; height: 100px; border-radius: 50%; background: white; display: flex; align-items: center; justify-content: center; flex-direction: column; }
580
+ .score-value { font-size: 2rem; font-weight: bold; }
581
+ .list { list-style: none; }
582
+ .list li { padding: 0.5rem 0; border-bottom: 1px solid #f3f4f6; }
583
+ .list li:last-child { border-bottom: none; }
584
+ </style>
585
+ </head>
586
+ <body>
587
+ <div class="container">
588
+ <div class="header">
589
+ <h1>${this.config.branding.title ?? 'Security Dashboard'}</h1>
590
+ <p>${report.projectName} - Generated: ${report.generatedAt.toISOString()}</p>
591
+ </div>
592
+
593
+ <div class="card status-${report.summary.status}">
594
+ <h2>Executive Summary</h2>
595
+ <p><strong>${report.summary.statusMessage}</strong></p>
596
+ <ul class="list" style="margin-top: 1rem;">
597
+ ${report.summary.highlights.map(h => `<li>${h}</li>`).join('')}
598
+ </ul>
599
+ </div>
600
+
601
+ <div class="grid">
602
+ <div class="card">
603
+ <h2>Security Score</h2>
604
+ <div class="score-circle">
605
+ <div class="score-inner">
606
+ <div class="score-value">${report.metrics.securityScore}</div>
607
+ <div class="label">/100</div>
608
+ </div>
609
+ </div>
610
+ </div>
611
+
612
+ <div class="card">
613
+ <h2>Vulnerabilities by Severity</h2>
614
+ <div class="metric">
615
+ <div class="value severity-critical">${report.metrics.bySeverity.critical}</div>
616
+ <div class="label">Critical</div>
617
+ </div>
618
+ <div class="metric">
619
+ <div class="value severity-high">${report.metrics.bySeverity.high}</div>
620
+ <div class="label">High</div>
621
+ </div>
622
+ <div class="metric">
623
+ <div class="value severity-medium">${report.metrics.bySeverity.medium}</div>
624
+ <div class="label">Medium</div>
625
+ </div>
626
+ <div class="metric">
627
+ <div class="value severity-low">${report.metrics.bySeverity.low}</div>
628
+ <div class="label">Low</div>
629
+ </div>
630
+ </div>
631
+ </div>
632
+
633
+ <div class="card">
634
+ <h2>Top Vulnerabilities</h2>
635
+ <table>
636
+ <thead>
637
+ <tr><th>Type</th><th>Severity</th><th>Count</th><th>Recommendation</th></tr>
638
+ </thead>
639
+ <tbody>
640
+ ${report.topVulnerabilities.map(v => `
641
+ <tr>
642
+ <td>${v.type}</td>
643
+ <td><span class="badge badge-${v.severity}">${v.severity.toUpperCase()}</span></td>
644
+ <td>${v.count}</td>
645
+ <td>${v.recommendation}</td>
646
+ </tr>
647
+ `).join('')}
648
+ </tbody>
649
+ </table>
650
+ </div>
651
+
652
+ <div class="card">
653
+ <h2>Component Risks</h2>
654
+ <table>
655
+ <thead>
656
+ <tr><th>Component</th><th>Vulnerabilities</th><th>Critical</th><th>High</th><th>Risk Score</th></tr>
657
+ </thead>
658
+ <tbody>
659
+ ${report.componentRisks.map(c => `
660
+ <tr>
661
+ <td><code>${c.component}</code></td>
662
+ <td>${c.vulnerabilityCount}</td>
663
+ <td class="severity-critical">${c.criticalCount}</td>
664
+ <td class="severity-high">${c.highCount}</td>
665
+ <td>${c.riskScore}</td>
666
+ </tr>
667
+ `).join('')}
668
+ </tbody>
669
+ </table>
670
+ </div>
671
+
672
+ ${report.recommendations ? `
673
+ <div class="card">
674
+ <h2>Recommendations</h2>
675
+ <ul class="list">
676
+ ${report.recommendations.map(r => `
677
+ <li>
678
+ <span class="badge badge-${r.priority}">${r.priority.toUpperCase()}</span>
679
+ <strong>${r.title}</strong>: ${r.description}
680
+ </li>
681
+ `).join('')}
682
+ </ul>
683
+ </div>
684
+ ` : ''}
685
+ </div>
686
+ </body>
687
+ </html>`;
688
+ }
689
+ /**
690
+ * Export to Markdown format
691
+ */
692
+ toMarkdown(report) {
693
+ return `# Security Dashboard - ${report.projectName}
694
+
695
+ Generated: ${report.generatedAt.toISOString()}
696
+
697
+ ## Executive Summary
698
+
699
+ **Status: ${report.summary.status.toUpperCase()}**
700
+
701
+ ${report.summary.statusMessage}
702
+
703
+ ### Highlights
704
+ ${report.summary.highlights.map(h => `- ${h}`).join('\n')}
705
+
706
+ ### Key Findings
707
+ ${report.summary.keyFindings.map(f => `- ${f}`).join('\n')}
708
+
709
+ ### Immediate Actions
710
+ ${report.summary.immediateActions.map(a => `- ${a}`).join('\n')}
711
+
712
+ ---
713
+
714
+ ## Security Metrics
715
+
716
+ | Metric | Value |
717
+ |--------|-------|
718
+ | Security Score | ${report.metrics.securityScore}/100 |
719
+ | Risk Level | ${report.metrics.riskLevel} |
720
+ | Total Vulnerabilities | ${report.metrics.totalVulnerabilities} |
721
+
722
+ ### By Severity
723
+
724
+ | Severity | Count |
725
+ |----------|-------|
726
+ | Critical | ${report.metrics.bySeverity.critical} |
727
+ | High | ${report.metrics.bySeverity.high} |
728
+ | Medium | ${report.metrics.bySeverity.medium} |
729
+ | Low | ${report.metrics.bySeverity.low} |
730
+ | Info | ${report.metrics.bySeverity.info} |
731
+
732
+ ---
733
+
734
+ ## Top Vulnerabilities
735
+
736
+ | Type | Severity | Count | Recommendation |
737
+ |------|----------|-------|----------------|
738
+ ${report.topVulnerabilities.map(v => `| ${v.type} | ${v.severity} | ${v.count} | ${v.recommendation} |`).join('\n')}
739
+
740
+ ---
741
+
742
+ ## Component Risks
743
+
744
+ | Component | Vulnerabilities | Critical | High | Risk Score |
745
+ |-----------|-----------------|----------|------|------------|
746
+ ${report.componentRisks.map(c => `| \`${c.component}\` | ${c.vulnerabilityCount} | ${c.criticalCount} | ${c.highCount} | ${c.riskScore} |`).join('\n')}
747
+
748
+ ---
749
+
750
+ ${report.recommendations ? `
751
+ ## Recommendations
752
+
753
+ ${report.recommendations.map(r => `
754
+ ### [${r.priority.toUpperCase()}] ${r.title}
755
+
756
+ - **Category:** ${r.category}
757
+ - **Description:** ${r.description}
758
+ - **Impact:** ${r.impact}
759
+ - **Effort:** ${r.effort}
760
+ - **Affected:** ${r.affectedCount} items
761
+ `).join('\n')}
762
+ ` : ''}
763
+
764
+ ---
765
+
766
+ ## Scan Summary
767
+
768
+ | Metric | Value |
769
+ |--------|-------|
770
+ | Total Scans | ${report.scanSummary.totalScans} |
771
+ | Files Scanned | ${report.scanSummary.filesScanned} |
772
+ | Last Scan | ${report.scanSummary.lastScanDate.toISOString()} |
773
+ | Coverage | ${report.scanSummary.coverage}% |
774
+ `;
775
+ }
776
+ /**
777
+ * Get status color
778
+ */
779
+ getStatusColor(status, colors) {
780
+ const mapping = {
781
+ critical: colors.critical ?? '#dc2626',
782
+ warning: colors.high ?? '#ea580c',
783
+ attention: colors.medium ?? '#ca8a04',
784
+ good: colors.low ?? '#16a34a',
785
+ excellent: colors.info ?? '#2563eb',
786
+ };
787
+ return mapping[status];
788
+ }
789
+ }
790
+ /**
791
+ * Create security dashboard instance
792
+ */
793
+ export function createSecurityDashboard(config) {
794
+ return new SecurityDashboard(config);
795
+ }
796
+ //# sourceMappingURL=security-dashboard.js.map