mcp-wordpress 2.2.0 → 2.3.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.
Files changed (36) hide show
  1. package/dist/security/AISecurityScanner.d.ts +175 -0
  2. package/dist/security/AISecurityScanner.d.ts.map +1 -0
  3. package/dist/security/AISecurityScanner.js +645 -0
  4. package/dist/security/AISecurityScanner.js.map +1 -0
  5. package/dist/security/AutomatedRemediation.d.ts +145 -0
  6. package/dist/security/AutomatedRemediation.d.ts.map +1 -0
  7. package/dist/security/AutomatedRemediation.js +535 -0
  8. package/dist/security/AutomatedRemediation.js.map +1 -0
  9. package/dist/security/SecurityCIPipeline.d.ts +213 -0
  10. package/dist/security/SecurityCIPipeline.d.ts.map +1 -0
  11. package/dist/security/SecurityCIPipeline.js +684 -0
  12. package/dist/security/SecurityCIPipeline.js.map +1 -0
  13. package/dist/security/SecurityConfigManager.d.ts +294 -0
  14. package/dist/security/SecurityConfigManager.d.ts.map +1 -0
  15. package/dist/security/SecurityConfigManager.js +553 -0
  16. package/dist/security/SecurityConfigManager.js.map +1 -0
  17. package/dist/security/SecurityMonitoring.d.ts +245 -0
  18. package/dist/security/SecurityMonitoring.d.ts.map +1 -0
  19. package/dist/security/SecurityMonitoring.js +596 -0
  20. package/dist/security/SecurityMonitoring.js.map +1 -0
  21. package/dist/security/SecurityReviewer.d.ts +168 -0
  22. package/dist/security/SecurityReviewer.d.ts.map +1 -0
  23. package/dist/security/SecurityReviewer.js +683 -0
  24. package/dist/security/SecurityReviewer.js.map +1 -0
  25. package/dist/security/index.d.ts +182 -0
  26. package/dist/security/index.d.ts.map +1 -0
  27. package/dist/security/index.js +189 -0
  28. package/dist/security/index.js.map +1 -0
  29. package/package.json +8 -3
  30. package/src/security/AISecurityScanner.ts +780 -0
  31. package/src/security/AutomatedRemediation.ts +665 -0
  32. package/src/security/SecurityCIPipeline.ts +969 -0
  33. package/src/security/SecurityConfigManager.ts +829 -0
  34. package/src/security/SecurityMonitoring.ts +841 -0
  35. package/src/security/SecurityReviewer.ts +855 -0
  36. package/src/security/index.ts +249 -0
