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.
Files changed (71) hide show
  1. package/README.md +503 -0
  2. package/dist/client/api.d.ts +90 -0
  3. package/dist/client/api.d.ts.map +1 -1
  4. package/dist/client/api.js +90 -0
  5. package/dist/client/api.js.map +1 -1
  6. package/dist/security/AISecurityScanner.d.ts +175 -0
  7. package/dist/security/AISecurityScanner.d.ts.map +1 -0
  8. package/dist/security/AISecurityScanner.js +645 -0
  9. package/dist/security/AISecurityScanner.js.map +1 -0
  10. package/dist/security/AutomatedRemediation.d.ts +145 -0
  11. package/dist/security/AutomatedRemediation.d.ts.map +1 -0
  12. package/dist/security/AutomatedRemediation.js +535 -0
  13. package/dist/security/AutomatedRemediation.js.map +1 -0
  14. package/dist/security/SecurityCIPipeline.d.ts +213 -0
  15. package/dist/security/SecurityCIPipeline.d.ts.map +1 -0
  16. package/dist/security/SecurityCIPipeline.js +684 -0
  17. package/dist/security/SecurityCIPipeline.js.map +1 -0
  18. package/dist/security/SecurityConfigManager.d.ts +294 -0
  19. package/dist/security/SecurityConfigManager.d.ts.map +1 -0
  20. package/dist/security/SecurityConfigManager.js +553 -0
  21. package/dist/security/SecurityConfigManager.js.map +1 -0
  22. package/dist/security/SecurityMonitoring.d.ts +245 -0
  23. package/dist/security/SecurityMonitoring.d.ts.map +1 -0
  24. package/dist/security/SecurityMonitoring.js +596 -0
  25. package/dist/security/SecurityMonitoring.js.map +1 -0
  26. package/dist/security/SecurityReviewer.d.ts +168 -0
  27. package/dist/security/SecurityReviewer.d.ts.map +1 -0
  28. package/dist/security/SecurityReviewer.js +683 -0
  29. package/dist/security/SecurityReviewer.js.map +1 -0
  30. package/dist/security/index.d.ts +182 -0
  31. package/dist/security/index.d.ts.map +1 -0
  32. package/dist/security/index.js +189 -0
  33. package/dist/security/index.js.map +1 -0
  34. package/dist/tools/media.d.ts +43 -4
  35. package/dist/tools/media.d.ts.map +1 -1
  36. package/dist/tools/media.js +43 -4
  37. package/dist/tools/media.js.map +1 -1
  38. package/dist/tools/posts.d.ts +225 -4
  39. package/dist/tools/posts.d.ts.map +1 -1
  40. package/dist/tools/posts.js +225 -4
  41. package/dist/tools/posts.js.map +1 -1
  42. package/docs/DOCKER_PUBLISHING_TROUBLESHOOTING.md +233 -0
  43. package/docs/PUBLISHING-TROUBLESHOOTING.md +227 -0
  44. package/docs/api/README.md +53 -11
  45. package/docs/api/openapi.json +10 -10
  46. package/docs/api/summary.json +1 -1
  47. package/docs/api/tools/wp_create_post.md +9 -3
  48. package/docs/api/tools/wp_delete_post.md +2 -3
  49. package/docs/api/tools/wp_get_current_user.md +7 -1
  50. package/docs/api/tools/wp_get_post.md +2 -3
  51. package/docs/api/tools/wp_get_post_revisions.md +1 -1
  52. package/docs/api/tools/wp_list_posts.md +10 -3
  53. package/docs/api/tools/wp_list_users.md +8 -1
  54. package/docs/api/tools/wp_search_site.md +8 -1
  55. package/docs/api/tools/wp_test_auth.md +8 -1
  56. package/docs/api/tools/wp_update_post.md +2 -3
  57. package/docs/examples/docker-production.md +801 -0
  58. package/docs/examples/multi-site-setup.md +575 -0
  59. package/docs/examples/single-site-setup.md +390 -0
  60. package/docs/examples/use-case-workflows.md +469 -0
  61. package/package.json +11 -3
  62. package/src/client/api.ts +90 -0
  63. package/src/security/AISecurityScanner.ts +780 -0
  64. package/src/security/AutomatedRemediation.ts +665 -0
  65. package/src/security/SecurityCIPipeline.ts +969 -0
  66. package/src/security/SecurityConfigManager.ts +829 -0
  67. package/src/security/SecurityMonitoring.ts +841 -0
  68. package/src/security/SecurityReviewer.ts +855 -0
  69. package/src/security/index.ts +249 -0
  70. package/src/tools/media.ts +43 -4
  71. package/src/tools/posts.ts +225 -4
