defense-mcp-server 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/build/core/auto-installer.js +31 -31
  2. package/build/core/command-allowlist.js +1 -1
  3. package/build/core/dependency-validator.js +9 -9
  4. package/build/core/distro-adapter.js +0 -7
  5. package/build/core/distro.js +0 -48
  6. package/build/core/encrypted-state.js +0 -7
  7. package/build/core/logger.js +1 -1
  8. package/build/core/pam-utils.js +1 -1
  9. package/build/core/parsers.js +1 -1
  10. package/build/core/preflight.js +13 -13
  11. package/build/core/progress.js +20 -20
  12. package/build/core/run-command.js +46 -0
  13. package/build/core/sudo-guard.js +4 -4
  14. package/build/core/third-party-installer.js +4 -4
  15. package/build/core/tool-wrapper.js +3 -3
  16. package/build/tools/access-control.js +6 -6
  17. package/build/tools/api-security.js +5 -51
  18. package/build/tools/app-hardening.js +23 -25
  19. package/build/tools/cloud-security.js +5 -51
  20. package/build/tools/compliance.js +9 -13
  21. package/build/tools/container-security.js +51 -52
  22. package/build/tools/deception.js +8 -54
  23. package/build/tools/dns-security.js +2 -48
  24. package/build/tools/encryption.js +86 -87
  25. package/build/tools/firewall.js +324 -30
  26. package/build/tools/hardening.js +12 -13
  27. package/build/tools/incident-response.js +3 -3
  28. package/build/tools/logging.js +17 -59
  29. package/build/tools/malware.js +2 -2
  30. package/build/tools/meta.js +86 -165
  31. package/build/tools/network-defense.js +3 -3
  32. package/build/tools/patch-management.js +8 -8
  33. package/build/tools/process-security.js +38 -92
  34. package/build/tools/sudo-management.js +36 -36
  35. package/build/tools/threat-intel.js +2 -48
  36. package/build/tools/vulnerability-management.js +3 -49
  37. package/build/tools/waf.js +47 -93
  38. package/build/tools/wireless-security.js +9 -55
  39. package/package.json +5 -3
  40. package/build/core/auto-installer.d.ts +0 -102
  41. package/build/core/auto-installer.d.ts.map +0 -1
  42. package/build/core/backup-manager.d.ts +0 -63
  43. package/build/core/backup-manager.d.ts.map +0 -1
  44. package/build/core/changelog.d.ts +0 -119
  45. package/build/core/changelog.d.ts.map +0 -1
  46. package/build/core/command-allowlist.d.ts +0 -129
  47. package/build/core/command-allowlist.d.ts.map +0 -1
  48. package/build/core/config.d.ts +0 -107
  49. package/build/core/config.d.ts.map +0 -1
  50. package/build/core/dependency-validator.d.ts +0 -106
  51. package/build/core/dependency-validator.d.ts.map +0 -1
  52. package/build/core/distro-adapter.d.ts +0 -177
  53. package/build/core/distro-adapter.d.ts.map +0 -1
  54. package/build/core/distro.d.ts +0 -68
  55. package/build/core/distro.d.ts.map +0 -1
  56. package/build/core/encrypted-state.d.ts +0 -76
  57. package/build/core/encrypted-state.d.ts.map +0 -1
  58. package/build/core/executor.d.ts +0 -65
  59. package/build/core/executor.d.ts.map +0 -1
  60. package/build/core/installer.d.ts +0 -129
  61. package/build/core/installer.d.ts.map +0 -1
  62. package/build/core/logger.d.ts +0 -118
  63. package/build/core/logger.d.ts.map +0 -1
  64. package/build/core/metrics.d.ts +0 -74
  65. package/build/core/metrics.d.ts.map +0 -1
  66. package/build/core/metrics.js +0 -97
  67. package/build/core/output-redactor.d.ts +0 -26
  68. package/build/core/output-redactor.d.ts.map +0 -1
  69. package/build/core/pam-utils.d.ts +0 -356
  70. package/build/core/pam-utils.d.ts.map +0 -1
  71. package/build/core/parsers.d.ts +0 -191
  72. package/build/core/parsers.d.ts.map +0 -1
  73. package/build/core/policy-engine.d.ts +0 -170
  74. package/build/core/policy-engine.d.ts.map +0 -1
  75. package/build/core/preflight.d.ts +0 -157
  76. package/build/core/preflight.d.ts.map +0 -1
  77. package/build/core/privilege-manager.d.ts +0 -108
  78. package/build/core/privilege-manager.d.ts.map +0 -1
  79. package/build/core/progress.d.ts +0 -99
  80. package/build/core/progress.d.ts.map +0 -1
  81. package/build/core/rate-limiter.d.ts +0 -101
  82. package/build/core/rate-limiter.d.ts.map +0 -1
  83. package/build/core/rollback.d.ts +0 -73
  84. package/build/core/rollback.d.ts.map +0 -1
  85. package/build/core/safeguards.d.ts +0 -58
  86. package/build/core/safeguards.d.ts.map +0 -1
  87. package/build/core/sanitizer.d.ts +0 -118
  88. package/build/core/sanitizer.d.ts.map +0 -1
  89. package/build/core/secure-fs.d.ts +0 -67
  90. package/build/core/secure-fs.d.ts.map +0 -1
  91. package/build/core/spawn-safe.d.ts +0 -55
  92. package/build/core/spawn-safe.d.ts.map +0 -1
  93. package/build/core/sudo-guard.d.ts +0 -167
  94. package/build/core/sudo-guard.d.ts.map +0 -1
  95. package/build/core/sudo-session.d.ts +0 -143
  96. package/build/core/sudo-session.d.ts.map +0 -1
  97. package/build/core/third-party-installer.d.ts +0 -58
  98. package/build/core/third-party-installer.d.ts.map +0 -1
  99. package/build/core/third-party-manifest.d.ts +0 -48
  100. package/build/core/third-party-manifest.d.ts.map +0 -1
  101. package/build/core/tool-annotations.d.ts +0 -13
  102. package/build/core/tool-annotations.d.ts.map +0 -1
  103. package/build/core/tool-dependencies.d.ts +0 -60
  104. package/build/core/tool-dependencies.d.ts.map +0 -1
  105. package/build/core/tool-durations.d.ts +0 -71
  106. package/build/core/tool-durations.d.ts.map +0 -1
  107. package/build/core/tool-registry.d.ts +0 -112
  108. package/build/core/tool-registry.d.ts.map +0 -1
  109. package/build/core/tool-wrapper.d.ts +0 -73
  110. package/build/core/tool-wrapper.d.ts.map +0 -1
  111. package/build/index.d.ts +0 -3
  112. package/build/index.d.ts.map +0 -1
  113. package/build/tools/access-control.d.ts +0 -11
  114. package/build/tools/access-control.d.ts.map +0 -1
  115. package/build/tools/api-security.d.ts +0 -12
  116. package/build/tools/api-security.d.ts.map +0 -1
  117. package/build/tools/app-hardening.d.ts +0 -11
  118. package/build/tools/app-hardening.d.ts.map +0 -1
  119. package/build/tools/backup.d.ts +0 -8
  120. package/build/tools/backup.d.ts.map +0 -1
  121. package/build/tools/cloud-security.d.ts +0 -17
  122. package/build/tools/cloud-security.d.ts.map +0 -1
  123. package/build/tools/compliance.d.ts +0 -11
  124. package/build/tools/compliance.d.ts.map +0 -1
  125. package/build/tools/container-security.d.ts +0 -14
  126. package/build/tools/container-security.d.ts.map +0 -1
  127. package/build/tools/deception.d.ts +0 -13
  128. package/build/tools/deception.d.ts.map +0 -1
  129. package/build/tools/dns-security.d.ts +0 -93
  130. package/build/tools/dns-security.d.ts.map +0 -1
  131. package/build/tools/ebpf-security.d.ts +0 -15
  132. package/build/tools/ebpf-security.d.ts.map +0 -1
  133. package/build/tools/encryption.d.ts +0 -12
  134. package/build/tools/encryption.d.ts.map +0 -1
  135. package/build/tools/firewall.d.ts +0 -9
  136. package/build/tools/firewall.d.ts.map +0 -1
  137. package/build/tools/hardening.d.ts +0 -8
  138. package/build/tools/hardening.d.ts.map +0 -1
  139. package/build/tools/incident-response.d.ts +0 -11
  140. package/build/tools/incident-response.d.ts.map +0 -1
  141. package/build/tools/integrity.d.ts +0 -15
  142. package/build/tools/integrity.d.ts.map +0 -1
  143. package/build/tools/logging.d.ts +0 -21
  144. package/build/tools/logging.d.ts.map +0 -1
  145. package/build/tools/malware.d.ts +0 -10
  146. package/build/tools/malware.d.ts.map +0 -1
  147. package/build/tools/meta.d.ts +0 -13
  148. package/build/tools/meta.d.ts.map +0 -1
  149. package/build/tools/network-defense.d.ts +0 -11
  150. package/build/tools/network-defense.d.ts.map +0 -1
  151. package/build/tools/patch-management.d.ts +0 -3
  152. package/build/tools/patch-management.d.ts.map +0 -1
  153. package/build/tools/process-security.d.ts +0 -12
  154. package/build/tools/process-security.d.ts.map +0 -1
  155. package/build/tools/secrets.d.ts +0 -8
  156. package/build/tools/secrets.d.ts.map +0 -1
  157. package/build/tools/sudo-management.d.ts +0 -17
  158. package/build/tools/sudo-management.d.ts.map +0 -1
  159. package/build/tools/supply-chain-security.d.ts +0 -8
  160. package/build/tools/supply-chain-security.d.ts.map +0 -1
  161. package/build/tools/threat-intel.d.ts +0 -22
  162. package/build/tools/threat-intel.d.ts.map +0 -1
  163. package/build/tools/vulnerability-management.d.ts +0 -11
  164. package/build/tools/vulnerability-management.d.ts.map +0 -1
  165. package/build/tools/waf.d.ts +0 -12
  166. package/build/tools/waf.d.ts.map +0 -1
  167. package/build/tools/wireless-security.d.ts +0 -19
  168. package/build/tools/wireless-security.d.ts.map +0 -1
  169. package/build/tools/zero-trust-network.d.ts +0 -8
  170. package/build/tools/zero-trust-network.d.ts.map +0 -1
