mcp-wordpress 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +503 -0
- package/dist/client/api.d.ts +90 -0
- package/dist/client/api.d.ts.map +1 -1
- package/dist/client/api.js +90 -0
- package/dist/client/api.js.map +1 -1
- package/dist/security/AISecurityScanner.d.ts +175 -0
- package/dist/security/AISecurityScanner.d.ts.map +1 -0
- package/dist/security/AISecurityScanner.js +645 -0
- package/dist/security/AISecurityScanner.js.map +1 -0
- package/dist/security/AutomatedRemediation.d.ts +145 -0
- package/dist/security/AutomatedRemediation.d.ts.map +1 -0
- package/dist/security/AutomatedRemediation.js +535 -0
- package/dist/security/AutomatedRemediation.js.map +1 -0
- package/dist/security/SecurityCIPipeline.d.ts +213 -0
- package/dist/security/SecurityCIPipeline.d.ts.map +1 -0
- package/dist/security/SecurityCIPipeline.js +684 -0
- package/dist/security/SecurityCIPipeline.js.map +1 -0
- package/dist/security/SecurityConfigManager.d.ts +294 -0
- package/dist/security/SecurityConfigManager.d.ts.map +1 -0
- package/dist/security/SecurityConfigManager.js +553 -0
- package/dist/security/SecurityConfigManager.js.map +1 -0
- package/dist/security/SecurityMonitoring.d.ts +245 -0
- package/dist/security/SecurityMonitoring.d.ts.map +1 -0
- package/dist/security/SecurityMonitoring.js +596 -0
- package/dist/security/SecurityMonitoring.js.map +1 -0
- package/dist/security/SecurityReviewer.d.ts +168 -0
- package/dist/security/SecurityReviewer.d.ts.map +1 -0
- package/dist/security/SecurityReviewer.js +683 -0
- package/dist/security/SecurityReviewer.js.map +1 -0
- package/dist/security/index.d.ts +182 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +189 -0
- package/dist/security/index.js.map +1 -0
- package/dist/tools/media.d.ts +43 -4
- package/dist/tools/media.d.ts.map +1 -1
- package/dist/tools/media.js +43 -4
- package/dist/tools/media.js.map +1 -1
- package/dist/tools/posts.d.ts +225 -4
- package/dist/tools/posts.d.ts.map +1 -1
- package/dist/tools/posts.js +225 -4
- package/dist/tools/posts.js.map +1 -1
- package/docs/DOCKER_PUBLISHING_TROUBLESHOOTING.md +233 -0
- package/docs/PUBLISHING-TROUBLESHOOTING.md +227 -0
- package/docs/api/README.md +53 -11
- package/docs/api/openapi.json +10 -10
- package/docs/api/summary.json +1 -1
- package/docs/api/tools/wp_create_post.md +9 -3
- package/docs/api/tools/wp_delete_post.md +2 -3
- package/docs/api/tools/wp_get_current_user.md +7 -1
- package/docs/api/tools/wp_get_post.md +2 -3
- package/docs/api/tools/wp_get_post_revisions.md +1 -1
- package/docs/api/tools/wp_list_posts.md +10 -3
- package/docs/api/tools/wp_list_users.md +8 -1
- package/docs/api/tools/wp_search_site.md +8 -1
- package/docs/api/tools/wp_test_auth.md +8 -1
- package/docs/api/tools/wp_update_post.md +2 -3
- package/docs/examples/docker-production.md +801 -0
- package/docs/examples/multi-site-setup.md +575 -0
- package/docs/examples/single-site-setup.md +390 -0
- package/docs/examples/use-case-workflows.md +469 -0
- package/package.json +11 -3
- package/src/client/api.ts +90 -0
- package/src/security/AISecurityScanner.ts +780 -0
- package/src/security/AutomatedRemediation.ts +665 -0
- package/src/security/SecurityCIPipeline.ts +969 -0
- package/src/security/SecurityConfigManager.ts +829 -0
- package/src/security/SecurityMonitoring.ts +841 -0
- package/src/security/SecurityReviewer.ts +855 -0
- package/src/security/index.ts +249 -0
- package/src/tools/media.ts +43 -4
- package/src/tools/posts.ts +225 -4
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security CI/CD Pipeline Integration
|
|
3
|
+
* Provides security checks and gates for continuous integration and deployment
|
|
4
|
+
*/
|
|
5
|
+
import { AISecurityScanner } from "./AISecurityScanner";
|
|
6
|
+
import { AutomatedRemediation } from "./AutomatedRemediation";
|
|
7
|
+
import { SecurityReviewer } from "./SecurityReviewer";
|
|
8
|
+
import { SecurityConfigManager } from "./SecurityConfigManager";
|
|
9
|
+
import { SecurityUtils } from "./SecurityConfig";
|
|
10
|
+
import { SecurityValidationError } from "./InputValidator";
|
|
11
|
+
/**
|
|
12
|
+
* Security CI/CD Pipeline Manager
|
|
13
|
+
*/
|
|
14
|
+
export class SecurityCIPipeline {
|
|
15
|
+
scanner;
|
|
16
|
+
remediation;
|
|
17
|
+
reviewer;
|
|
18
|
+
configManager;
|
|
19
|
+
gates = new Map();
|
|
20
|
+
reports = [];
|
|
21
|
+
constructor() {
|
|
22
|
+
this.scanner = new AISecurityScanner();
|
|
23
|
+
this.remediation = new AutomatedRemediation();
|
|
24
|
+
this.reviewer = new SecurityReviewer();
|
|
25
|
+
this.configManager = new SecurityConfigManager();
|
|
26
|
+
this.initializeDefaultGates();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Initialize the security pipeline
|
|
30
|
+
*/
|
|
31
|
+
async initialize() {
|
|
32
|
+
console.log("[Security Pipeline] Initializing security CI/CD pipeline");
|
|
33
|
+
await this.configManager.initialize();
|
|
34
|
+
console.log("[Security Pipeline] Security pipeline ready");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execute security gates for a pipeline stage
|
|
38
|
+
*/
|
|
39
|
+
async executeSecurityGates(stage, context, options = {}) {
|
|
40
|
+
const reportId = SecurityUtils.generateSecureToken(16);
|
|
41
|
+
const startTime = Date.now();
|
|
42
|
+
console.log(`[Security Pipeline] Executing ${stage} security gates for ${context.branch}@${context.commit}`);
|
|
43
|
+
const applicableGates = Array.from(this.gates.values()).filter((gate) => gate.stage === stage && gate.enabled);
|
|
44
|
+
if (applicableGates.length === 0) {
|
|
45
|
+
console.log(`[Security Pipeline] No security gates configured for stage: ${stage}`);
|
|
46
|
+
return this.createEmptyReport(reportId, stage, startTime);
|
|
47
|
+
}
|
|
48
|
+
const gateResults = [];
|
|
49
|
+
let overallStatus = "passed";
|
|
50
|
+
for (const gate of applicableGates) {
|
|
51
|
+
console.log(`[Security Pipeline] Executing gate: ${gate.name}`);
|
|
52
|
+
try {
|
|
53
|
+
const gateResult = await this.executeSecurityGate(gate, context, options);
|
|
54
|
+
gateResults.push(gateResult);
|
|
55
|
+
// Update overall status
|
|
56
|
+
if (gateResult.status === "failed" && gate.blocking) {
|
|
57
|
+
overallStatus = "failed";
|
|
58
|
+
}
|
|
59
|
+
else if (gateResult.status === "warning" && overallStatus === "passed") {
|
|
60
|
+
overallStatus = "warning";
|
|
61
|
+
}
|
|
62
|
+
// Stop on blocking failure unless continuing on failure
|
|
63
|
+
if (gateResult.status === "failed" && gate.blocking && !options.continueOnFailure) {
|
|
64
|
+
console.log(`[Security Pipeline] Stopping pipeline due to blocking gate failure: ${gate.name}`);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error(`[Security Pipeline] Gate execution error: ${gate.name}`, error);
|
|
70
|
+
const errorResult = {
|
|
71
|
+
gateId: gate.id,
|
|
72
|
+
gateName: gate.name,
|
|
73
|
+
status: "failed",
|
|
74
|
+
duration: Date.now() - startTime,
|
|
75
|
+
checks: [],
|
|
76
|
+
blocking: gate.blocking,
|
|
77
|
+
message: `Gate execution failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
78
|
+
};
|
|
79
|
+
gateResults.push(errorResult);
|
|
80
|
+
if (gate.blocking && !options.continueOnFailure) {
|
|
81
|
+
overallStatus = "failed";
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const report = this.generatePipelineReport(reportId, stage, startTime, overallStatus, gateResults, context);
|
|
87
|
+
this.reports.push(report);
|
|
88
|
+
console.log(`[Security Pipeline] ${stage} gates completed with status: ${overallStatus}`);
|
|
89
|
+
return report;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Execute a single security gate
|
|
93
|
+
*/
|
|
94
|
+
async executeSecurityGate(gate, context, options = {}) {
|
|
95
|
+
const startTime = Date.now();
|
|
96
|
+
const checkResults = [];
|
|
97
|
+
for (const check of gate.checks) {
|
|
98
|
+
if (!check.enabled) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
console.log(`[Security Pipeline] Running check: ${check.name}`);
|
|
102
|
+
try {
|
|
103
|
+
const checkResult = await this.executeSecurityCheck(check, context, options);
|
|
104
|
+
checkResults.push(checkResult);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
console.error(`[Security Pipeline] Check execution error: ${check.name}`, error);
|
|
108
|
+
checkResults.push({
|
|
109
|
+
checkId: check.id,
|
|
110
|
+
checkName: check.name,
|
|
111
|
+
status: "error",
|
|
112
|
+
duration: Date.now() - startTime,
|
|
113
|
+
findings: [],
|
|
114
|
+
details: `Check execution failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
115
|
+
score: 0,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Evaluate gate status based on check results and thresholds
|
|
120
|
+
const gateStatus = this.evaluateGateStatus(gate, checkResults);
|
|
121
|
+
return {
|
|
122
|
+
gateId: gate.id,
|
|
123
|
+
gateName: gate.name,
|
|
124
|
+
status: gateStatus.status,
|
|
125
|
+
duration: Date.now() - startTime,
|
|
126
|
+
checks: checkResults,
|
|
127
|
+
blocking: gate.blocking,
|
|
128
|
+
message: gateStatus.message,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Execute a single security check
|
|
133
|
+
*/
|
|
134
|
+
async executeSecurityCheck(check, context, options = {}) {
|
|
135
|
+
const startTime = Date.now();
|
|
136
|
+
const findings = [];
|
|
137
|
+
let score = 100;
|
|
138
|
+
let details = "";
|
|
139
|
+
if (options.dryRun) {
|
|
140
|
+
return {
|
|
141
|
+
checkId: check.id,
|
|
142
|
+
checkName: check.name,
|
|
143
|
+
status: "passed",
|
|
144
|
+
duration: Date.now() - startTime,
|
|
145
|
+
findings: [],
|
|
146
|
+
details: "Dry run - no actual checks performed",
|
|
147
|
+
score: 100,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
switch (check.type) {
|
|
152
|
+
case "scan":
|
|
153
|
+
const scanResults = await this.executeScanCheck(check, context);
|
|
154
|
+
findings.push(...scanResults.findings);
|
|
155
|
+
score = scanResults.score;
|
|
156
|
+
details = scanResults.details;
|
|
157
|
+
break;
|
|
158
|
+
case "review":
|
|
159
|
+
const reviewResults = await this.executeReviewCheck(check, context);
|
|
160
|
+
findings.push(...reviewResults.findings);
|
|
161
|
+
score = reviewResults.score;
|
|
162
|
+
details = reviewResults.details;
|
|
163
|
+
break;
|
|
164
|
+
case "dependency":
|
|
165
|
+
const depResults = await this.executeDependencyCheck(check, context);
|
|
166
|
+
findings.push(...depResults.findings);
|
|
167
|
+
score = depResults.score;
|
|
168
|
+
details = depResults.details;
|
|
169
|
+
break;
|
|
170
|
+
case "configuration":
|
|
171
|
+
const configResults = await this.executeConfigurationCheck(check, context);
|
|
172
|
+
findings.push(...configResults.findings);
|
|
173
|
+
score = configResults.score;
|
|
174
|
+
details = configResults.details;
|
|
175
|
+
break;
|
|
176
|
+
case "secrets":
|
|
177
|
+
const secretResults = await this.executeSecretsCheck(check, context);
|
|
178
|
+
findings.push(...secretResults.findings);
|
|
179
|
+
score = secretResults.score;
|
|
180
|
+
details = secretResults.details;
|
|
181
|
+
break;
|
|
182
|
+
case "compliance":
|
|
183
|
+
const complianceResults = await this.executeComplianceCheck(check, context);
|
|
184
|
+
findings.push(...complianceResults.findings);
|
|
185
|
+
score = complianceResults.score;
|
|
186
|
+
details = complianceResults.details;
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
throw new Error(`Unknown check type: ${check.type}`);
|
|
190
|
+
}
|
|
191
|
+
// Determine check status based on findings
|
|
192
|
+
const criticalCount = findings.filter((f) => f.severity === "critical").length;
|
|
193
|
+
const highCount = findings.filter((f) => f.severity === "high").length;
|
|
194
|
+
let status;
|
|
195
|
+
if (criticalCount > 0) {
|
|
196
|
+
status = "failed";
|
|
197
|
+
}
|
|
198
|
+
else if (highCount > 0) {
|
|
199
|
+
status = "warning";
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
status = "passed";
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
checkId: check.id,
|
|
206
|
+
checkName: check.name,
|
|
207
|
+
status,
|
|
208
|
+
duration: Date.now() - startTime,
|
|
209
|
+
findings,
|
|
210
|
+
details,
|
|
211
|
+
score,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
throw new SecurityValidationError(`Check ${check.name} failed`, [{ message: String(error) }]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Execute security scan check
|
|
220
|
+
*/
|
|
221
|
+
async executeScanCheck(check, context) {
|
|
222
|
+
const scanResult = await this.scanner.performScan({
|
|
223
|
+
targets: check.parameters.targets || ["src/"],
|
|
224
|
+
depth: check.parameters.depth || "deep",
|
|
225
|
+
includeRuntime: check.parameters.includeRuntime || false,
|
|
226
|
+
includeFileSystem: check.parameters.includeFileSystem || true,
|
|
227
|
+
});
|
|
228
|
+
const findings = scanResult.vulnerabilities.map((vuln) => ({
|
|
229
|
+
id: vuln.id,
|
|
230
|
+
severity: vuln.severity,
|
|
231
|
+
type: vuln.type,
|
|
232
|
+
description: vuln.description,
|
|
233
|
+
file: vuln.location.file,
|
|
234
|
+
line: vuln.location.line,
|
|
235
|
+
remediation: vuln.remediation.suggested,
|
|
236
|
+
}));
|
|
237
|
+
const score = Math.max(0, 100 - (scanResult.summary.critical * 10 + scanResult.summary.high * 5 + scanResult.summary.medium * 2));
|
|
238
|
+
return {
|
|
239
|
+
findings,
|
|
240
|
+
score,
|
|
241
|
+
details: `Scanned codebase: ${scanResult.summary.total} vulnerabilities found`,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Execute code review check
|
|
246
|
+
*/
|
|
247
|
+
async executeReviewCheck(check, context) {
|
|
248
|
+
const reviewResults = await this.reviewer.reviewDirectory("src/", {
|
|
249
|
+
recursive: true,
|
|
250
|
+
rules: check.parameters.rules,
|
|
251
|
+
excludeRules: check.parameters.excludeRules,
|
|
252
|
+
aiAnalysis: check.parameters.aiAnalysis || false,
|
|
253
|
+
});
|
|
254
|
+
const allFindings = [];
|
|
255
|
+
let totalScore = 0;
|
|
256
|
+
for (const result of reviewResults) {
|
|
257
|
+
const resultFindings = result.findings.map((finding) => ({
|
|
258
|
+
id: finding.id,
|
|
259
|
+
severity: finding.severity,
|
|
260
|
+
type: finding.category,
|
|
261
|
+
description: finding.message,
|
|
262
|
+
file: result.file,
|
|
263
|
+
line: finding.line,
|
|
264
|
+
remediation: finding.recommendation,
|
|
265
|
+
}));
|
|
266
|
+
allFindings.push(...resultFindings);
|
|
267
|
+
totalScore += this.calculateFileScore(result.findings);
|
|
268
|
+
}
|
|
269
|
+
const averageScore = reviewResults.length > 0 ? totalScore / reviewResults.length : 100;
|
|
270
|
+
return {
|
|
271
|
+
findings: allFindings,
|
|
272
|
+
score: averageScore,
|
|
273
|
+
details: `Reviewed ${reviewResults.length} files: ${allFindings.length} security issues found`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Execute dependency check
|
|
278
|
+
*/
|
|
279
|
+
async executeDependencyCheck(check, context) {
|
|
280
|
+
// This would integrate with npm audit, Snyk, or similar tools
|
|
281
|
+
console.log("[Security Pipeline] Dependency check - integration with external tools required");
|
|
282
|
+
return {
|
|
283
|
+
findings: [],
|
|
284
|
+
score: 100,
|
|
285
|
+
details: "Dependency check completed - no vulnerabilities found",
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Execute configuration check
|
|
290
|
+
*/
|
|
291
|
+
async executeConfigurationCheck(check, context) {
|
|
292
|
+
const compliance = await this.configManager.validateCompliance(context.environment);
|
|
293
|
+
const findings = compliance.violations.map((violation, index) => ({
|
|
294
|
+
id: `config-${index}`,
|
|
295
|
+
severity: "medium",
|
|
296
|
+
type: "Configuration",
|
|
297
|
+
description: violation,
|
|
298
|
+
remediation: "Review security configuration",
|
|
299
|
+
}));
|
|
300
|
+
const score = compliance.compliant ? 100 : Math.max(0, 100 - compliance.violations.length * 10);
|
|
301
|
+
return {
|
|
302
|
+
findings,
|
|
303
|
+
score,
|
|
304
|
+
details: `Configuration compliance: ${compliance.compliant ? "compliant" : "non-compliant"}`,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Execute secrets check
|
|
309
|
+
*/
|
|
310
|
+
async executeSecretsCheck(check, context) {
|
|
311
|
+
// This would integrate with tools like TruffleHog, GitLeaks, etc.
|
|
312
|
+
console.log("[Security Pipeline] Secrets check - integration with secret scanning tools required");
|
|
313
|
+
return {
|
|
314
|
+
findings: [],
|
|
315
|
+
score: 100,
|
|
316
|
+
details: "Secrets scan completed - no exposed secrets found",
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Execute compliance check
|
|
321
|
+
*/
|
|
322
|
+
async executeComplianceCheck(check, context) {
|
|
323
|
+
const frameworks = check.parameters.frameworks || ["OWASP", "CWE"];
|
|
324
|
+
const findings = [];
|
|
325
|
+
// Check for compliance with security frameworks
|
|
326
|
+
for (const framework of frameworks) {
|
|
327
|
+
// This would integrate with compliance checking tools
|
|
328
|
+
console.log(`[Security Pipeline] Checking ${framework} compliance`);
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
findings,
|
|
332
|
+
score: 100,
|
|
333
|
+
details: `Compliance check completed for frameworks: ${frameworks.join(", ")}`,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Calculate security score for file findings
|
|
338
|
+
*/
|
|
339
|
+
calculateFileScore(findings) {
|
|
340
|
+
const severityWeights = { critical: 20, high: 10, medium: 5, low: 2, info: 1 };
|
|
341
|
+
const penalty = findings.reduce((sum, finding) => {
|
|
342
|
+
return sum + (severityWeights[finding.severity] || 0);
|
|
343
|
+
}, 0);
|
|
344
|
+
return Math.max(0, 100 - penalty);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Evaluate gate status based on check results and thresholds
|
|
348
|
+
*/
|
|
349
|
+
evaluateGateStatus(gate, checkResults) {
|
|
350
|
+
const allFindings = checkResults.flatMap((result) => result.findings);
|
|
351
|
+
const criticalCount = allFindings.filter((f) => f.severity === "critical").length;
|
|
352
|
+
const highCount = allFindings.filter((f) => f.severity === "high").length;
|
|
353
|
+
const mediumCount = allFindings.filter((f) => f.severity === "medium").length;
|
|
354
|
+
const averageScore = checkResults.length > 0 ? checkResults.reduce((sum, result) => sum + result.score, 0) / checkResults.length : 100;
|
|
355
|
+
// Check thresholds
|
|
356
|
+
if (criticalCount > gate.thresholds.maxCritical) {
|
|
357
|
+
return {
|
|
358
|
+
status: "failed",
|
|
359
|
+
message: `Critical vulnerabilities (${criticalCount}) exceed threshold (${gate.thresholds.maxCritical})`,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (highCount > gate.thresholds.maxHigh) {
|
|
363
|
+
return {
|
|
364
|
+
status: "failed",
|
|
365
|
+
message: `High-severity vulnerabilities (${highCount}) exceed threshold (${gate.thresholds.maxHigh})`,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
if (averageScore < gate.thresholds.minSecurityScore) {
|
|
369
|
+
return {
|
|
370
|
+
status: "failed",
|
|
371
|
+
message: `Security score (${averageScore.toFixed(1)}) below threshold (${gate.thresholds.minSecurityScore})`,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
if (mediumCount > gate.thresholds.maxMedium) {
|
|
375
|
+
return {
|
|
376
|
+
status: "warning",
|
|
377
|
+
message: `Medium-severity vulnerabilities (${mediumCount}) exceed threshold (${gate.thresholds.maxMedium})`,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
return {
|
|
381
|
+
status: "passed",
|
|
382
|
+
message: "All security checks passed",
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Generate pipeline security report
|
|
387
|
+
*/
|
|
388
|
+
generatePipelineReport(reportId, stage, startTime, status, gateResults, context) {
|
|
389
|
+
const allFindings = gateResults.flatMap((gate) => gate.checks.flatMap((check) => check.findings));
|
|
390
|
+
const summary = {
|
|
391
|
+
totalIssues: allFindings.length,
|
|
392
|
+
criticalIssues: allFindings.filter((f) => f.severity === "critical").length,
|
|
393
|
+
highIssues: allFindings.filter((f) => f.severity === "high").length,
|
|
394
|
+
mediumIssues: allFindings.filter((f) => f.severity === "medium").length,
|
|
395
|
+
lowIssues: allFindings.filter((f) => f.severity === "low").length,
|
|
396
|
+
securityScore: this.calculateOverallSecurityScore(gateResults),
|
|
397
|
+
compliance: status === "passed",
|
|
398
|
+
};
|
|
399
|
+
const recommendations = this.generateRecommendations(gateResults, summary);
|
|
400
|
+
return {
|
|
401
|
+
reportId,
|
|
402
|
+
timestamp: new Date(),
|
|
403
|
+
stage,
|
|
404
|
+
status,
|
|
405
|
+
duration: Date.now() - startTime,
|
|
406
|
+
gates: gateResults,
|
|
407
|
+
summary,
|
|
408
|
+
recommendations,
|
|
409
|
+
artifacts: this.generateArtifacts(reportId, gateResults),
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Calculate overall security score
|
|
414
|
+
*/
|
|
415
|
+
calculateOverallSecurityScore(gateResults) {
|
|
416
|
+
const allChecks = gateResults.flatMap((gate) => gate.checks);
|
|
417
|
+
if (allChecks.length === 0) {
|
|
418
|
+
return 100;
|
|
419
|
+
}
|
|
420
|
+
const totalScore = allChecks.reduce((sum, check) => sum + check.score, 0);
|
|
421
|
+
return totalScore / allChecks.length;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Generate recommendations based on results
|
|
425
|
+
*/
|
|
426
|
+
generateRecommendations(gateResults, summary) {
|
|
427
|
+
const recommendations = [];
|
|
428
|
+
if (summary.criticalIssues > 0) {
|
|
429
|
+
recommendations.push("Address critical security vulnerabilities immediately before deployment");
|
|
430
|
+
}
|
|
431
|
+
if (summary.highIssues > 5) {
|
|
432
|
+
recommendations.push("Review and remediate high-severity security issues");
|
|
433
|
+
}
|
|
434
|
+
if (summary.securityScore < 80) {
|
|
435
|
+
recommendations.push("Improve overall security posture through code review and security training");
|
|
436
|
+
}
|
|
437
|
+
const failedGates = gateResults.filter((gate) => gate.status === "failed");
|
|
438
|
+
if (failedGates.length > 0) {
|
|
439
|
+
recommendations.push(`Review failed security gates: ${failedGates.map((g) => g.gateName).join(", ")}`);
|
|
440
|
+
}
|
|
441
|
+
return recommendations;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Generate artifacts for the security report
|
|
445
|
+
*/
|
|
446
|
+
generateArtifacts(reportId, gateResults) {
|
|
447
|
+
// In a real implementation, this would generate SARIF files, security reports, etc.
|
|
448
|
+
return [`security-report-${reportId}.json`, `security-findings-${reportId}.sarif`];
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Create empty report for stages with no gates
|
|
452
|
+
*/
|
|
453
|
+
createEmptyReport(reportId, stage, startTime) {
|
|
454
|
+
return {
|
|
455
|
+
reportId,
|
|
456
|
+
timestamp: new Date(),
|
|
457
|
+
stage,
|
|
458
|
+
status: "passed",
|
|
459
|
+
duration: Date.now() - startTime,
|
|
460
|
+
gates: [],
|
|
461
|
+
summary: {
|
|
462
|
+
totalIssues: 0,
|
|
463
|
+
criticalIssues: 0,
|
|
464
|
+
highIssues: 0,
|
|
465
|
+
mediumIssues: 0,
|
|
466
|
+
lowIssues: 0,
|
|
467
|
+
securityScore: 100,
|
|
468
|
+
compliance: true,
|
|
469
|
+
},
|
|
470
|
+
recommendations: [],
|
|
471
|
+
artifacts: [],
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Initialize default security gates
|
|
476
|
+
*/
|
|
477
|
+
initializeDefaultGates() {
|
|
478
|
+
// Pre-commit gate
|
|
479
|
+
this.gates.set("pre-commit", {
|
|
480
|
+
id: "pre-commit",
|
|
481
|
+
name: "Pre-commit Security Gate",
|
|
482
|
+
stage: "pre-commit",
|
|
483
|
+
enabled: true,
|
|
484
|
+
blocking: true,
|
|
485
|
+
checks: [
|
|
486
|
+
{
|
|
487
|
+
id: "secrets-scan",
|
|
488
|
+
name: "Secrets Scan",
|
|
489
|
+
type: "secrets",
|
|
490
|
+
enabled: true,
|
|
491
|
+
timeout: 60000,
|
|
492
|
+
retries: 1,
|
|
493
|
+
parameters: {},
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
id: "basic-review",
|
|
497
|
+
name: "Basic Security Review",
|
|
498
|
+
type: "review",
|
|
499
|
+
enabled: true,
|
|
500
|
+
timeout: 120000,
|
|
501
|
+
retries: 1,
|
|
502
|
+
parameters: { rules: ["auth-001", "input-001", "crypto-001"] },
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
thresholds: {
|
|
506
|
+
maxCritical: 0,
|
|
507
|
+
maxHigh: 2,
|
|
508
|
+
maxMedium: 10,
|
|
509
|
+
minSecurityScore: 80,
|
|
510
|
+
},
|
|
511
|
+
exceptions: [],
|
|
512
|
+
});
|
|
513
|
+
// Pre-build gate
|
|
514
|
+
this.gates.set("pre-build", {
|
|
515
|
+
id: "pre-build",
|
|
516
|
+
name: "Pre-build Security Gate",
|
|
517
|
+
stage: "pre-build",
|
|
518
|
+
enabled: true,
|
|
519
|
+
blocking: true,
|
|
520
|
+
checks: [
|
|
521
|
+
{
|
|
522
|
+
id: "full-scan",
|
|
523
|
+
name: "Full Security Scan",
|
|
524
|
+
type: "scan",
|
|
525
|
+
enabled: true,
|
|
526
|
+
timeout: 300000,
|
|
527
|
+
retries: 1,
|
|
528
|
+
parameters: { depth: "comprehensive", includeRuntime: true },
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
id: "dependency-check",
|
|
532
|
+
name: "Dependency Vulnerability Check",
|
|
533
|
+
type: "dependency",
|
|
534
|
+
enabled: true,
|
|
535
|
+
timeout: 180000,
|
|
536
|
+
retries: 2,
|
|
537
|
+
parameters: {},
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
id: "config-review",
|
|
541
|
+
name: "Configuration Review",
|
|
542
|
+
type: "configuration",
|
|
543
|
+
enabled: true,
|
|
544
|
+
timeout: 60000,
|
|
545
|
+
retries: 1,
|
|
546
|
+
parameters: {},
|
|
547
|
+
},
|
|
548
|
+
],
|
|
549
|
+
thresholds: {
|
|
550
|
+
maxCritical: 0,
|
|
551
|
+
maxHigh: 5,
|
|
552
|
+
maxMedium: 20,
|
|
553
|
+
minSecurityScore: 75,
|
|
554
|
+
},
|
|
555
|
+
exceptions: [],
|
|
556
|
+
});
|
|
557
|
+
// Pre-deploy gate
|
|
558
|
+
this.gates.set("pre-deploy", {
|
|
559
|
+
id: "pre-deploy",
|
|
560
|
+
name: "Pre-deployment Security Gate",
|
|
561
|
+
stage: "pre-deploy",
|
|
562
|
+
enabled: true,
|
|
563
|
+
blocking: true,
|
|
564
|
+
checks: [
|
|
565
|
+
{
|
|
566
|
+
id: "compliance-check",
|
|
567
|
+
name: "Compliance Validation",
|
|
568
|
+
type: "compliance",
|
|
569
|
+
enabled: true,
|
|
570
|
+
timeout: 120000,
|
|
571
|
+
retries: 1,
|
|
572
|
+
parameters: { frameworks: ["OWASP", "CWE"] },
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
id: "final-review",
|
|
576
|
+
name: "Final Security Review",
|
|
577
|
+
type: "review",
|
|
578
|
+
enabled: true,
|
|
579
|
+
timeout: 240000,
|
|
580
|
+
retries: 1,
|
|
581
|
+
parameters: { aiAnalysis: true },
|
|
582
|
+
},
|
|
583
|
+
],
|
|
584
|
+
thresholds: {
|
|
585
|
+
maxCritical: 0,
|
|
586
|
+
maxHigh: 1,
|
|
587
|
+
maxMedium: 5,
|
|
588
|
+
minSecurityScore: 85,
|
|
589
|
+
},
|
|
590
|
+
exceptions: [],
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Get security gate configuration
|
|
595
|
+
*/
|
|
596
|
+
getSecurityGate(gateId) {
|
|
597
|
+
return this.gates.get(gateId) || null;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Update security gate configuration
|
|
601
|
+
*/
|
|
602
|
+
updateSecurityGate(gateId, updates) {
|
|
603
|
+
const gate = this.gates.get(gateId);
|
|
604
|
+
if (!gate) {
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
const updatedGate = { ...gate, ...updates, id: gateId };
|
|
608
|
+
this.gates.set(gateId, updatedGate);
|
|
609
|
+
console.log(`[Security Pipeline] Updated security gate: ${updatedGate.name}`);
|
|
610
|
+
return true;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Get pipeline reports
|
|
614
|
+
*/
|
|
615
|
+
getReports(options = {}) {
|
|
616
|
+
let reports = [...this.reports];
|
|
617
|
+
if (options.stage) {
|
|
618
|
+
reports = reports.filter((r) => r.stage === options.stage);
|
|
619
|
+
}
|
|
620
|
+
if (options.status) {
|
|
621
|
+
reports = reports.filter((r) => r.status === options.status);
|
|
622
|
+
}
|
|
623
|
+
if (options.since) {
|
|
624
|
+
reports = reports.filter((r) => r.timestamp >= options.since);
|
|
625
|
+
}
|
|
626
|
+
// Sort by timestamp (newest first)
|
|
627
|
+
reports.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
|
|
628
|
+
if (options.limit) {
|
|
629
|
+
reports = reports.slice(0, options.limit);
|
|
630
|
+
}
|
|
631
|
+
return reports;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Get pipeline statistics
|
|
635
|
+
*/
|
|
636
|
+
getStatistics() {
|
|
637
|
+
const totalReports = this.reports.length;
|
|
638
|
+
const passedReports = this.reports.filter((r) => r.status === "passed").length;
|
|
639
|
+
const passRate = totalReports > 0 ? passedReports / totalReports : 1;
|
|
640
|
+
const averageSecurityScore = totalReports > 0 ? this.reports.reduce((sum, r) => sum + r.summary.securityScore, 0) / totalReports : 100;
|
|
641
|
+
// Count issue types
|
|
642
|
+
const issueTypes = {};
|
|
643
|
+
this.reports.forEach((report) => {
|
|
644
|
+
report.gates.forEach((gate) => {
|
|
645
|
+
gate.checks.forEach((check) => {
|
|
646
|
+
check.findings.forEach((finding) => {
|
|
647
|
+
issueTypes[finding.type] = (issueTypes[finding.type] || 0) + 1;
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
const mostCommonIssues = Object.entries(issueTypes)
|
|
653
|
+
.map(([type, count]) => ({ type, count }))
|
|
654
|
+
.sort((a, b) => b.count - a.count)
|
|
655
|
+
.slice(0, 5);
|
|
656
|
+
// Calculate gate performance
|
|
657
|
+
const gateStats = {};
|
|
658
|
+
this.reports.forEach((report) => {
|
|
659
|
+
report.gates.forEach((gate) => {
|
|
660
|
+
if (!gateStats[gate.gateId]) {
|
|
661
|
+
gateStats[gate.gateId] = { total: 0, passed: 0, totalDuration: 0 };
|
|
662
|
+
}
|
|
663
|
+
gateStats[gate.gateId].total++;
|
|
664
|
+
gateStats[gate.gateId].totalDuration += gate.duration;
|
|
665
|
+
if (gate.status === "passed") {
|
|
666
|
+
gateStats[gate.gateId].passed++;
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
});
|
|
670
|
+
const gatePerformance = Object.entries(gateStats).map(([gateId, stats]) => ({
|
|
671
|
+
gateId,
|
|
672
|
+
successRate: stats.total > 0 ? stats.passed / stats.total : 0,
|
|
673
|
+
averageDuration: stats.total > 0 ? stats.totalDuration / stats.total : 0,
|
|
674
|
+
}));
|
|
675
|
+
return {
|
|
676
|
+
totalReports,
|
|
677
|
+
passRate,
|
|
678
|
+
averageSecurityScore,
|
|
679
|
+
mostCommonIssues,
|
|
680
|
+
gatePerformance,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
//# sourceMappingURL=SecurityCIPipeline.js.map
|