@@ -0,0 +1,665 @@
1
+ /**
2
+ * Automated Security Remediation System
3
+ * Provides intelligent automated fixes for detected vulnerabilities
4
+ */
5
+
6
+ import * as fs from "fs/promises";
7
+ import * as path from "path";
8
+ import { SecurityVulnerability, SecurityScanResult } from "./AISecurityScanner";
9
+ import { SecurityUtils } from "./SecurityConfig";
10
+ import { SecurityValidationError } from "./InputValidator";
11
+
12
+ interface RemediationAction {
13
+ id: string;
14
+ type: "replace" | "insert" | "delete" | "config" | "file";
15
+ target: {
16
+ file?: string | undefined;
17
+ line?: number | undefined;
18
+ pattern?: RegExp | undefined;
19
+ value?: string | undefined;
20
+ };
21
+ replacement: {
22
+ content?: string;
23
+ config?: Record<string, any>;
24
+ action?: string;
25
+ };
26
+ backup: {
27
+ enabled: boolean;
28
+ path?: string;
29
+ };
30
+ validation: {
31
+ test?: string;
32
+ expected?: any;
33
+ };
34
+ }
35
+
36
+ export interface RemediationResult {
37
+ vulnerabilityId: string;
38
+ success: boolean;
39
+ action: string;
40
+ details: string;
41
+ timestamp: Date;
42
+ backupPath?: string | undefined;
43
+ validationResult?: boolean | undefined;
44
+ }
45
+
46
+ interface RemediationPlan {
47
+ planId: string;
48
+ vulnerabilities: SecurityVulnerability[];
49
+ actions: RemediationAction[];
50
+ estimatedDuration: number;
51
+ riskLevel: "low" | "medium" | "high";
52
+ requiresApproval: boolean;
53
+ }
54
+
55
+ /**
56
+ * Automated remediation patterns for common vulnerabilities
57
+ */
58
+ const REMEDIATION_PATTERNS = {
59
+ sqlInjection: {
60
+ pattern: /(SELECT|INSERT|UPDATE|DELETE).*?[\'\"].*?[\'\"].*?(WHERE|FROM|INTO)/gi,
61
+ replacement: "// TODO: Replace with parameterized query",
62
+ confidence: 0.7,
63
+ },
64
+
65
+ xssSimple: {
66
+ pattern: /innerHTML\s*=\s*[^;]+;?/gi,
67
+ replacement: "textContent = $1; // XSS remediation",
68
+ confidence: 0.8,
69
+ },
70
+
71
+ pathTraversal: {
72
+ pattern: /\.\.[\/\\]/g,
73
+ replacement: "",
74
+ confidence: 0.9,
75
+ },
76
+
77
+ credentialExposure: {
78
+ pattern: /(password|secret|key|token)\s*[:=]\s*['"][^'"]+['"]/gi,
79
+ replacement: "$1 = process.env.$1?.toUpperCase() || '[REQUIRED]'",
80
+ confidence: 0.85,
81
+ },
82
+
83
+ httpToHttps: {
84
+ pattern: /http:\/\//gi,
85
+ replacement: "https://",
86
+ confidence: 0.95,
87
+ },
88
+
89
+ insecureConfig: {
90
+ pattern: /(ssl|secure|verify)\s*[:=]\s*false/gi,
91
+ replacement: "$1: true",
92
+ confidence: 0.9,
93
+ },
94
+ };
95
+
96
+ /**
97
+ * Automated Security Remediation Engine
98
+ */
99
+ export class AutomatedRemediation {
100
+ private remediationHistory: RemediationResult[] = [];
101
+ private backupDirectory = "security-backups";
102
+
103
+ /**
104
+ * Create remediation plan for scan results
105
+ */
106
+ async createRemediationPlan(scanResult: SecurityScanResult): Promise<RemediationPlan> {
107
+ const planId = SecurityUtils.generateSecureToken(16);
108
+ const remediableVulns = scanResult.vulnerabilities.filter((v) => v.remediation.automated);
109
+
110
+ console.log(`[Remediation] Creating plan for ${remediableVulns.length} remediable vulnerabilities`);
111
+
112
+ const actions: RemediationAction[] = [];
113
+ let estimatedDuration = 0;
114
+ let maxRiskLevel: "low" | "medium" | "high" = "low";
115
+
116
+ for (const vulnerability of remediableVulns) {
117
+ const action = await this.createRemediationAction(vulnerability);
118
+ if (action) {
119
+ actions.push(action);
120
+ estimatedDuration += 30; // 30 seconds per action estimate
121
+
122
+ // Update risk level
123
+ if (vulnerability.severity === "critical" || vulnerability.severity === "high") {
124
+ maxRiskLevel = "high";
125
+ } else if (vulnerability.severity === "medium" && maxRiskLevel === "low") {
126
+ maxRiskLevel = "medium";
127
+ }
128
+ }
129
+ }
130
+
131
+ const requiresApproval = maxRiskLevel === "high" || actions.length > 10;
132
+
133
+ return {
134
+ planId,
135
+ vulnerabilities: remediableVulns,
136
+ actions,
137
+ estimatedDuration,
138
+ riskLevel: maxRiskLevel,
139
+ requiresApproval,
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Create remediation action for a specific vulnerability
145
+ */
146
+ private async createRemediationAction(vulnerability: SecurityVulnerability): Promise<RemediationAction | null> {
147
+ const actionId = SecurityUtils.generateSecureToken(12);
148
+
149
+ switch (vulnerability.type) {
150
+ case "SQL Injection":
151
+ return this.createSQLInjectionRemediation(actionId, vulnerability);
152
+
153
+ case "Cross-Site Scripting (XSS)":
154
+ return this.createXSSRemediation(actionId, vulnerability);
155
+
156
+ case "Path Traversal":
157
+ return this.createPathTraversalRemediation(actionId, vulnerability);
158
+
159
+ case "Credential Exposure":
160
+ return this.createCredentialExposureRemediation(actionId, vulnerability);
161
+
162
+ case "Insecure Configuration":
163
+ return this.createConfigRemediation(actionId, vulnerability);
164
+
165
+ case "Information Disclosure":
166
+ return this.createInfoDisclosureRemediation(actionId, vulnerability);
167
+
168
+ default:
169
+ return null;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Create SQL injection remediation
175
+ */
176
+ private createSQLInjectionRemediation(actionId: string, vulnerability: SecurityVulnerability): RemediationAction {
177
+ return {
178
+ id: actionId,
179
+ type: "replace",
180
+ target: {
181
+ file: vulnerability.location.file,
182
+ line: vulnerability.location.line,
183
+ pattern: REMEDIATION_PATTERNS.sqlInjection.pattern,
184
+ },
185
+ replacement: {
186
+ content:
187
+ "// SECURITY FIX: Replace with parameterized query to prevent SQL injection\n" +
188
+ "// Example: db.query('SELECT * FROM users WHERE id = ?', [userId])",
189
+ },
190
+ backup: {
191
+ enabled: true,
192
+ },
193
+ validation: {
194
+ test: 'grep -n "SELECT.*WHERE" $file | wc -l',
195
+ expected: 0,
196
+ },
197
+ };
198
+ }
199
+
200
+ /**
201
+ * Create XSS remediation
202
+ */
203
+ private createXSSRemediation(actionId: string, vulnerability: SecurityVulnerability): RemediationAction {
204
+ return {
205
+ id: actionId,
206
+ type: "replace",
207
+ target: {
208
+ file: vulnerability.location.file,
209
+ line: vulnerability.location.line,
210
+ pattern: /innerHTML\s*=\s*([^;]+);?/gi,
211
+ },
212
+ replacement: {
213
+ content: "textContent = $1; // XSS remediation: use textContent instead of innerHTML",
214
+ },
215
+ backup: {
216
+ enabled: true,
217
+ },
218
+ validation: {
219
+ test: 'grep -n "innerHTML" $file | wc -l',
220
+ expected: 0,
221
+ },
222
+ };
223
+ }
224
+
225
+ /**
226
+ * Create path traversal remediation
227
+ */
228
+ private createPathTraversalRemediation(actionId: string, vulnerability: SecurityVulnerability): RemediationAction {
229
+ return {
230
+ id: actionId,
231
+ type: "replace",
232
+ target: {
233
+ file: vulnerability.location.file,
234
+ line: vulnerability.location.line,
235
+ pattern: /\.\.[\/\\]/g,
236
+ },
237
+ replacement: {
238
+ content: "", // Remove path traversal sequences
239
+ },
240
+ backup: {
241
+ enabled: true,
242
+ },
243
+ validation: {
244
+ test: 'grep -n "\\.\\./" $file | wc -l',
245
+ expected: 0,
246
+ },
247
+ };
248
+ }
249
+
250
+ /**
251
+ * Create credential exposure remediation
252
+ */
253
+ private createCredentialExposureRemediation(
254
+ actionId: string,
255
+ vulnerability: SecurityVulnerability,
256
+ ): RemediationAction {
257
+ return {
258
+ id: actionId,
259
+ type: "replace",
260
+ target: {
261
+ file: vulnerability.location.file,
262
+ line: vulnerability.location.line,
263
+ pattern: /(password|secret|key|token)\s*[:=]\s*['"][^'"]+['"]/gi,
264
+ },
265
+ replacement: {
266
+ content:
267
+ "// SECURITY FIX: Credential moved to environment variable\n" +
268
+ "// Add to .env: $1=your_actual_value\n" +
269
+ "$1: process.env.$1 || (() => { throw new Error('$1 environment variable required'); })()",
270
+ },
271
+ backup: {
272
+ enabled: true,
273
+ },
274
+ validation: {
275
+ test: 'grep -n "password.*=.*[\'\\"]" $file | wc -l',
276
+ expected: 0,
277
+ },
278
+ };
279
+ }
280
+
281
+ /**
282
+ * Create configuration remediation
283
+ */
284
+ private createConfigRemediation(actionId: string, vulnerability: SecurityVulnerability): RemediationAction {
285
+ return {
286
+ id: actionId,
287
+ type: "replace",
288
+ target: {
289
+ file: vulnerability.location.file,
290
+ line: vulnerability.location.line,
291
+ pattern: /(ssl|secure|verify)\s*[:=]\s*false/gi,
292
+ },
293
+ replacement: {
294
+ content: "$1: true // Security fix: enabled secure configuration",
295
+ },
296
+ backup: {
297
+ enabled: true,
298
+ },
299
+ validation: {
300
+ test: 'grep -n "ssl.*false" $file | wc -l',
301
+ expected: 0,
302
+ },
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Create information disclosure remediation
308
+ */
309
+ private createInfoDisclosureRemediation(actionId: string, vulnerability: SecurityVulnerability): RemediationAction {
310
+ return {
311
+ id: actionId,
312
+ type: "replace",
313
+ target: {
314
+ file: vulnerability.location.file,
315
+ line: vulnerability.location.line,
316
+ pattern: /(debug|trace|error)\s*[:=]\s*true/gi,
317
+ },
318
+ replacement: {
319
+ content: "$1: process.env.NODE_ENV !== 'production' // Security fix: disable in production",
320
+ },
321
+ backup: {
322
+ enabled: true,
323
+ },
324
+ validation: {
325
+ test: 'grep -n "debug.*true" $file | wc -l',
326
+ expected: 0,
327
+ },
328
+ };
329
+ }
330
+
331
+ /**
332
+ * Execute remediation plan
333
+ */
334
+ async executeRemediationPlan(
335
+ plan: RemediationPlan,
336
+ options: {
337
+ dryRun?: boolean;
338
+ requireConfirmation?: boolean;
339
+ } = {},
340
+ ): Promise<RemediationResult[]> {
341
+ console.log(`[Remediation] Executing plan ${plan.planId} with ${plan.actions.length} actions`);
342
+
343
+ if (options.dryRun) {
344
+ console.log("[Remediation] DRY RUN MODE - No changes will be made");
345
+ return this.simulateRemediationActions(plan.actions);
346
+ }
347
+
348
+ const results: RemediationResult[] = [];
349
+
350
+ // Ensure backup directory exists
351
+ await this.ensureBackupDirectory();
352
+
353
+ for (const action of plan.actions) {
354
+ try {
355
+ console.log(`[Remediation] Executing action ${action.id} of type ${action.type}`);
356
+
357
+ const result = await this.executeRemediationAction(action);
358
+ results.push(result);
359
+
360
+ if (!result.success) {
361
+ console.error(`[Remediation] Action ${action.id} failed: ${result.details}`);
362
+ }
363
+ } catch (error) {
364
+ console.error(`[Remediation] Action ${action.id} threw error:`, error);
365
+ results.push({
366
+ vulnerabilityId: action.id,
367
+ success: false,
368
+ action: action.type,
369
+ details: `Error: ${error instanceof Error ? error.message : String(error)}`,
370
+ timestamp: new Date(),
371
+ });
372
+ }
373
+ }
374
+
375
+ this.remediationHistory.push(...results);
376
+
377
+ const successCount = results.filter((r) => r.success).length;
378
+ console.log(`[Remediation] Plan completed: ${successCount}/${results.length} actions successful`);
379
+
380
+ return results;
381
+ }
382
+
383
+ /**
384
+ * Execute a single remediation action
385
+ */
386
+ private async executeRemediationAction(action: RemediationAction): Promise<RemediationResult> {
387
+ const startTime = Date.now();
388
+
389
+ try {
390
+ let backupPath: string | undefined;
391
+
392
+ // Create backup if enabled
393
+ if (action.backup.enabled && action.target.file) {
394
+ backupPath = await this.createBackup(action.target.file);
395
+ }
396
+
397
+ // Execute the action based on type
398
+ switch (action.type) {
399
+ case "replace":
400
+ await this.executeReplaceAction(action);
401
+ break;
402
+
403
+ case "insert":
404
+ await this.executeInsertAction(action);
405
+ break;
406
+
407
+ case "delete":
408
+ await this.executeDeleteAction(action);
409
+ break;
410
+
411
+ case "config":
412
+ await this.executeConfigAction(action);
413
+ break;
414
+
415
+ case "file":
416
+ await this.executeFileAction(action);
417
+ break;
418
+
419
+ default:
420
+ throw new Error(`Unknown action type: ${action.type}`);
421
+ }
422
+
423
+ // Validate the fix if validation is provided
424
+ let validationResult: boolean | undefined;
425
+ if (action.validation && action.target.file) {
426
+ validationResult = await this.validateRemediation(action);
427
+ }
428
+
429
+ return {
430
+ vulnerabilityId: action.id,
431
+ success: true,
432
+ action: action.type,
433
+ details: `Remediation completed successfully in ${Date.now() - startTime}ms`,
434
+ timestamp: new Date(),
435
+ backupPath,
436
+ validationResult,
437
+ };
438
+ } catch (error) {
439
+ return {
440
+ vulnerabilityId: action.id,
441
+ success: false,
442
+ action: action.type,
443
+ details: `Remediation failed: ${error instanceof Error ? error.message : String(error)}`,
444
+ timestamp: new Date(),
445
+ };
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Execute replace action
451
+ */
452
+ private async executeReplaceAction(action: RemediationAction): Promise<void> {
453
+ if (!action.target.file || !action.target.pattern || !action.replacement.content) {
454
+ throw new Error("Replace action missing required fields");
455
+ }
456
+
457
+ const content = await fs.readFile(action.target.file, "utf-8");
458
+ const updatedContent = content.replace(action.target.pattern, action.replacement.content);
459
+
460
+ if (content === updatedContent) {
461
+ throw new Error("No changes made - pattern not found");
462
+ }
463
+
464
+ await fs.writeFile(action.target.file, updatedContent, "utf-8");
465
+ }
466
+
467
+ /**
468
+ * Execute insert action
469
+ */
470
+ private async executeInsertAction(action: RemediationAction): Promise<void> {
471
+ if (!action.target.file || !action.replacement.content) {
472
+ throw new Error("Insert action missing required fields");
473
+ }
474
+
475
+ const content = await fs.readFile(action.target.file, "utf-8");
476
+ const lines = content.split("\n");
477
+
478
+ const insertIndex = action.target.line ? Math.max(0, action.target.line - 1) : lines.length;
479
+ lines.splice(insertIndex, 0, action.replacement.content);
480
+
481
+ await fs.writeFile(action.target.file, lines.join("\n"), "utf-8");
482
+ }
483
+
484
+ /**
485
+ * Execute delete action
486
+ */
487
+ private async executeDeleteAction(action: RemediationAction): Promise<void> {
488
+ if (!action.target.file) {
489
+ throw new Error("Delete action missing file");
490
+ }
491
+
492
+ if (action.target.line) {
493
+ // Delete specific line
494
+ const content = await fs.readFile(action.target.file, "utf-8");
495
+ const lines = content.split("\n");
496
+
497
+ if (action.target.line > 0 && action.target.line <= lines.length) {
498
+ lines.splice(action.target.line - 1, 1);
499
+ await fs.writeFile(action.target.file, lines.join("\n"), "utf-8");
500
+ }
501
+ } else if (action.target.pattern) {
502
+ // Delete pattern matches
503
+ const content = await fs.readFile(action.target.file, "utf-8");
504
+ const updatedContent = content.replace(action.target.pattern, "");
505
+ await fs.writeFile(action.target.file, updatedContent, "utf-8");
506
+ } else {
507
+ throw new Error("Delete action missing target specification");
508
+ }
509
+ }
510
+
511
+ /**
512
+ * Execute config action
513
+ */
514
+ private async executeConfigAction(action: RemediationAction): Promise<void> {
515
+ if (!action.target.file || !action.replacement.config) {
516
+ throw new Error("Config action missing required fields");
517
+ }
518
+
519
+ const content = await fs.readFile(action.target.file, "utf-8");
520
+ const config = JSON.parse(content);
521
+
522
+ // Merge configuration changes
523
+ Object.assign(config, action.replacement.config);
524
+
525
+ await fs.writeFile(action.target.file, JSON.stringify(config, null, 2), "utf-8");
526
+ }
527
+
528
+ /**
529
+ * Execute file action
530
+ */
531
+ private async executeFileAction(action: RemediationAction): Promise<void> {
532
+ if (!action.replacement.action) {
533
+ throw new Error("File action missing action specification");
534
+ }
535
+
536
+ switch (action.replacement.action) {
537
+ case "delete":
538
+ if (action.target.file) {
539
+ await fs.unlink(action.target.file);
540
+ }
541
+ break;
542
+
543
+ case "create":
544
+ if (action.target.file && action.replacement.content) {
545
+ await fs.writeFile(action.target.file, action.replacement.content, "utf-8");
546
+ }
547
+ break;
548
+
549
+ default:
550
+ throw new Error(`Unknown file action: ${action.replacement.action}`);
551
+ }
552
+ }
553
+
554
+ /**
555
+ * Create backup of file
556
+ */
557
+ private async createBackup(filePath: string): Promise<string> {
558
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
559
+ const backupPath = path.join(this.backupDirectory, `${path.basename(filePath)}.${timestamp}.backup`);
560
+
561
+ const content = await fs.readFile(filePath, "utf-8");
562
+ await fs.writeFile(backupPath, content, "utf-8");
563
+
564
+ console.log(`[Remediation] Created backup: ${backupPath}`);
565
+ return backupPath;
566
+ }
567
+
568
+ /**
569
+ * Ensure backup directory exists
570
+ */
571
+ private async ensureBackupDirectory(): Promise<void> {
572
+ try {
573
+ await fs.access(this.backupDirectory);
574
+ } catch {
575
+ await fs.mkdir(this.backupDirectory, { recursive: true });
576
+ console.log(`[Remediation] Created backup directory: ${this.backupDirectory}`);
577
+ }
578
+ }
579
+
580
+ /**
581
+ * Validate remediation
582
+ */
583
+ private async validateRemediation(action: RemediationAction): Promise<boolean> {
584
+ if (!action.validation?.test || !action.target.file) {
585
+ return true; // No validation specified
586
+ }
587
+
588
+ try {
589
+ // This is a simplified validation - in practice you'd run the test command
590
+ const content = await fs.readFile(action.target.file, "utf-8");
591
+
592
+ // Simple pattern-based validation
593
+ if (action.target.pattern) {
594
+ const matches = content.match(action.target.pattern);
595
+ return (matches?.length || 0) === (action.validation.expected || 0);
596
+ }
597
+
598
+ return true;
599
+ } catch (error) {
600
+ console.warn(`[Remediation] Validation failed for action ${action.id}:`, error);
601
+ return false;
602
+ }
603
+ }
604
+
605
+ /**
606
+ * Simulate remediation actions for dry run
607
+ */
608
+ private async simulateRemediationActions(actions: RemediationAction[]): Promise<RemediationResult[]> {
609
+ const results: RemediationResult[] = [];
610
+
611
+ for (const action of actions) {
612
+ results.push({
613
+ vulnerabilityId: action.id,
614
+ success: true,
615
+ action: `${action.type} (simulated)`,
616
+ details: `Would ${action.type} in ${action.target.file || "configuration"}`,
617
+ timestamp: new Date(),
618
+ });
619
+ }
620
+
621
+ return results;
622
+ }
623
+
624
+ /**
625
+ * Get remediation history
626
+ */
627
+ getRemediationHistory(): RemediationResult[] {
628
+ return [...this.remediationHistory];
629
+ }
630
+
631
+ /**
632
+ * Rollback remediation using backup
633
+ */
634
+ async rollbackRemediation(backupPath: string, targetFile: string): Promise<void> {
635
+ try {
636
+ const backupContent = await fs.readFile(backupPath, "utf-8");
637
+ await fs.writeFile(targetFile, backupContent, "utf-8");
638
+ console.log(`[Remediation] Rolled back ${targetFile} from ${backupPath}`);
639
+ } catch (error) {
640
+ throw new SecurityValidationError(`Rollback failed: ${error instanceof Error ? error.message : String(error)}`);
641
+ }
642
+ }
643
+
644
+ /**
645
+ * Clean up old backups
646
+ */
647
+ async cleanupBackups(maxAge: number = 7 * 24 * 60 * 60 * 1000): Promise<void> {
648
+ try {
649
+ const files = await fs.readdir(this.backupDirectory);
650
+ const now = Date.now();
651
+
652
+ for (const file of files) {
653
+ const filePath = path.join(this.backupDirectory, file);
654
+ const stats = await fs.stat(filePath);
655
+
656
+ if (now - stats.mtime.getTime() > maxAge) {
657
+ await fs.unlink(filePath);
658
+ console.log(`[Remediation] Cleaned up old backup: ${file}`);
659
+ }
660
+ }
661
+ } catch (error) {
662
+ console.warn("[Remediation] Backup cleanup failed:", error);
663
+ }
664
+ }
665
+ }