@@ -0,0 +1,969 @@
1
+ /**
2
+ * Security CI/CD Pipeline Integration
3
+ * Provides security checks and gates for continuous integration and deployment
4
+ */
5
+
6
+ import { AISecurityScanner } from "./AISecurityScanner";
7
+ import { AutomatedRemediation } from "./AutomatedRemediation";
8
+ import { SecurityReviewer } from "./SecurityReviewer";
9
+ import { SecurityConfigManager } from "./SecurityConfigManager";
10
+ import { SecurityUtils } from "./SecurityConfig";
11
+ import { SecurityValidationError } from "./InputValidator";
12
+
13
+ interface SecurityGate {
14
+ id: string;
15
+ name: string;
16
+ stage: "pre-commit" | "pre-build" | "pre-deploy" | "post-deploy";
17
+ enabled: boolean;
18
+ blocking: boolean;
19
+ checks: SecurityCheck[];
20
+ thresholds: {
21
+ maxCritical: number;
22
+ maxHigh: number;
23
+ maxMedium: number;
24
+ minSecurityScore: number;
25
+ };
26
+ exceptions: string[];
27
+ }
28
+
29
+ interface SecurityCheck {
30
+ id: string;
31
+ name: string;
32
+ type: "scan" | "review" | "dependency" | "configuration" | "secrets" | "compliance";
33
+ enabled: boolean;
34
+ timeout: number;
35
+ retries: number;
36
+ parameters: Record<string, any>;
37
+ }
38
+
39
+ export interface PipelineSecurityReport {
40
+ reportId: string;
41
+ timestamp: Date;
42
+ stage: string;
43
+ status: "passed" | "failed" | "warning";
44
+ duration: number;
45
+ gates: GateResult[];
46
+ summary: {
47
+ totalIssues: number;
48
+ criticalIssues: number;
49
+ highIssues: number;
50
+ mediumIssues: number;
51
+ lowIssues: number;
52
+ securityScore: number;
53
+ compliance: boolean;
54
+ };
55
+ recommendations: string[];
56
+ artifacts: string[];
57
+ }
58
+
59
+ interface GateResult {
60
+ gateId: string;
61
+ gateName: string;
62
+ status: "passed" | "failed" | "warning" | "skipped";
63
+ duration: number;
64
+ checks: CheckResult[];
65
+ blocking: boolean;
66
+ message: string;
67
+ }
68
+
69
+ interface CheckResult {
70
+ checkId: string;
71
+ checkName: string;
72
+ status: "passed" | "failed" | "warning" | "error";
73
+ duration: number;
74
+ findings: SecurityFinding[];
75
+ details: string;
76
+ score: number;
77
+ }
78
+
79
+ interface SecurityFinding {
80
+ id: string;
81
+ severity: "critical" | "high" | "medium" | "low" | "info";
82
+ type: string;
83
+ description: string;
84
+ file?: string | undefined;
85
+ line?: number | undefined;
86
+ remediation?: string | undefined;
87
+ }
88
+
89
+ interface PipelineContext {
90
+ repositoryUrl: string;
91
+ branch: string;
92
+ commit: string;
93
+ author: string;
94
+ pullRequest?: {
95
+ id: string;
96
+ title: string;
97
+ source: string;
98
+ target: string;
99
+ };
100
+ environment: string;
101
+ buildNumber: string;
102
+ artifacts: string[];
103
+ }
104
+
105
+ /**
106
+ * Security CI/CD Pipeline Manager
107
+ */
108
+ export class SecurityCIPipeline {
109
+ private scanner: AISecurityScanner;
110
+ private remediation: AutomatedRemediation;
111
+ private reviewer: SecurityReviewer;
112
+ private configManager: SecurityConfigManager;
113
+ private gates: Map<string, SecurityGate> = new Map();
114
+ private reports: PipelineSecurityReport[] = [];
115
+
116
+ constructor() {
117
+ this.scanner = new AISecurityScanner();
118
+ this.remediation = new AutomatedRemediation();
119
+ this.reviewer = new SecurityReviewer();
120
+ this.configManager = new SecurityConfigManager();
121
+
122
+ this.initializeDefaultGates();
123
+ }
124
+
125
+ /**
126
+ * Initialize the security pipeline
127
+ */
128
+ async initialize(): Promise<void> {
129
+ console.log("[Security Pipeline] Initializing security CI/CD pipeline");
130
+ await this.configManager.initialize();
131
+ console.log("[Security Pipeline] Security pipeline ready");
132
+ }
133
+
134
+ /**
135
+ * Execute security gates for a pipeline stage
136
+ */
137
+ async executeSecurityGates(
138
+ stage: SecurityGate["stage"],
139
+ context: PipelineContext,
140
+ options: {
141
+ skipNonBlocking?: boolean;
142
+ continueOnFailure?: boolean;
143
+ dryRun?: boolean;
144
+ } = {},
145
+ ): Promise<PipelineSecurityReport> {
146
+ const reportId = SecurityUtils.generateSecureToken(16);
147
+ const startTime = Date.now();
148
+
149
+ console.log(`[Security Pipeline] Executing ${stage} security gates for ${context.branch}@${context.commit}`);
150
+
151
+ const applicableGates = Array.from(this.gates.values()).filter((gate) => gate.stage === stage && gate.enabled);
152
+
153
+ if (applicableGates.length === 0) {
154
+ console.log(`[Security Pipeline] No security gates configured for stage: ${stage}`);
155
+ return this.createEmptyReport(reportId, stage, startTime);
156
+ }
157
+
158
+ const gateResults: GateResult[] = [];
159
+ let overallStatus: "passed" | "failed" | "warning" = "passed";
160
+
161
+ for (const gate of applicableGates) {
162
+ console.log(`[Security Pipeline] Executing gate: ${gate.name}`);
163
+
164
+ try {
165
+ const gateResult = await this.executeSecurityGate(gate, context, options);
166
+ gateResults.push(gateResult);
167
+
168
+ // Update overall status
169
+ if (gateResult.status === "failed" && gate.blocking) {
170
+ overallStatus = "failed";
171
+ } else if (gateResult.status === "warning" && overallStatus === "passed") {
172
+ overallStatus = "warning";
173
+ }
174
+
175
+ // Stop on blocking failure unless continuing on failure
176
+ if (gateResult.status === "failed" && gate.blocking && !options.continueOnFailure) {
177
+ console.log(`[Security Pipeline] Stopping pipeline due to blocking gate failure: ${gate.name}`);
178
+ break;
179
+ }
180
+ } catch (error) {
181
+ console.error(`[Security Pipeline] Gate execution error: ${gate.name}`, error);
182
+
183
+ const errorResult: GateResult = {
184
+ gateId: gate.id,
185
+ gateName: gate.name,
186
+ status: "failed",
187
+ duration: Date.now() - startTime,
188
+ checks: [],
189
+ blocking: gate.blocking,
190
+ message: `Gate execution failed: ${error instanceof Error ? error.message : String(error)}`,
191
+ };
192
+
193
+ gateResults.push(errorResult);
194
+
195
+ if (gate.blocking && !options.continueOnFailure) {
196
+ overallStatus = "failed";
197
+ break;
198
+ }
199
+ }
200
+ }
201
+
202
+ const report = this.generatePipelineReport(reportId, stage, startTime, overallStatus, gateResults, context);
203
+
204
+ this.reports.push(report);
205
+
206
+ console.log(`[Security Pipeline] ${stage} gates completed with status: ${overallStatus}`);
207
+
208
+ return report;
209
+ }
210
+
211
+ /**
212
+ * Execute a single security gate
213
+ */
214
+ private async executeSecurityGate(
215
+ gate: SecurityGate,
216
+ context: PipelineContext,
217
+ options: { dryRun?: boolean } = {},
218
+ ): Promise<GateResult> {
219
+ const startTime = Date.now();
220
+ const checkResults: CheckResult[] = [];
221
+
222
+ for (const check of gate.checks) {
223
+ if (!check.enabled) {
224
+ continue;
225
+ }
226
+
227
+ console.log(`[Security Pipeline] Running check: ${check.name}`);
228
+
229
+ try {
230
+ const checkResult = await this.executeSecurityCheck(check, context, options);
231
+ checkResults.push(checkResult);
232
+ } catch (error) {
233
+ console.error(`[Security Pipeline] Check execution error: ${check.name}`, error);
234
+
235
+ checkResults.push({
236
+ checkId: check.id,
237
+ checkName: check.name,
238
+ status: "error",
239
+ duration: Date.now() - startTime,
240
+ findings: [],
241
+ details: `Check execution failed: ${error instanceof Error ? error.message : String(error)}`,
242
+ score: 0,
243
+ });
244
+ }
245
+ }
246
+
247
+ // Evaluate gate status based on check results and thresholds
248
+ const gateStatus = this.evaluateGateStatus(gate, checkResults);
249
+
250
+ return {
251
+ gateId: gate.id,
252
+ gateName: gate.name,
253
+ status: gateStatus.status,
254
+ duration: Date.now() - startTime,
255
+ checks: checkResults,
256
+ blocking: gate.blocking,
257
+ message: gateStatus.message,
258
+ };
259
+ }
260
+
261
+ /**
262
+ * Execute a single security check
263
+ */
264
+ private async executeSecurityCheck(
265
+ check: SecurityCheck,
266
+ context: PipelineContext,
267
+ options: { dryRun?: boolean } = {},
268
+ ): Promise<CheckResult> {
269
+ const startTime = Date.now();
270
+ const findings: SecurityFinding[] = [];
271
+ let score = 100;
272
+ let details = "";
273
+
274
+ if (options.dryRun) {
275
+ return {
276
+ checkId: check.id,
277
+ checkName: check.name,
278
+ status: "passed",
279
+ duration: Date.now() - startTime,
280
+ findings: [],
281
+ details: "Dry run - no actual checks performed",
282
+ score: 100,
283
+ };
284
+ }
285
+
286
+ try {
287
+ switch (check.type) {
288
+ case "scan":
289
+ const scanResults = await this.executeScanCheck(check, context);
290
+ findings.push(...scanResults.findings);
291
+ score = scanResults.score;
292
+ details = scanResults.details;
293
+ break;
294
+
295
+ case "review":
296
+ const reviewResults = await this.executeReviewCheck(check, context);
297
+ findings.push(...reviewResults.findings);
298
+ score = reviewResults.score;
299
+ details = reviewResults.details;
300
+ break;
301
+
302
+ case "dependency":
303
+ const depResults = await this.executeDependencyCheck(check, context);
304
+ findings.push(...depResults.findings);
305
+ score = depResults.score;
306
+ details = depResults.details;
307
+ break;
308
+
309
+ case "configuration":
310
+ const configResults = await this.executeConfigurationCheck(check, context);
311
+ findings.push(...configResults.findings);
312
+ score = configResults.score;
313
+ details = configResults.details;
314
+ break;
315
+
316
+ case "secrets":
317
+ const secretResults = await this.executeSecretsCheck(check, context);
318
+ findings.push(...secretResults.findings);
319
+ score = secretResults.score;
320
+ details = secretResults.details;
321
+ break;
322
+
323
+ case "compliance":
324
+ const complianceResults = await this.executeComplianceCheck(check, context);
325
+ findings.push(...complianceResults.findings);
326
+ score = complianceResults.score;
327
+ details = complianceResults.details;
328
+ break;
329
+
330
+ default:
331
+ throw new Error(`Unknown check type: ${check.type}`);
332
+ }
333
+
334
+ // Determine check status based on findings
335
+ const criticalCount = findings.filter((f) => f.severity === "critical").length;
336
+ const highCount = findings.filter((f) => f.severity === "high").length;
337
+
338
+ let status: CheckResult["status"];
339
+ if (criticalCount > 0) {
340
+ status = "failed";
341
+ } else if (highCount > 0) {
342
+ status = "warning";
343
+ } else {
344
+ status = "passed";
345
+ }
346
+
347
+ return {
348
+ checkId: check.id,
349
+ checkName: check.name,
350
+ status,
351
+ duration: Date.now() - startTime,
352
+ findings,
353
+ details,
354
+ score,
355
+ };
356
+ } catch (error) {
357
+ throw new SecurityValidationError(`Check ${check.name} failed`, [{ message: String(error) }]);
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Execute security scan check
363
+ */
364
+ private async executeScanCheck(
365
+ check: SecurityCheck,
366
+ context: PipelineContext,
367
+ ): Promise<{
368
+ findings: SecurityFinding[];
369
+ score: number;
370
+ details: string;
371
+ }> {
372
+ const scanResult = await this.scanner.performScan({
373
+ targets: check.parameters.targets || ["src/"],
374
+ depth: check.parameters.depth || "deep",
375
+ includeRuntime: check.parameters.includeRuntime || false,
376
+ includeFileSystem: check.parameters.includeFileSystem || true,
377
+ });
378
+
379
+ const findings: SecurityFinding[] = scanResult.vulnerabilities.map((vuln) => ({
380
+ id: vuln.id,
381
+ severity: vuln.severity,
382
+ type: vuln.type,
383
+ description: vuln.description,
384
+ file: vuln.location.file,
385
+ line: vuln.location.line,
386
+ remediation: vuln.remediation.suggested,
387
+ }));
388
+
389
+ const score = Math.max(
390
+ 0,
391
+ 100 - (scanResult.summary.critical * 10 + scanResult.summary.high * 5 + scanResult.summary.medium * 2),
392
+ );
393
+
394
+ return {
395
+ findings,
396
+ score,
397
+ details: `Scanned codebase: ${scanResult.summary.total} vulnerabilities found`,
398
+ };
399
+ }
400
+
401
+ /**
402
+ * Execute code review check
403
+ */
404
+ private async executeReviewCheck(
405
+ check: SecurityCheck,
406
+ context: PipelineContext,
407
+ ): Promise<{
408
+ findings: SecurityFinding[];
409
+ score: number;
410
+ details: string;
411
+ }> {
412
+ const reviewResults = await this.reviewer.reviewDirectory("src/", {
413
+ recursive: true,
414
+ rules: check.parameters.rules,
415
+ excludeRules: check.parameters.excludeRules,
416
+ aiAnalysis: check.parameters.aiAnalysis || false,
417
+ });
418
+
419
+ const allFindings: SecurityFinding[] = [];
420
+ let totalScore = 0;
421
+
422
+ for (const result of reviewResults) {
423
+ const resultFindings = result.findings.map((finding) => ({
424
+ id: finding.id,
425
+ severity: finding.severity,
426
+ type: finding.category,
427
+ description: finding.message,
428
+ file: result.file,
429
+ line: finding.line,
430
+ remediation: finding.recommendation,
431
+ }));
432
+
433
+ allFindings.push(...resultFindings);
434
+ totalScore += this.calculateFileScore(result.findings);
435
+ }
436
+
437
+ const averageScore = reviewResults.length > 0 ? totalScore / reviewResults.length : 100;
438
+
439
+ return {
440
+ findings: allFindings,
441
+ score: averageScore,
442
+ details: `Reviewed ${reviewResults.length} files: ${allFindings.length} security issues found`,
443
+ };
444
+ }
445
+
446
+ /**
447
+ * Execute dependency check
448
+ */
449
+ private async executeDependencyCheck(
450
+ check: SecurityCheck,
451
+ context: PipelineContext,
452
+ ): Promise<{
453
+ findings: SecurityFinding[];
454
+ score: number;
455
+ details: string;
456
+ }> {
457
+ // This would integrate with npm audit, Snyk, or similar tools
458
+ console.log("[Security Pipeline] Dependency check - integration with external tools required");
459
+
460
+ return {
461
+ findings: [],
462
+ score: 100,
463
+ details: "Dependency check completed - no vulnerabilities found",
464
+ };
465
+ }
466
+
467
+ /**
468
+ * Execute configuration check
469
+ */
470
+ private async executeConfigurationCheck(
471
+ check: SecurityCheck,
472
+ context: PipelineContext,
473
+ ): Promise<{
474
+ findings: SecurityFinding[];
475
+ score: number;
476
+ details: string;
477
+ }> {
478
+ const compliance = await this.configManager.validateCompliance(context.environment);
479
+
480
+ const findings: SecurityFinding[] = compliance.violations.map((violation, index) => ({
481
+ id: `config-${index}`,
482
+ severity: "medium" as const,
483
+ type: "Configuration",
484
+ description: violation,
485
+ remediation: "Review security configuration",
486
+ }));
487
+
488
+ const score = compliance.compliant ? 100 : Math.max(0, 100 - compliance.violations.length * 10);
489
+
490
+ return {
491
+ findings,
492
+ score,
493
+ details: `Configuration compliance: ${compliance.compliant ? "compliant" : "non-compliant"}`,
494
+ };
495
+ }
496
+
497
+ /**
498
+ * Execute secrets check
499
+ */
500
+ private async executeSecretsCheck(
501
+ check: SecurityCheck,
502
+ context: PipelineContext,
503
+ ): Promise<{
504
+ findings: SecurityFinding[];
505
+ score: number;
506
+ details: string;
507
+ }> {
508
+ // This would integrate with tools like TruffleHog, GitLeaks, etc.
509
+ console.log("[Security Pipeline] Secrets check - integration with secret scanning tools required");
510
+
511
+ return {
512
+ findings: [],
513
+ score: 100,
514
+ details: "Secrets scan completed - no exposed secrets found",
515
+ };
516
+ }
517
+
518
+ /**
519
+ * Execute compliance check
520
+ */
521
+ private async executeComplianceCheck(
522
+ check: SecurityCheck,
523
+ context: PipelineContext,
524
+ ): Promise<{
525
+ findings: SecurityFinding[];
526
+ score: number;
527
+ details: string;
528
+ }> {
529
+ const frameworks = check.parameters.frameworks || ["OWASP", "CWE"];
530
+ const findings: SecurityFinding[] = [];
531
+
532
+ // Check for compliance with security frameworks
533
+ for (const framework of frameworks) {
534
+ // This would integrate with compliance checking tools
535
+ console.log(`[Security Pipeline] Checking ${framework} compliance`);
536
+ }
537
+
538
+ return {
539
+ findings,
540
+ score: 100,
541
+ details: `Compliance check completed for frameworks: ${frameworks.join(", ")}`,
542
+ };
543
+ }
544
+
545
+ /**
546
+ * Calculate security score for file findings
547
+ */
548
+ private calculateFileScore(findings: any[]): number {
549
+ const severityWeights = { critical: 20, high: 10, medium: 5, low: 2, info: 1 };
550
+
551
+ const penalty = findings.reduce((sum, finding) => {
552
+ return sum + (severityWeights[finding.severity as keyof typeof severityWeights] || 0);
553
+ }, 0);
554
+
555
+ return Math.max(0, 100 - penalty);
556
+ }
557
+
558
+ /**
559
+ * Evaluate gate status based on check results and thresholds
560
+ */
561
+ private evaluateGateStatus(
562
+ gate: SecurityGate,
563
+ checkResults: CheckResult[],
564
+ ): {
565
+ status: "passed" | "failed" | "warning";
566
+ message: string;
567
+ } {
568
+ const allFindings = checkResults.flatMap((result) => result.findings);
569
+
570
+ const criticalCount = allFindings.filter((f) => f.severity === "critical").length;
571
+ const highCount = allFindings.filter((f) => f.severity === "high").length;
572
+ const mediumCount = allFindings.filter((f) => f.severity === "medium").length;
573
+
574
+ const averageScore =
575
+ checkResults.length > 0 ? checkResults.reduce((sum, result) => sum + result.score, 0) / checkResults.length : 100;
576
+
577
+ // Check thresholds
578
+ if (criticalCount > gate.thresholds.maxCritical) {
579
+ return {
580
+ status: "failed",
581
+ message: `Critical vulnerabilities (${criticalCount}) exceed threshold (${gate.thresholds.maxCritical})`,
582
+ };
583
+ }
584
+
585
+ if (highCount > gate.thresholds.maxHigh) {
586
+ return {
587
+ status: "failed",
588
+ message: `High-severity vulnerabilities (${highCount}) exceed threshold (${gate.thresholds.maxHigh})`,
589
+ };
590
+ }
591
+
592
+ if (averageScore < gate.thresholds.minSecurityScore) {
593
+ return {
594
+ status: "failed",
595
+ message: `Security score (${averageScore.toFixed(1)}) below threshold (${gate.thresholds.minSecurityScore})`,
596
+ };
597
+ }
598
+
599
+ if (mediumCount > gate.thresholds.maxMedium) {
600
+ return {
601
+ status: "warning",
602
+ message: `Medium-severity vulnerabilities (${mediumCount}) exceed threshold (${gate.thresholds.maxMedium})`,
603
+ };
604
+ }
605
+
606
+ return {
607
+ status: "passed",
608
+ message: "All security checks passed",
609
+ };
610
+ }
611
+
612
+ /**
613
+ * Generate pipeline security report
614
+ */
615
+ private generatePipelineReport(
616
+ reportId: string,
617
+ stage: string,
618
+ startTime: number,
619
+ status: "passed" | "failed" | "warning",
620
+ gateResults: GateResult[],
621
+ context: PipelineContext,
622
+ ): PipelineSecurityReport {
623
+ const allFindings = gateResults.flatMap((gate) => gate.checks.flatMap((check) => check.findings));
624
+
625
+ const summary = {
626
+ totalIssues: allFindings.length,
627
+ criticalIssues: allFindings.filter((f) => f.severity === "critical").length,
628
+ highIssues: allFindings.filter((f) => f.severity === "high").length,
629
+ mediumIssues: allFindings.filter((f) => f.severity === "medium").length,
630
+ lowIssues: allFindings.filter((f) => f.severity === "low").length,
631
+ securityScore: this.calculateOverallSecurityScore(gateResults),
632
+ compliance: status === "passed",
633
+ };
634
+
635
+ const recommendations = this.generateRecommendations(gateResults, summary);
636
+
637
+ return {
638
+ reportId,
639
+ timestamp: new Date(),
640
+ stage,
641
+ status,
642
+ duration: Date.now() - startTime,
643
+ gates: gateResults,
644
+ summary,
645
+ recommendations,
646
+ artifacts: this.generateArtifacts(reportId, gateResults),
647
+ };
648
+ }
649
+
650
+ /**
651
+ * Calculate overall security score
652
+ */
653
+ private calculateOverallSecurityScore(gateResults: GateResult[]): number {
654
+ const allChecks = gateResults.flatMap((gate) => gate.checks);
655
+
656
+ if (allChecks.length === 0) {
657
+ return 100;
658
+ }
659
+
660
+ const totalScore = allChecks.reduce((sum, check) => sum + check.score, 0);
661
+ return totalScore / allChecks.length;
662
+ }
663
+
664
+ /**
665
+ * Generate recommendations based on results
666
+ */
667
+ private generateRecommendations(gateResults: GateResult[], summary: any): string[] {
668
+ const recommendations: string[] = [];
669
+
670
+ if (summary.criticalIssues > 0) {
671
+ recommendations.push("Address critical security vulnerabilities immediately before deployment");
672
+ }
673
+
674
+ if (summary.highIssues > 5) {
675
+ recommendations.push("Review and remediate high-severity security issues");
676
+ }
677
+
678
+ if (summary.securityScore < 80) {
679
+ recommendations.push("Improve overall security posture through code review and security training");
680
+ }
681
+
682
+ const failedGates = gateResults.filter((gate) => gate.status === "failed");
683
+ if (failedGates.length > 0) {
684
+ recommendations.push(`Review failed security gates: ${failedGates.map((g) => g.gateName).join(", ")}`);
685
+ }
686
+
687
+ return recommendations;
688
+ }
689
+
690
+ /**
691
+ * Generate artifacts for the security report
692
+ */
693
+ private generateArtifacts(reportId: string, gateResults: GateResult[]): string[] {
694
+ // In a real implementation, this would generate SARIF files, security reports, etc.
695
+ return [`security-report-${reportId}.json`, `security-findings-${reportId}.sarif`];
696
+ }
697
+
698
+ /**
699
+ * Create empty report for stages with no gates
700
+ */
701
+ private createEmptyReport(reportId: string, stage: string, startTime: number): PipelineSecurityReport {
702
+ return {
703
+ reportId,
704
+ timestamp: new Date(),
705
+ stage,
706
+ status: "passed",
707
+ duration: Date.now() - startTime,
708
+ gates: [],
709
+ summary: {
710
+ totalIssues: 0,
711
+ criticalIssues: 0,
712
+ highIssues: 0,
713
+ mediumIssues: 0,
714
+ lowIssues: 0,
715
+ securityScore: 100,
716
+ compliance: true,
717
+ },
718
+ recommendations: [],
719
+ artifacts: [],
720
+ };
721
+ }
722
+
723
+ /**
724
+ * Initialize default security gates
725
+ */
726
+ private initializeDefaultGates(): void {
727
+ // Pre-commit gate
728
+ this.gates.set("pre-commit", {
729
+ id: "pre-commit",
730
+ name: "Pre-commit Security Gate",
731
+ stage: "pre-commit",
732
+ enabled: true,
733
+ blocking: true,
734
+ checks: [
735
+ {
736
+ id: "secrets-scan",
737
+ name: "Secrets Scan",
738
+ type: "secrets",
739
+ enabled: true,
740
+ timeout: 60000,
741
+ retries: 1,
742
+ parameters: {},
743
+ },
744
+ {
745
+ id: "basic-review",
746
+ name: "Basic Security Review",
747
+ type: "review",
748
+ enabled: true,
749
+ timeout: 120000,
750
+ retries: 1,
751
+ parameters: { rules: ["auth-001", "input-001", "crypto-001"] },
752
+ },
753
+ ],
754
+ thresholds: {
755
+ maxCritical: 0,
756
+ maxHigh: 2,
757
+ maxMedium: 10,
758
+ minSecurityScore: 80,
759
+ },
760
+ exceptions: [],
761
+ });
762
+
763
+ // Pre-build gate
764
+ this.gates.set("pre-build", {
765
+ id: "pre-build",
766
+ name: "Pre-build Security Gate",
767
+ stage: "pre-build",
768
+ enabled: true,
769
+ blocking: true,
770
+ checks: [
771
+ {
772
+ id: "full-scan",
773
+ name: "Full Security Scan",
774
+ type: "scan",
775
+ enabled: true,
776
+ timeout: 300000,
777
+ retries: 1,
778
+ parameters: { depth: "comprehensive", includeRuntime: true },
779
+ },
780
+ {
781
+ id: "dependency-check",
782
+ name: "Dependency Vulnerability Check",
783
+ type: "dependency",
784
+ enabled: true,
785
+ timeout: 180000,
786
+ retries: 2,
787
+ parameters: {},
788
+ },
789
+ {
790
+ id: "config-review",
791
+ name: "Configuration Review",
792
+ type: "configuration",
793
+ enabled: true,
794
+ timeout: 60000,
795
+ retries: 1,
796
+ parameters: {},
797
+ },
798
+ ],
799
+ thresholds: {
800
+ maxCritical: 0,
801
+ maxHigh: 5,
802
+ maxMedium: 20,
803
+ minSecurityScore: 75,
804
+ },
805
+ exceptions: [],
806
+ });
807
+
808
+ // Pre-deploy gate
809
+ this.gates.set("pre-deploy", {
810
+ id: "pre-deploy",
811
+ name: "Pre-deployment Security Gate",
812
+ stage: "pre-deploy",
813
+ enabled: true,
814
+ blocking: true,
815
+ checks: [
816
+ {
817
+ id: "compliance-check",
818
+ name: "Compliance Validation",
819
+ type: "compliance",
820
+ enabled: true,
821
+ timeout: 120000,
822
+ retries: 1,
823
+ parameters: { frameworks: ["OWASP", "CWE"] },
824
+ },
825
+ {
826
+ id: "final-review",
827
+ name: "Final Security Review",
828
+ type: "review",
829
+ enabled: true,
830
+ timeout: 240000,
831
+ retries: 1,
832
+ parameters: { aiAnalysis: true },
833
+ },
834
+ ],
835
+ thresholds: {
836
+ maxCritical: 0,
837
+ maxHigh: 1,
838
+ maxMedium: 5,
839
+ minSecurityScore: 85,
840
+ },
841
+ exceptions: [],
842
+ });
843
+ }
844
+
845
+ /**
846
+ * Get security gate configuration
847
+ */
848
+ getSecurityGate(gateId: string): SecurityGate | null {
849
+ return this.gates.get(gateId) || null;
850
+ }
851
+
852
+ /**
853
+ * Update security gate configuration
854
+ */
855
+ updateSecurityGate(gateId: string, updates: Partial<SecurityGate>): boolean {
856
+ const gate = this.gates.get(gateId);
857
+ if (!gate) {
858
+ return false;
859
+ }
860
+
861
+ const updatedGate = { ...gate, ...updates, id: gateId };
862
+ this.gates.set(gateId, updatedGate);
863
+
864
+ console.log(`[Security Pipeline] Updated security gate: ${updatedGate.name}`);
865
+ return true;
866
+ }
867
+
868
+ /**
869
+ * Get pipeline reports
870
+ */
871
+ getReports(
872
+ options: {
873
+ stage?: string;
874
+ status?: string;
875
+ since?: Date;
876
+ limit?: number;
877
+ } = {},
878
+ ): PipelineSecurityReport[] {
879
+ let reports = [...this.reports];
880
+
881
+ if (options.stage) {
882
+ reports = reports.filter((r) => r.stage === options.stage);
883
+ }
884
+
885
+ if (options.status) {
886
+ reports = reports.filter((r) => r.status === options.status);
887
+ }
888
+
889
+ if (options.since) {
890
+ reports = reports.filter((r) => r.timestamp >= options.since!);
891
+ }
892
+
893
+ // Sort by timestamp (newest first)
894
+ reports.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
895
+
896
+ if (options.limit) {
897
+ reports = reports.slice(0, options.limit);
898
+ }
899
+
900
+ return reports;
901
+ }
902
+
903
+ /**
904
+ * Get pipeline statistics
905
+ */
906
+ getStatistics(): {
907
+ totalReports: number;
908
+ passRate: number;
909
+ averageSecurityScore: number;
910
+ mostCommonIssues: { type: string; count: number }[];
911
+ gatePerformance: { gateId: string; successRate: number; averageDuration: number }[];
912
+ } {
913
+ const totalReports = this.reports.length;
914
+ const passedReports = this.reports.filter((r) => r.status === "passed").length;
915
+ const passRate = totalReports > 0 ? passedReports / totalReports : 1;
916
+
917
+ const averageSecurityScore =
918
+ totalReports > 0 ? this.reports.reduce((sum, r) => sum + r.summary.securityScore, 0) / totalReports : 100;
919
+
920
+ // Count issue types
921
+ const issueTypes: Record<string, number> = {};
922
+ this.reports.forEach((report) => {
923
+ report.gates.forEach((gate) => {
924
+ gate.checks.forEach((check) => {
925
+ check.findings.forEach((finding) => {
926
+ issueTypes[finding.type] = (issueTypes[finding.type] || 0) + 1;
927
+ });
928
+ });
929
+ });
930
+ });
931
+
932
+ const mostCommonIssues = Object.entries(issueTypes)
933
+ .map(([type, count]) => ({ type, count }))
934
+ .sort((a, b) => b.count - a.count)
935
+ .slice(0, 5);
936
+
937
+ // Calculate gate performance
938
+ const gateStats: Record<string, { total: number; passed: number; totalDuration: number }> = {};
939
+
940
+ this.reports.forEach((report) => {
941
+ report.gates.forEach((gate) => {
942
+ if (!gateStats[gate.gateId]) {
943
+ gateStats[gate.gateId] = { total: 0, passed: 0, totalDuration: 0 };
944
+ }
945
+
946
+ gateStats[gate.gateId].total++;
947
+ gateStats[gate.gateId].totalDuration += gate.duration;
948
+
949
+ if (gate.status === "passed") {
950
+ gateStats[gate.gateId].passed++;
951
+ }
952
+ });
953
+ });
954
+
955
+ const gatePerformance = Object.entries(gateStats).map(([gateId, stats]) => ({
956
+ gateId,
957
+ successRate: stats.total > 0 ? stats.passed / stats.total : 0,
958
+ averageDuration: stats.total > 0 ? stats.totalDuration / stats.total : 0,
959
+ }));
960
+
961
+ return {
962
+ totalReports,
963
+ passRate,
964
+ averageSecurityScore,
965
+ mostCommonIssues,
966
+ gatePerformance,
967
+ };
968
+ }
969
+ }