defense-mcp-server 0.6.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 (186) hide show
  1. package/CHANGELOG.md +471 -0
  2. package/LICENSE +21 -0
  3. package/README.md +242 -0
  4. package/build/core/auto-installer.d.ts +102 -0
  5. package/build/core/auto-installer.d.ts.map +1 -0
  6. package/build/core/auto-installer.js +833 -0
  7. package/build/core/backup-manager.d.ts +63 -0
  8. package/build/core/backup-manager.d.ts.map +1 -0
  9. package/build/core/backup-manager.js +189 -0
  10. package/build/core/changelog.d.ts +75 -0
  11. package/build/core/changelog.d.ts.map +1 -0
  12. package/build/core/changelog.js +123 -0
  13. package/build/core/command-allowlist.d.ts +129 -0
  14. package/build/core/command-allowlist.d.ts.map +1 -0
  15. package/build/core/command-allowlist.js +849 -0
  16. package/build/core/config.d.ts +79 -0
  17. package/build/core/config.d.ts.map +1 -0
  18. package/build/core/config.js +193 -0
  19. package/build/core/dependency-validator.d.ts +106 -0
  20. package/build/core/dependency-validator.d.ts.map +1 -0
  21. package/build/core/dependency-validator.js +405 -0
  22. package/build/core/distro-adapter.d.ts +177 -0
  23. package/build/core/distro-adapter.d.ts.map +1 -0
  24. package/build/core/distro-adapter.js +481 -0
  25. package/build/core/distro.d.ts +68 -0
  26. package/build/core/distro.d.ts.map +1 -0
  27. package/build/core/distro.js +457 -0
  28. package/build/core/encrypted-state.d.ts +76 -0
  29. package/build/core/encrypted-state.d.ts.map +1 -0
  30. package/build/core/encrypted-state.js +209 -0
  31. package/build/core/executor.d.ts +56 -0
  32. package/build/core/executor.d.ts.map +1 -0
  33. package/build/core/executor.js +350 -0
  34. package/build/core/installer.d.ts +92 -0
  35. package/build/core/installer.d.ts.map +1 -0
  36. package/build/core/installer.js +1072 -0
  37. package/build/core/logger.d.ts +102 -0
  38. package/build/core/logger.d.ts.map +1 -0
  39. package/build/core/logger.js +132 -0
  40. package/build/core/parsers.d.ts +151 -0
  41. package/build/core/parsers.d.ts.map +1 -0
  42. package/build/core/parsers.js +479 -0
  43. package/build/core/policy-engine.d.ts +170 -0
  44. package/build/core/policy-engine.d.ts.map +1 -0
  45. package/build/core/policy-engine.js +656 -0
  46. package/build/core/preflight.d.ts +157 -0
  47. package/build/core/preflight.d.ts.map +1 -0
  48. package/build/core/preflight.js +638 -0
  49. package/build/core/privilege-manager.d.ts +108 -0
  50. package/build/core/privilege-manager.d.ts.map +1 -0
  51. package/build/core/privilege-manager.js +363 -0
  52. package/build/core/rate-limiter.d.ts +67 -0
  53. package/build/core/rate-limiter.d.ts.map +1 -0
  54. package/build/core/rate-limiter.js +129 -0
  55. package/build/core/rollback.d.ts +73 -0
  56. package/build/core/rollback.d.ts.map +1 -0
  57. package/build/core/rollback.js +278 -0
  58. package/build/core/safeguards.d.ts +58 -0
  59. package/build/core/safeguards.d.ts.map +1 -0
  60. package/build/core/safeguards.js +448 -0
  61. package/build/core/sanitizer.d.ts +118 -0
  62. package/build/core/sanitizer.d.ts.map +1 -0
  63. package/build/core/sanitizer.js +459 -0
  64. package/build/core/secure-fs.d.ts +67 -0
  65. package/build/core/secure-fs.d.ts.map +1 -0
  66. package/build/core/secure-fs.js +143 -0
  67. package/build/core/spawn-safe.d.ts +55 -0
  68. package/build/core/spawn-safe.d.ts.map +1 -0
  69. package/build/core/spawn-safe.js +146 -0
  70. package/build/core/sudo-guard.d.ts +145 -0
  71. package/build/core/sudo-guard.d.ts.map +1 -0
  72. package/build/core/sudo-guard.js +349 -0
  73. package/build/core/sudo-session.d.ts +100 -0
  74. package/build/core/sudo-session.d.ts.map +1 -0
  75. package/build/core/sudo-session.js +319 -0
  76. package/build/core/tool-dependencies.d.ts +61 -0
  77. package/build/core/tool-dependencies.d.ts.map +1 -0
  78. package/build/core/tool-dependencies.js +571 -0
  79. package/build/core/tool-registry.d.ts +111 -0
  80. package/build/core/tool-registry.d.ts.map +1 -0
  81. package/build/core/tool-registry.js +656 -0
  82. package/build/core/tool-wrapper.d.ts +73 -0
  83. package/build/core/tool-wrapper.d.ts.map +1 -0
  84. package/build/core/tool-wrapper.js +296 -0
  85. package/build/index.d.ts +3 -0
  86. package/build/index.d.ts.map +1 -0
  87. package/build/index.js +247 -0
  88. package/build/tools/access-control.d.ts +9 -0
  89. package/build/tools/access-control.d.ts.map +1 -0
  90. package/build/tools/access-control.js +1818 -0
  91. package/build/tools/api-security.d.ts +12 -0
  92. package/build/tools/api-security.d.ts.map +1 -0
  93. package/build/tools/api-security.js +901 -0
  94. package/build/tools/app-hardening.d.ts +11 -0
  95. package/build/tools/app-hardening.d.ts.map +1 -0
  96. package/build/tools/app-hardening.js +768 -0
  97. package/build/tools/backup.d.ts +8 -0
  98. package/build/tools/backup.d.ts.map +1 -0
  99. package/build/tools/backup.js +381 -0
  100. package/build/tools/cloud-security.d.ts +17 -0
  101. package/build/tools/cloud-security.d.ts.map +1 -0
  102. package/build/tools/cloud-security.js +739 -0
  103. package/build/tools/compliance.d.ts +10 -0
  104. package/build/tools/compliance.d.ts.map +1 -0
  105. package/build/tools/compliance.js +1225 -0
  106. package/build/tools/container-security.d.ts +14 -0
  107. package/build/tools/container-security.d.ts.map +1 -0
  108. package/build/tools/container-security.js +788 -0
  109. package/build/tools/deception.d.ts +13 -0
  110. package/build/tools/deception.d.ts.map +1 -0
  111. package/build/tools/deception.js +763 -0
  112. package/build/tools/dns-security.d.ts +93 -0
  113. package/build/tools/dns-security.d.ts.map +1 -0
  114. package/build/tools/dns-security.js +745 -0
  115. package/build/tools/drift-detection.d.ts +8 -0
  116. package/build/tools/drift-detection.d.ts.map +1 -0
  117. package/build/tools/drift-detection.js +326 -0
  118. package/build/tools/ebpf-security.d.ts +15 -0
  119. package/build/tools/ebpf-security.d.ts.map +1 -0
  120. package/build/tools/ebpf-security.js +294 -0
  121. package/build/tools/encryption.d.ts +9 -0
  122. package/build/tools/encryption.d.ts.map +1 -0
  123. package/build/tools/encryption.js +1667 -0
  124. package/build/tools/firewall.d.ts +9 -0
  125. package/build/tools/firewall.d.ts.map +1 -0
  126. package/build/tools/firewall.js +1398 -0
  127. package/build/tools/hardening.d.ts +10 -0
  128. package/build/tools/hardening.d.ts.map +1 -0
  129. package/build/tools/hardening.js +2654 -0
  130. package/build/tools/ids.d.ts +9 -0
  131. package/build/tools/ids.d.ts.map +1 -0
  132. package/build/tools/ids.js +624 -0
  133. package/build/tools/incident-response.d.ts +10 -0
  134. package/build/tools/incident-response.d.ts.map +1 -0
  135. package/build/tools/incident-response.js +1180 -0
  136. package/build/tools/logging.d.ts +12 -0
  137. package/build/tools/logging.d.ts.map +1 -0
  138. package/build/tools/logging.js +454 -0
  139. package/build/tools/malware.d.ts +10 -0
  140. package/build/tools/malware.d.ts.map +1 -0
  141. package/build/tools/malware.js +532 -0
  142. package/build/tools/meta.d.ts +11 -0
  143. package/build/tools/meta.d.ts.map +1 -0
  144. package/build/tools/meta.js +2278 -0
  145. package/build/tools/network-defense.d.ts +12 -0
  146. package/build/tools/network-defense.d.ts.map +1 -0
  147. package/build/tools/network-defense.js +760 -0
  148. package/build/tools/patch-management.d.ts +3 -0
  149. package/build/tools/patch-management.d.ts.map +1 -0
  150. package/build/tools/patch-management.js +708 -0
  151. package/build/tools/process-security.d.ts +12 -0
  152. package/build/tools/process-security.d.ts.map +1 -0
  153. package/build/tools/process-security.js +784 -0
  154. package/build/tools/reporting.d.ts +11 -0
  155. package/build/tools/reporting.d.ts.map +1 -0
  156. package/build/tools/reporting.js +559 -0
  157. package/build/tools/secrets.d.ts +9 -0
  158. package/build/tools/secrets.d.ts.map +1 -0
  159. package/build/tools/secrets.js +596 -0
  160. package/build/tools/siem-integration.d.ts +18 -0
  161. package/build/tools/siem-integration.d.ts.map +1 -0
  162. package/build/tools/siem-integration.js +754 -0
  163. package/build/tools/sudo-management.d.ts +18 -0
  164. package/build/tools/sudo-management.d.ts.map +1 -0
  165. package/build/tools/sudo-management.js +737 -0
  166. package/build/tools/supply-chain-security.d.ts +8 -0
  167. package/build/tools/supply-chain-security.d.ts.map +1 -0
  168. package/build/tools/supply-chain-security.js +256 -0
  169. package/build/tools/threat-intel.d.ts +22 -0
  170. package/build/tools/threat-intel.d.ts.map +1 -0
  171. package/build/tools/threat-intel.js +749 -0
  172. package/build/tools/vulnerability-management.d.ts +11 -0
  173. package/build/tools/vulnerability-management.d.ts.map +1 -0
  174. package/build/tools/vulnerability-management.js +667 -0
  175. package/build/tools/waf.d.ts +12 -0
  176. package/build/tools/waf.d.ts.map +1 -0
  177. package/build/tools/waf.js +843 -0
  178. package/build/tools/wireless-security.d.ts +19 -0
  179. package/build/tools/wireless-security.d.ts.map +1 -0
  180. package/build/tools/wireless-security.js +826 -0
  181. package/build/tools/zero-trust-network.d.ts +8 -0
  182. package/build/tools/zero-trust-network.d.ts.map +1 -0
  183. package/build/tools/zero-trust-network.js +367 -0
  184. package/docs/SAFEGUARDS.md +518 -0
  185. package/docs/TOOLS-REFERENCE.md +665 -0
  186. package/package.json +87 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Reporting tools for Kali Defense MCP Server.