@@ -84,7 +84,7 @@ export function registerSudoManagementTools(server) {
84
84
  const status = session.getStatus();
85
85
  return {
86
86
  content: [
87
- createTextContent(`🔓 Already elevated as '${status.username}'.\n` +
87
+ createTextContent(`Already elevated as '${status.username}'.\n` +
88
88
  `Session expires at: ${status.expiresAt ?? "never"}\n` +
89
89
  `Remaining: ${status.remainingSeconds !== null ? `${status.remainingSeconds}s` : "∞"}\n\n` +
90
90
  `Use sudo_session action=drop to end the current session before re-elevating.`),
@@ -100,7 +100,7 @@ export function registerSudoManagementTools(server) {
100
100
  : "unknown";
101
101
  return {
102
102
  content: [
103
- createErrorContent(`❌ Authentication rate limit exceeded.\n\n` +
103
+ createErrorContent(`Authentication rate limit exceeded.\n\n` +
104
104
  `Too many failed attempts were detected within the last 5 minutes.\n` +
105
105
  `Please wait until ${resetAt} before trying again.\n\n` +
106
106
  `For security, this lockout cannot be bypassed.\n` +
@@ -120,7 +120,7 @@ export function registerSudoManagementTools(server) {
120
120
  invalidatePreflightCaches();
121
121
  const status = session.getStatus();
122
122
  const lines = [
123
- `🔓 Privileges elevated successfully!`,
123
+ `Privileges elevated successfully!`,
124
124
  ``,
125
125
  ` User: ${status.username}`,
126
126
  ` Expires: ${status.expiresAt ?? "never (running as root)"}`,
@@ -142,7 +142,7 @@ export function registerSudoManagementTools(server) {
142
142
  : "unknown";
143
143
  return {
144
144
  content: [
145
- createErrorContent(`❌ Authentication rate limit exceeded.\n\n` +
145
+ createErrorContent(`Authentication rate limit exceeded.\n\n` +
146
146
  `Too many failed attempts. Please wait until ${resetAt} before retrying.\n\n` +
147
147
  `For security, this lockout cannot be bypassed.`),
148
148
  ],
@@ -160,7 +160,7 @@ export function registerSudoManagementTools(server) {
160
160
  : "";
161
161
  return {
162
162
  content: [
163
- createErrorContent(`❌ Authentication failed: ${result.error}\n\n` +
163
+ createErrorContent(`Authentication failed: ${result.error}\n\n` +
164
164
  `${attemptsLine}\n\n` +
165
165
  `Please verify:\n` +
166
166
  ` 1. The password is correct\n` +
@@ -197,7 +197,7 @@ export function registerSudoManagementTools(server) {
197
197
  const status = session.getStatus();
198
198
  return {
199
199
  content: [
200
- createTextContent(`🔓 Already elevated as '${status.username}'.\n` +
200
+ createTextContent(`Already elevated as '${status.username}'.\n` +
201
201
  `Session expires at: ${status.expiresAt ?? "never"}\n` +
202
202
  `Remaining: ${status.remainingSeconds !== null ? `${status.remainingSeconds}s` : "∞"}\n\n` +
203
203
  `Use sudo_session action=drop to end the current session before re-elevating.`),
@@ -212,7 +212,7 @@ export function registerSudoManagementTools(server) {
212
212
  : "unknown";
213
213
  return {
214
214
  content: [
215
- createErrorContent(`❌ Authentication rate limit exceeded.\n\n` +
215
+ createErrorContent(`Authentication rate limit exceeded.\n\n` +
216
216
  `Too many failed attempts. Please wait until ${resetAt} before retrying.`),
217
217
  ],
218
218
  isError: true,
@@ -226,7 +226,7 @@ export function registerSudoManagementTools(server) {
226
226
  if (!hasDisplay) {
227
227
  return {
228
228
  content: [
229
- createErrorContent(`❌ GUI elevation is not available — no graphical session detected.\n\n` +
229
+ createErrorContent(`GUI elevation is not available — no graphical session detected.\n\n` +
230
230
  `Could not find DISPLAY or WAYLAND_DISPLAY in the current process\n` +
231
231
  `or any desktop session process (gnome-shell, plasmashell, etc.).\n\n` +
232
232
  `Use sudo_session action=elevate with your password instead.`),
@@ -239,7 +239,7 @@ export function registerSudoManagementTools(server) {
239
239
  if (!guiTool) {
240
240
  return {
241
241
  content: [
242
- createErrorContent(`❌ No GUI password dialog tool found.\n\n` +
242
+ createErrorContent(`No GUI password dialog tool found.\n\n` +
243
243
  `Install one of: zenity, kdialog, or ssh-askpass\n` +
244
244
  ` sudo apt install zenity # GNOME/GTK\n` +
245
245
  ` sudo apt install kdialog # KDE/Qt\n\n` +
@@ -257,7 +257,7 @@ export function registerSudoManagementTools(server) {
257
257
  if (!password) {
258
258
  return {
259
259
  content: [
260
- createErrorContent(`❌ Password dialog was cancelled or timed out.\n\n` +
260
+ createErrorContent(`Password dialog was cancelled or timed out.\n\n` +
261
261
  `No password was entered. Try again with:\n` +
262
262
  ` sudo_session action=elevate_gui\n\n` +
263
263
  `Or provide your password directly with:\n` +
@@ -278,7 +278,7 @@ export function registerSudoManagementTools(server) {
278
278
  const status = session.getStatus();
279
279
  return {
280
280
  content: [
281
- createTextContent(`🔓 Privileges elevated successfully!\n\n` +
281
+ createTextContent(`Privileges elevated successfully!\n\n` +
282
282
  ` User: ${status.username}\n` +
283
283
  ` Expires: ${status.expiresAt ?? "never (running as root)"}\n` +
284
284
  ` Timeout: ${timeout_minutes} minutes\n` +
@@ -295,7 +295,7 @@ export function registerSudoManagementTools(server) {
295
295
  : `Attempts remaining before lockout: ${rlAfter.attemptsRemaining}`;
296
296
  return {
297
297
  content: [
298
- createErrorContent(`❌ Authentication failed: ${result.error}\n\n` +
298
+ createErrorContent(`Authentication failed: ${result.error}\n\n` +
299
299
  `${attemptsLine}\n\n` +
300
300
  `The password was securely wiped. Please try again.`),
301
301
  ],
@@ -319,7 +319,7 @@ export function registerSudoManagementTools(server) {
319
319
  if (!status.elevated) {
320
320
  const rlLines = [];
321
321
  if (rl.limited) {
322
- rlLines.push(` ⚠️ Rate limit ACTIVE — elevation blocked`);
322
+ rlLines.push(` WARNING: Rate limit ACTIVE — elevation blocked`);
323
323
  rlLines.push(` Unlocks at: ${rl.resetAt ? new Date(rl.resetAt).toLocaleTimeString() : "unknown"}`);
324
324
  }
325
325
  else {
@@ -327,7 +327,7 @@ export function registerSudoManagementTools(server) {
327
327
  }
328
328
  return {
329
329
  content: [
330
- createTextContent(`🔒 Not elevated — sudo credentials are not cached.\n\n` +
330
+ createTextContent(`Not elevated — sudo credentials are not cached.\n\n` +
331
331
  rlLines.join("\n") + "\n\n" +
332
332
  `Use sudo_session action=elevate to provide your password and enable\n` +
333
333
  `transparent sudo for all defensive security tools.`),
@@ -335,8 +335,8 @@ export function registerSudoManagementTools(server) {
335
335
  };
336
336
  }
337
337
  const sections = [];
338
- sections.push("🔓 Sudo Session Active");
339
- sections.push("".repeat(40));
338
+ sections.push("Sudo Session Active");
339
+ sections.push("");
340
340
  sections.push(` User: ${status.username}`);
341
341
  sections.push(` Expires: ${status.expiresAt ?? "never (root)"}`);
342
342
  sections.push(` Auth method: password (sudo -S)`);
@@ -345,7 +345,7 @@ export function registerSudoManagementTools(server) {
345
345
  const secs = status.remainingSeconds % 60;
346
346
  sections.push(` Remaining: ${mins}m ${secs}s`);
347
347
  if (status.remainingSeconds < 120) {
348
- sections.push(`\n ⚠️ Session expiring soon! Use sudo_session action=extend to continue.`);
348
+ sections.push(`\n Session expiring soon! Use sudo_session action=extend to continue.`);
349
349
  }
350
350
  }
351
351
  else {
@@ -374,7 +374,7 @@ export function registerSudoManagementTools(server) {
374
374
  if (wasElevated) {
375
375
  return {
376
376
  content: [
377
- createTextContent(`🔒 Privileges dropped successfully.\n\n` +
377
+ createTextContent(`Privileges dropped successfully.\n\n` +
378
378
  ` Previous user: ${prevStatus.username}\n` +
379
379
  ` Password buffer: zeroed\n` +
380
380
  ` System sudo cache: invalidated\n\n` +
@@ -384,7 +384,7 @@ export function registerSudoManagementTools(server) {
384
384
  }
385
385
  return {
386
386
  content: [
387
- createTextContent(`🔒 No active sudo session to drop.\n` +
387
+ createTextContent(`No active sudo session to drop.\n` +
388
388
  `The system is already in an unprivileged state.`),
389
389
  ],
390
390
  };
@@ -405,7 +405,7 @@ export function registerSudoManagementTools(server) {
405
405
  if (!session.isElevated()) {
406
406
  return {
407
407
  content: [
408
- createErrorContent(`🔒 No active sudo session to extend.\n\n` +
408
+ createErrorContent(`No active sudo session to extend.\n\n` +
409
409
  `Use sudo_session action=elevate to provide your password and start a session first.`),
410
410
  ],
411
411
  isError: true,
@@ -428,7 +428,7 @@ export function registerSudoManagementTools(server) {
428
428
  const status = session.getStatus();
429
429
  return {
430
430
  content: [
431
- createTextContent(`🔓 Session extended by ${minutes} minutes.\n\n` +
431
+ createTextContent(`Session extended by ${minutes} minutes.\n\n` +
432
432
  ` User: ${status.username}\n` +
433
433
  ` New expiry: ${status.expiresAt ?? "never (root)"}\n` +
434
434
  ` Remaining: ${status.remainingSeconds !== null ? `${Math.floor(status.remainingSeconds / 60)}m ${status.remainingSeconds % 60}s` : "∞"}`),
@@ -501,26 +501,26 @@ export function registerSudoManagementTools(server) {
501
501
  const otherFails = results.filter((r) => !r.ready && !r.needsSudo && r.missingDeps.length === 0);
502
502
  // Build report
503
503
  const lines = [];
504
- lines.push("🔍 Pre-flight Batch Check Results");
505
- lines.push("".repeat(50));
504
+ lines.push("Pre-flight Batch Check Results");
505
+ lines.push("");
506
506
  lines.push(`Checked: ${toolNames.length} tools`);
507
- lines.push(` Ready: ${ready.length}`);
508
- lines.push(` 🔒 Need sudo: ${needSudo.length}`);
509
- lines.push(` 📦 Missing deps: ${needDeps.length}`);
507
+ lines.push(` Ready: ${ready.length}`);
508
+ lines.push(` Need sudo: ${needSudo.length}`);
509
+ lines.push(` Missing deps: ${needDeps.length}`);
510
510
  if (otherFails.length > 0) {
511
- lines.push(` Other issues: ${otherFails.length}`);
511
+ lines.push(` Other issues: ${otherFails.length}`);
512
512
  }
513
513
  // Section: Tools that need sudo elevation
514
514
  if (needSudo.length > 0) {
515
515
  lines.push("");
516
- lines.push("🛑 SUDO ELEVATION REQUIRED");
517
- lines.push("".repeat(50));
516
+ lines.push("SUDO ELEVATION REQUIRED");
517
+ lines.push("");
518
518
  lines.push("The following tools need sudo privileges.");
519
519
  lines.push("Call sudo_session action=elevate with the user's password BEFORE");
520
520
  lines.push("executing any of these tools:");
521
521
  lines.push("");
522
522
  for (const r of needSudo) {
523
- lines.push(` 🔒 ${r.tool}`);
523
+ lines.push(` ${r.tool}`);
524
524
  if (r.sudoReason) {
525
525
  lines.push(` Reason: ${r.sudoReason}`);
526
526
  }
@@ -532,10 +532,10 @@ export function registerSudoManagementTools(server) {
532
532
  // Section: Missing dependencies
533
533
  if (needDeps.length > 0) {
534
534
  lines.push("");
535
- lines.push("📦 MISSING DEPENDENCIES");
536
- lines.push("".repeat(50));
535
+ lines.push("MISSING DEPENDENCIES");
536
+ lines.push("");
537
537
  for (const r of needDeps) {
538
- lines.push(` ${r.tool}`);
538
+ lines.push(` ${r.tool}`);
539
539
  for (const dep of r.missingDeps) {
540
540
  lines.push(` Missing: ${dep}`);
541
541
  }
@@ -547,10 +547,10 @@ export function registerSudoManagementTools(server) {
547
547
  // Section: Ready tools
548
548
  if (ready.length > 0) {
549
549
  lines.push("");
550
- lines.push("READY TO EXECUTE");
551
- lines.push("".repeat(50));
550
+ lines.push("READY TO EXECUTE");
551
+ lines.push("");
552
552
  for (const r of ready) {
553
- lines.push(` ${r.tool}`);
553
+ lines.push(` ${r.tool}`);
554
554
  }
555
555
  }
556
556
  // Build machine-readable metadata
@@ -8,7 +8,7 @@
8
8
  * feeds, feed management, and blocklist application to iptables/fail2ban/hosts.
9
9
  */
10
10
  import { z } from "zod";
11
- import { spawnSafe } from "../core/spawn-safe.js";
11
+ import { runCommand } from "../core/run-command.js";
12
12
  import { createTextContent, createErrorContent, formatToolOutput, } from "../core/parsers.js";
13
13
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
14
14
  // ── Constants ──────────────────────────────────────────────────────────────────
@@ -26,53 +26,7 @@ const MAX_BATCH_SIZE = 1000;
26
26
  const SINKHOLE_IPS = new Set(["0.0.0.0", "127.0.0.1"]);
27
27
  /** Basic IPv4 regex for validation */
28
28
  const IPV4_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
29
- /**
30
- * Run a command via spawnSafe and collect output as a promise.
31
- * Handles errors gracefully — returns error info instead of throwing.
32
- */
33
- async function runCommand(command, args, timeoutMs = 30_000) {
34
- return new Promise((resolve) => {
35
- let child;
36
- try {
37
- child = spawnSafe(command, args);
38
- }
39
- catch (err) {
40
- const msg = err instanceof Error ? err.message : String(err);
41
- resolve({ stdout: "", stderr: msg, exitCode: -1 });
42
- return;
43
- }
44
- let stdout = "";
45
- let stderr = "";
46
- let resolved = false;
47
- const timer = setTimeout(() => {
48
- if (!resolved) {
49
- resolved = true;
50
- child.kill("SIGTERM");
51
- resolve({ stdout, stderr: stderr + "\n[TIMEOUT]", exitCode: -1 });
52
- }
53
- }, timeoutMs);
54
- child.stdout?.on("data", (data) => {
55
- stdout += data.toString();
56
- });
57
- child.stderr?.on("data", (data) => {
58
- stderr += data.toString();
59
- });
60
- child.on("close", (code) => {
61
- if (!resolved) {
62
- resolved = true;
63
- clearTimeout(timer);
64
- resolve({ stdout, stderr, exitCode: code ?? -1 });
65
- }
66
- });
67
- child.on("error", (err) => {
68
- if (!resolved) {
69
- resolved = true;
70
- clearTimeout(timer);
71
- resolve({ stdout, stderr: err.message, exitCode: -1 });
72
- }
73
- });
74
- });
75
- }
29
+ // ── Helpers ────────────────────────────────────────────────────────────────────
76
30
  // ── Validation ─────────────────────────────────────────────────────────────────
77
31
  /**
78
32
  * Validate an IPv4 address.
@@ -7,59 +7,13 @@
7
7
  * using nmap, nikto, and searchsploit.
8
8
  */
9
9
  import { z } from "zod";
10
- import { spawnSafe } from "../core/spawn-safe.js";
10
+ import { runCommand } from "../core/run-command.js";
11
11
  import { secureWriteFileSync } from "../core/secure-fs.js";
12
12
  import { createTextContent, createErrorContent, formatToolOutput, } from "../core/parsers.js";
13
13
  import { existsSync, readFileSync } from "node:fs";
14
14
  // ── Constants ──────────────────────────────────────────────────────────────────
15
15
  const VULN_TRACKER_PATH = "/var/lib/defense-mcp/vuln-tracker.json";
16
- /**
17
- * Run a command via spawnSafe and collect output as a promise.
18
- * Handles errors gracefully — returns error info instead of throwing.
19
- */
20
- async function runCommand(command, args, timeoutMs = 60_000) {
21
- return new Promise((resolve) => {
22
- let child;
23
- try {
24
- child = spawnSafe(command, args);
25
- }
26
- catch (err) {
27
- const msg = err instanceof Error ? err.message : String(err);
28
- resolve({ stdout: "", stderr: msg, exitCode: -1 });
29
- return;
30
- }
31
- let stdout = "";
32
- let stderr = "";
33
- let resolved = false;
34
- const timer = setTimeout(() => {
35
- if (!resolved) {
36
- resolved = true;
37
- child.kill("SIGTERM");
38
- resolve({ stdout, stderr: stderr + "\n[TIMEOUT]", exitCode: -1 });
39
- }
40
- }, timeoutMs);
41
- child.stdout?.on("data", (data) => {
42
- stdout += data.toString();
43
- });
44
- child.stderr?.on("data", (data) => {
45
- stderr += data.toString();
46
- });
47
- child.on("close", (code) => {
48
- if (!resolved) {
49
- resolved = true;
50
- clearTimeout(timer);
51
- resolve({ stdout, stderr, exitCode: code ?? -1 });
52
- }
53
- });
54
- child.on("error", (err) => {
55
- if (!resolved) {
56
- resolved = true;
57
- clearTimeout(timer);
58
- resolve({ stdout, stderr: err.message, exitCode: -1 });
59
- }
60
- });
61
- });
62
- }
16
+ // ── Helpers ────────────────────────────────────────────────────────────────────
63
17
  /**
64
18
  * Load the vulnerability tracker database from disk.
65
19
  */
@@ -551,7 +505,7 @@ export function registerVulnerabilityManagementTools(server) {
551
505
  .map((v, i) => `${i + 1}. [${v.severity.toUpperCase()}] ${v.vuln_id} (score: ${v.priority_score})\n` +
552
506
  ` ${v.description}\n` +
553
507
  ` Action: ${v.recommended_action}` +
554
- (v.exploit_available ? "\n EXPLOIT AVAILABLE" : ""))
508
+ (v.exploit_available ? "\n WARNING: EXPLOIT AVAILABLE" : ""))
555
509
  .join("\n\n"))],
556
510
  };
557
511
  }