3
+ *
4
+ * Registers 1 tool: report_export (actions: generate, list_reports, formats)
5
+ *
6
+ * Generates consolidated security reports by collecting system audit data
7
+ * from multiple sources and formatting into structured output.
8
+ */
9
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ export declare function registerReportingTools(server: McpServer): void;
11
+ //# sourceMappingURL=reporting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporting.d.ts","sourceRoot":"","sources":["../../src/tools/reporting.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqbpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4Q9D"}
@@ -0,0 +1,559 @@
1
+ /**
2
+ * Reporting tools for Kali Defense MCP Server.
3
+ *
4
+ * Registers 1 tool: report_export (actions: generate, list_reports, formats)
5
+ *
6
+ * Generates consolidated security reports by collecting system audit data
7
+ * from multiple sources and formatting into structured output.
8
+ */
9
+ import { z } from "zod";
10
+ import { spawnSafe } from "../core/spawn-safe.js";
11
+ import { secureWriteFileSync } from "../core/secure-fs.js";
12
+ import { createTextContent, createErrorContent, formatToolOutput, } from "../core/parsers.js";
13
+ import { existsSync, readdirSync, statSync } from "node:fs";
14
+ // ── Constants ──────────────────────────────────────────────────────────────────
15
+ const DEFAULT_REPORT_DIR = "/var/lib/kali-defense/reports";
16
+ const SUPPORTED_FORMATS = [
17
+ { format: "markdown", description: "Markdown-formatted report with headers and code blocks", extension: ".md" },
18
+ { format: "html", description: "HTML report suitable for browser viewing", extension: ".html" },
19
+ { format: "json", description: "Structured JSON report for programmatic consumption", extension: ".json" },
20
+ { format: "csv", description: "CSV-formatted summary data for spreadsheet import", extension: ".csv" },
21
+ ];
22
+ const REPORT_TYPES = [
23
+ { type: "executive_summary", description: "High-level security posture overview for leadership" },
24
+ { type: "technical_detail", description: "Detailed technical findings with command output" },
25
+ { type: "compliance_evidence", description: "Evidence collection for compliance audits" },
26
+ { type: "vulnerability_report", description: "Identified vulnerabilities and remediation steps" },
27
+ { type: "hardening_status", description: "Current system hardening status and recommendations" },
28
+ ];
29
+ const ALL_SECTIONS = [
30
+ "system_overview",
31
+ "firewall_status",
32
+ "service_audit",
33
+ "active_connections",
34
+ "recent_logins",
35
+ "compliance_summary",
36
+ "recommendations",
37
+ ];
38
+ /**
39
+ * Run a command via spawnSafe and collect output as a promise.
40
+ * Handles errors gracefully — returns error info instead of throwing.
41
+ */
42
+ async function runCommand(command, args, timeoutMs = 30_000) {
43
+ return new Promise((resolve) => {
44
+ let child;
45
+ try {
46
+ child = spawnSafe(command, args);
47
+ }
48
+ catch (err) {
49
+ const msg = err instanceof Error ? err.message : String(err);
50
+ resolve({ stdout: "", stderr: msg, exitCode: -1 });
51
+ return;
52
+ }
53
+ let stdout = "";
54
+ let stderr = "";
55
+ let resolved = false;
56
+ const timer = setTimeout(() => {
57
+ if (!resolved) {
58
+ resolved = true;
59
+ child.kill("SIGTERM");
60
+ resolve({ stdout, stderr: stderr + "\n[TIMEOUT]", exitCode: -1 });
61
+ }
62
+ }, timeoutMs);
63
+ child.stdout?.on("data", (data) => {
64
+ stdout += data.toString();
65
+ });
66
+ child.stderr?.on("data", (data) => {
67
+ stderr += data.toString();
68
+ });
69
+ child.on("close", (code) => {
70
+ if (!resolved) {
71
+ resolved = true;
72
+ clearTimeout(timer);
73
+ resolve({ stdout, stderr, exitCode: code ?? -1 });
74
+ }
75
+ });
76
+ child.on("error", (err) => {
77
+ if (!resolved) {
78
+ resolved = true;
79
+ clearTimeout(timer);
80
+ resolve({ stdout, stderr: err.message, exitCode: -1 });
81
+ }
82
+ });
83
+ });
84
+ }
85
+ /**
86
+ * Run a command via sudo through spawnSafe.
87
+ */
88
+ async function runSudoCommand(command, args, timeoutMs = 30_000) {
89
+ return runCommand("sudo", [command, ...args], timeoutMs);
90
+ }
91
+ async function gatherSystemOverview() {
92
+ const uname = await runCommand("uname", ["-a"]);
93
+ const hostname = await runCommand("hostname", []);
94
+ const uptime = await runCommand("uptime", []);
95
+ let data = "";
96
+ if (uname.exitCode === 0)
97
+ data += `Kernel: ${uname.stdout.trim()}\n`;
98
+ else
99
+ data += `Kernel: [error: ${uname.stderr.trim()}]\n`;
100
+ if (hostname.exitCode === 0)
101
+ data += `Hostname: ${hostname.stdout.trim()}\n`;
102
+ if (uptime.exitCode === 0)
103
+ data += `Uptime: ${uptime.stdout.trim()}\n`;
104
+ return {
105
+ name: "System Overview",
106
+ key: "system_overview",
107
+ data,
108
+ error: uname.exitCode !== 0 ? uname.stderr.trim() : undefined,
109
+ };
110
+ }
111
+ async function gatherFirewallStatus() {
112
+ const iptables = await runSudoCommand("iptables", ["-L", "-n", "--line-numbers"]);
113
+ let data = "";
114
+ if (iptables.exitCode === 0) {
115
+ data = iptables.stdout.trim();
116
+ }
117
+ else {
118
+ data = `[Error gathering firewall rules: ${iptables.stderr.trim()}]`;
119
+ }
120
+ return {
121
+ name: "Firewall Status",
122
+ key: "firewall_status",
123
+ data,
124
+ error: iptables.exitCode !== 0 ? iptables.stderr.trim() : undefined,
125
+ };
126
+ }
127
+ async function gatherServiceAudit() {
128
+ const services = await runCommand("systemctl", [
129
+ "list-units", "--type=service", "--state=running", "--no-pager", "--no-legend",
130
+ ]);
131
+ let data = "";
132
+ if (services.exitCode === 0) {
133
+ data = services.stdout.trim();
134
+ }
135
+ else {
136
+ data = `[Error listing services: ${services.stderr.trim()}]`;
137
+ }
138
+ return {
139
+ name: "Service Audit",
140
+ key: "service_audit",
141
+ data,
142
+ error: services.exitCode !== 0 ? services.stderr.trim() : undefined,
143
+ };
144
+ }
145
+ async function gatherActiveConnections() {
146
+ const ss = await runCommand("ss", ["-tulnp"]);
147
+ let data = "";
148
+ if (ss.exitCode === 0) {
149
+ data = ss.stdout.trim();
150
+ }
151
+ else {
152
+ data = `[Error listing connections: ${ss.stderr.trim()}]`;
153
+ }
154
+ return {
155
+ name: "Active Connections",
156
+ key: "active_connections",
157
+ data,
158
+ error: ss.exitCode !== 0 ? ss.stderr.trim() : undefined,
159
+ };
160
+ }
161
+ async function gatherRecentLogins(since) {
162
+ // Use journalctl to get recent login activity
163
+ const args = ["_COMM=sshd", "-n", "50", "--no-pager"];
164
+ if (since) {
165
+ args.push("--since", since);
166
+ }
167
+ const logins = await runCommand("journalctl", args);
168
+ let data = "";
169
+ if (logins.exitCode === 0 && logins.stdout.trim().length > 0) {
170
+ data = logins.stdout.trim();
171
+ }
172
+ else {
173
+ // Fallback: try grep on auth.log
174
+ const authLog = await runSudoCommand("grep", ["-i", "session opened", "/var/log/auth.log"]);
175
+ if (authLog.exitCode === 0) {
176
+ const lines = authLog.stdout.trim().split("\n");
177
+ data = lines.slice(-20).join("\n");
178
+ }
179
+ else {
180
+ data = "[No login data available]";
181
+ }
182
+ }
183
+ return {
184
+ name: "Recent Logins",
185
+ key: "recent_logins",
186
+ data,
187
+ error: logins.exitCode !== 0 && data === "[No login data available]"
188
+ ? logins.stderr.trim()
189
+ : undefined,
190
+ };
191
+ }
192
+ async function gatherComplianceSummary() {
193
+ // Try to run a quick lynis audit
194
+ const lynis = await runSudoCommand("lynis", ["audit", "system", "--quick", "--no-colors"], 120_000);
195
+ let data = "";
196
+ if (lynis.exitCode === 0 || lynis.stdout.includes("Hardening index")) {
197
+ // Extract hardening index
198
+ const match = lynis.stdout.match(/Hardening index\s*:\s*(\d+)/);
199
+ const index = match ? match[1] : "N/A";
200
+ // Count warnings and suggestions
201
+ const warnings = (lynis.stdout.match(/Warning/g) || []).length;
202
+ const suggestions = (lynis.stdout.match(/Suggestion/g) || []).length;
203
+ data = `Hardening Index: ${index}/100\n`;
204
+ data += `Warnings: ${warnings}\n`;
205
+ data += `Suggestions: ${suggestions}\n`;
206
+ }
207
+ else {
208
+ // Lynis not available — provide basic compliance info
209
+ const aideStatus = await runSudoCommand("aide", ["--check"], 60_000);
210
+ if (aideStatus.exitCode === 0) {
211
+ data += `AIDE Check: PASSED\n${aideStatus.stdout.trim().slice(0, 500)}\n`;
212
+ }
213
+ else {
214
+ data += `AIDE Check: ${aideStatus.exitCode === -1 ? "Not installed" : "FAILED"}\n`;
215
+ }
216
+ const fail2ban = await runSudoCommand("fail2ban-client", ["status"]);
217
+ if (fail2ban.exitCode === 0) {
218
+ data += `\nFail2ban: ${fail2ban.stdout.trim()}\n`;
219
+ }
220
+ else {
221
+ data += `\nFail2ban: Not available\n`;
222
+ }
223
+ }
224
+ return {
225
+ name: "Compliance Summary",
226
+ key: "compliance_summary",
227
+ data: data || "[No compliance data available]",
228
+ };
229
+ }
230
+ function generateRecommendations(sections) {
231
+ const recommendations = [];
232
+ const firewall = sections.find((s) => s.key === "firewall_status");
233
+ if (firewall?.error) {
234
+ recommendations.push("- Configure and enable firewall (iptables/nftables)");
235
+ }
236
+ else if (firewall?.data.includes("ACCEPT") &&
237
+ !firewall.data.includes("DROP")) {
238
+ recommendations.push("- Review firewall policy: consider setting default DROP policy");
239
+ }
240
+ const services = sections.find((s) => s.key === "service_audit");
241
+ if (services?.data) {
242
+ const dangerous = ["telnet", "rsh", "rlogin", "tftp"];
243
+ for (const svc of dangerous) {
244
+ if (services.data.toLowerCase().includes(svc)) {
245
+ recommendations.push(`- Disable insecure service: ${svc}`);
246
+ }
247
+ }
248
+ }
249
+ const connections = sections.find((s) => s.key === "active_connections");
250
+ if (connections?.data) {
251
+ const lineCount = connections.data.split("\n").length;
252
+ if (lineCount > 20) {
253
+ recommendations.push(`- Review ${lineCount} active connections for unnecessary exposure`);
254
+ }
255
+ }
256
+ const compliance = sections.find((s) => s.key === "compliance_summary");
257
+ if (compliance?.data.includes("Not installed") ||
258
+ compliance?.data.includes("Not available")) {
259
+ recommendations.push("- Install security audit tools: lynis, aide, fail2ban");
260
+ }
261
+ if (recommendations.length === 0) {
262
+ recommendations.push("- No critical recommendations at this time");
263
+ recommendations.push("- Continue regular security audits");
264
+ }
265
+ return {
266
+ name: "Recommendations",
267
+ key: "recommendations",
268
+ data: recommendations.join("\n"),
269
+ };
270
+ }
271
+ // ── Format Helpers ─────────────────────────────────────────────────────────────
272
+ function escapeHtml(text) {
273
+ return text
274
+ .replace(/&/g, "&")
275
+ .replace(/</g, "&lt;")
276
+ .replace(/>/g, "&gt;")
277
+ .replace(/"/g, "&quot;");
278
+ }
279
+ function formatAsMarkdown(sections, reportType, timestamp) {
280
+ let md = `# Security Report: ${reportType.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())}\n\n`;
281
+ md += `**Generated:** ${timestamp}\n`;
282
+ md += `**Report Type:** ${reportType}\n\n`;
283
+ md += `---\n\n`;
284
+ for (const section of sections) {
285
+ md += `## ${section.name}\n\n`;
286
+ if (section.error) {
287
+ md += `> ⚠️ Error: ${section.error}\n\n`;
288
+ }
289
+ md += `\`\`\`\n${section.data}\n\`\`\`\n\n`;
290
+ }
291
+ return md;
292
+ }
293
+ function formatAsHtml(sections, reportType, timestamp) {
294
+ let html = `<!DOCTYPE html>\n<html><head><meta charset="utf-8">\n`;
295
+ html += `<title>Security Report: ${escapeHtml(reportType)}</title>\n`;
296
+ html += `<style>body{font-family:sans-serif;max-width:900px;margin:0 auto;padding:20px}`;
297
+ html += `pre{background:#f4f4f4;padding:12px;border-radius:4px;overflow-x:auto}`;
298
+ html += `.warning{color:#c00;font-weight:bold}h1{border-bottom:2px solid #333}`;
299
+ html += `h2{border-bottom:1px solid #ccc;padding-bottom:4px}</style>\n`;
300
+ html += `</head><body>\n`;
301
+ html += `<h1>Security Report: ${escapeHtml(reportType.replace(/_/g, " "))}</h1>\n`;
302
+ html += `<p><strong>Generated:</strong> ${escapeHtml(timestamp)}</p>\n`;
303
+ for (const section of sections) {
304
+ html += `<h2>${escapeHtml(section.name)}</h2>\n`;
305
+ if (section.error) {
306
+ html += `<p class="warning">⚠ Error: ${escapeHtml(section.error)}</p>\n`;
307
+ }
308
+ html += `<pre>${escapeHtml(section.data)}</pre>\n`;
309
+ }
310
+ html += `</body></html>`;
311
+ return html;
312
+ }
313
+ function formatAsJson(sections, reportType, timestamp) {
314
+ const report = {
315
+ reportType,
316
+ generatedAt: timestamp,
317
+ sections: sections.map((s) => ({
318
+ name: s.name,
319
+ key: s.key,
320
+ data: s.data,
321
+ error: s.error || null,
322
+ })),
323
+ };
324
+ return JSON.stringify(report, null, 2);
325
+ }
326
+ function formatAsCsv(sections, _reportType, _timestamp) {
327
+ const lines = [];
328
+ lines.push("Section,Status,Summary");
329
+ for (const section of sections) {
330
+ const status = section.error ? "ERROR" : "OK";
331
+ const summary = section.data
332
+ .split("\n")[0]
333
+ .slice(0, 100)
334
+ .replace(/,/g, ";")
335
+ .replace(/"/g, '""');
336
+ lines.push(`"${section.name}","${status}","${summary}"`);
337
+ }
338
+ return lines.join("\n");
339
+ }
340
+ // ── Registration entry point ───────────────────────────────────────────────
341
+ export function registerReportingTools(server) {
342
+ server.tool("report_export", "Generate, list, or query security reports: consolidated system security data in multiple formats.", {
343
+ action: z
344
+ .enum(["generate", "list_reports", "formats"])
345
+ .describe("Action: generate=create report, list_reports=list saved reports, formats=show available formats"),
346
+ report_type: z
347
+ .enum([
348
+ "executive_summary",
349
+ "technical_detail",
350
+ "compliance_evidence",
351
+ "vulnerability_report",
352
+ "hardening_status",
353
+ ])
354
+ .optional()
355
+ .default("technical_detail")
356
+ .describe("Type of report to generate (used with generate action)"),
357
+ format: z
358
+ .enum(["markdown", "html", "json", "csv"])
359
+ .optional()
360
+ .default("markdown")
361
+ .describe("Output format for the report"),
362
+ output_path: z
363
+ .string()
364
+ .optional()
365
+ .describe("File path to save the report (uses secure-fs for writing)"),
366
+ include_sections: z
367
+ .array(z.string())
368
+ .optional()
369
+ .describe("Specific section names to include (default: all sections)"),
370
+ since: z
371
+ .string()
372
+ .optional()
373
+ .describe("Only include findings since this date (ISO 8601 or journalctl-compatible)"),
374
+ }, async (params) => {
375
+ const { action } = params;
376
+ switch (action) {
377
+ case "generate": {
378
+ const { report_type, format, output_path, include_sections, since, } = params;
379
+ try {
380
+ const timestamp = new Date().toISOString();
381
+ const effectiveReportType = report_type ?? "technical_detail";
382
+ const effectiveFormat = format ?? "markdown";
383
+ const sectionsToInclude = include_sections && include_sections.length > 0
384
+ ? include_sections
385
+ : ALL_SECTIONS;
386
+ // Gather all requested sections (in parallel where safe)
387
+ const sectionPromises = [];
388
+ if (sectionsToInclude.includes("system_overview")) {
389
+ sectionPromises.push(gatherSystemOverview());
390
+ }
391
+ if (sectionsToInclude.includes("firewall_status")) {
392
+ sectionPromises.push(gatherFirewallStatus());
393
+ }
394
+ if (sectionsToInclude.includes("service_audit")) {
395
+ sectionPromises.push(gatherServiceAudit());
396
+ }
397
+ if (sectionsToInclude.includes("active_connections")) {
398
+ sectionPromises.push(gatherActiveConnections());
399
+ }
400
+ if (sectionsToInclude.includes("recent_logins")) {
401
+ sectionPromises.push(gatherRecentLogins(since));
402
+ }
403
+ if (sectionsToInclude.includes("compliance_summary")) {
404
+ sectionPromises.push(gatherComplianceSummary());
405
+ }
406
+ const sections = await Promise.all(sectionPromises);
407
+ // Generate recommendations based on gathered data
408
+ if (sectionsToInclude.includes("recommendations")) {
409
+ sections.push(generateRecommendations(sections));
410
+ }
411
+ // Format output
412
+ let reportContent;
413
+ switch (effectiveFormat) {
414
+ case "html":
415
+ reportContent = formatAsHtml(sections, effectiveReportType, timestamp);
416
+ break;
417
+ case "json":
418
+ reportContent = formatAsJson(sections, effectiveReportType, timestamp);
419
+ break;
420
+ case "csv":
421
+ reportContent = formatAsCsv(sections, effectiveReportType, timestamp);
422
+ break;
423
+ case "markdown":
424
+ default:
425
+ reportContent = formatAsMarkdown(sections, effectiveReportType, timestamp);
426
+ break;
427
+ }
428
+ // Write to file if output_path provided
429
+ if (output_path) {
430
+ try {
431
+ secureWriteFileSync(output_path, reportContent, "utf-8");
432
+ }
433
+ catch (writeErr) {
434
+ const msg = writeErr instanceof Error
435
+ ? writeErr.message
436
+ : String(writeErr);
437
+ return {
438
+ content: [
439
+ createErrorContent(`Report generated but failed to write to ${output_path}: ${msg}`),
440
+ ],
441
+ isError: true,
442
+ };
443
+ }
444
+ }
445
+ // Return the report
446
+ if (effectiveFormat === "json") {
447
+ return {
448
+ content: [
449
+ formatToolOutput({
450
+ reportType: effectiveReportType,
451
+ format: effectiveFormat,
452
+ timestamp,
453
+ savedTo: output_path || null,
454
+ sectionsIncluded: sections.map((s) => s.key),
455
+ report: JSON.parse(reportContent),
456
+ }),
457
+ ],
458
+ };
459
+ }
460
+ const summary = {
461
+ reportType: effectiveReportType,
462
+ format: effectiveFormat,
463
+ timestamp,
464
+ savedTo: output_path || null,
465
+ sectionsIncluded: sections.map((s) => s.key),
466
+ sectionsWithErrors: sections
467
+ .filter((s) => s.error)
468
+ .map((s) => s.key),
469
+ };
470
+ return {
471
+ content: [
472
+ createTextContent(reportContent),
473
+ formatToolOutput(summary),
474
+ ],
475
+ };
476
+ }
477
+ catch (err) {
478
+ const msg = err instanceof Error ? err.message : String(err);
479
+ return {
480
+ content: [
481
+ createErrorContent(`Report generation failed: ${msg}`),
482
+ ],
483
+ isError: true,
484
+ };
485
+ }
486
+ }
487
+ case "list_reports": {
488
+ try {
489
+ if (!existsSync(DEFAULT_REPORT_DIR)) {
490
+ return {
491
+ content: [
492
+ formatToolOutput({
493
+ reportDir: DEFAULT_REPORT_DIR,
494
+ reports: [],
495
+ message: `Report directory ${DEFAULT_REPORT_DIR} does not exist. Generate a report with output_path to create it.`,
496
+ }),
497
+ ],
498
+ };
499
+ }
500
+ const files = readdirSync(DEFAULT_REPORT_DIR);
501
+ const reports = files
502
+ .filter((f) => /\.(md|html|json|csv)$/.test(f))
503
+ .map((f) => {
504
+ const fullPath = `${DEFAULT_REPORT_DIR}/${f}`;
505
+ try {
506
+ const stats = statSync(fullPath);
507
+ return {
508
+ filename: f,
509
+ path: fullPath,
510
+ size: stats.size,
511
+ modified: stats.mtime.toISOString(),
512
+ };
513
+ }
514
+ catch {
515
+ return {
516
+ filename: f,
517
+ path: fullPath,
518
+ size: 0,
519
+ modified: "unknown",
520
+ };
521
+ }
522
+ });
523
+ return {
524
+ content: [
525
+ formatToolOutput({
526
+ reportDir: DEFAULT_REPORT_DIR,
527
+ totalReports: reports.length,
528
+ reports,
529
+ }),
530
+ ],
531
+ };
532
+ }
533
+ catch (err) {
534
+ const msg = err instanceof Error ? err.message : String(err);
535
+ return {
536
+ content: [createErrorContent(`Failed to list reports: ${msg}`)],
537
+ isError: true,
538
+ };
539
+ }
540
+ }
541
+ case "formats": {
542
+ return {
543
+ content: [
544
+ formatToolOutput({
545
+ supportedFormats: SUPPORTED_FORMATS,
546
+ reportTypes: REPORT_TYPES,
547
+ availableSections: ALL_SECTIONS,
548
+ }),
549
+ ],
550
+ };
551
+ }
552
+ default:
553
+ return {
554
+ content: [createErrorContent(`Unknown action: ${action}`)],
555
+ isError: true,
556
+ };
557
+ }
558
+ });
559
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Secrets tools for Kali Defense MCP Server.
3
+ *
4
+ * Registers 4 tools: secrets_scan, secrets_env_audit,
5
+ * secrets_ssh_key_sprawl, scan_git_history.
6
+ */
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ export declare function registerSecretsTools(server: McpServer): void;
9
+ //# sourceMappingURL=secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../src/tools/secrets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6DpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0mB5D"}