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.
- package/CHANGELOG.md +471 -0
- package/LICENSE +21 -0
- package/README.md +242 -0
- package/build/core/auto-installer.d.ts +102 -0
- package/build/core/auto-installer.d.ts.map +1 -0
- package/build/core/auto-installer.js +833 -0
- package/build/core/backup-manager.d.ts +63 -0
- package/build/core/backup-manager.d.ts.map +1 -0
- package/build/core/backup-manager.js +189 -0
- package/build/core/changelog.d.ts +75 -0
- package/build/core/changelog.d.ts.map +1 -0
- package/build/core/changelog.js +123 -0
- package/build/core/command-allowlist.d.ts +129 -0
- package/build/core/command-allowlist.d.ts.map +1 -0
- package/build/core/command-allowlist.js +849 -0
- package/build/core/config.d.ts +79 -0
- package/build/core/config.d.ts.map +1 -0
- package/build/core/config.js +193 -0
- package/build/core/dependency-validator.d.ts +106 -0
- package/build/core/dependency-validator.d.ts.map +1 -0
- package/build/core/dependency-validator.js +405 -0
- package/build/core/distro-adapter.d.ts +177 -0
- package/build/core/distro-adapter.d.ts.map +1 -0
- package/build/core/distro-adapter.js +481 -0
- package/build/core/distro.d.ts +68 -0
- package/build/core/distro.d.ts.map +1 -0
- package/build/core/distro.js +457 -0
- package/build/core/encrypted-state.d.ts +76 -0
- package/build/core/encrypted-state.d.ts.map +1 -0
- package/build/core/encrypted-state.js +209 -0
- package/build/core/executor.d.ts +56 -0
- package/build/core/executor.d.ts.map +1 -0
- package/build/core/executor.js +350 -0
- package/build/core/installer.d.ts +92 -0
- package/build/core/installer.d.ts.map +1 -0
- package/build/core/installer.js +1072 -0
- package/build/core/logger.d.ts +102 -0
- package/build/core/logger.d.ts.map +1 -0
- package/build/core/logger.js +132 -0
- package/build/core/parsers.d.ts +151 -0
- package/build/core/parsers.d.ts.map +1 -0
- package/build/core/parsers.js +479 -0
- package/build/core/policy-engine.d.ts +170 -0
- package/build/core/policy-engine.d.ts.map +1 -0
- package/build/core/policy-engine.js +656 -0
- package/build/core/preflight.d.ts +157 -0
- package/build/core/preflight.d.ts.map +1 -0
- package/build/core/preflight.js +638 -0
- package/build/core/privilege-manager.d.ts +108 -0
- package/build/core/privilege-manager.d.ts.map +1 -0
- package/build/core/privilege-manager.js +363 -0
- package/build/core/rate-limiter.d.ts +67 -0
- package/build/core/rate-limiter.d.ts.map +1 -0
- package/build/core/rate-limiter.js +129 -0
- package/build/core/rollback.d.ts +73 -0
- package/build/core/rollback.d.ts.map +1 -0
- package/build/core/rollback.js +278 -0
- package/build/core/safeguards.d.ts +58 -0
- package/build/core/safeguards.d.ts.map +1 -0
- package/build/core/safeguards.js +448 -0
- package/build/core/sanitizer.d.ts +118 -0
- package/build/core/sanitizer.d.ts.map +1 -0
- package/build/core/sanitizer.js +459 -0
- package/build/core/secure-fs.d.ts +67 -0
- package/build/core/secure-fs.d.ts.map +1 -0
- package/build/core/secure-fs.js +143 -0
- package/build/core/spawn-safe.d.ts +55 -0
- package/build/core/spawn-safe.d.ts.map +1 -0
- package/build/core/spawn-safe.js +146 -0
- package/build/core/sudo-guard.d.ts +145 -0
- package/build/core/sudo-guard.d.ts.map +1 -0
- package/build/core/sudo-guard.js +349 -0
- package/build/core/sudo-session.d.ts +100 -0
- package/build/core/sudo-session.d.ts.map +1 -0
- package/build/core/sudo-session.js +319 -0
- package/build/core/tool-dependencies.d.ts +61 -0
- package/build/core/tool-dependencies.d.ts.map +1 -0
- package/build/core/tool-dependencies.js +571 -0
- package/build/core/tool-registry.d.ts +111 -0
- package/build/core/tool-registry.d.ts.map +1 -0
- package/build/core/tool-registry.js +656 -0
- package/build/core/tool-wrapper.d.ts +73 -0
- package/build/core/tool-wrapper.d.ts.map +1 -0
- package/build/core/tool-wrapper.js +296 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +247 -0
- package/build/tools/access-control.d.ts +9 -0
- package/build/tools/access-control.d.ts.map +1 -0
- package/build/tools/access-control.js +1818 -0
- package/build/tools/api-security.d.ts +12 -0
- package/build/tools/api-security.d.ts.map +1 -0
- package/build/tools/api-security.js +901 -0
- package/build/tools/app-hardening.d.ts +11 -0
- package/build/tools/app-hardening.d.ts.map +1 -0
- package/build/tools/app-hardening.js +768 -0
- package/build/tools/backup.d.ts +8 -0
- package/build/tools/backup.d.ts.map +1 -0
- package/build/tools/backup.js +381 -0
- package/build/tools/cloud-security.d.ts +17 -0
- package/build/tools/cloud-security.d.ts.map +1 -0
- package/build/tools/cloud-security.js +739 -0
- package/build/tools/compliance.d.ts +10 -0
- package/build/tools/compliance.d.ts.map +1 -0
- package/build/tools/compliance.js +1225 -0
- package/build/tools/container-security.d.ts +14 -0
- package/build/tools/container-security.d.ts.map +1 -0
- package/build/tools/container-security.js +788 -0
- package/build/tools/deception.d.ts +13 -0
- package/build/tools/deception.d.ts.map +1 -0
- package/build/tools/deception.js +763 -0
- package/build/tools/dns-security.d.ts +93 -0
- package/build/tools/dns-security.d.ts.map +1 -0
- package/build/tools/dns-security.js +745 -0
- package/build/tools/drift-detection.d.ts +8 -0
- package/build/tools/drift-detection.d.ts.map +1 -0
- package/build/tools/drift-detection.js +326 -0
- package/build/tools/ebpf-security.d.ts +15 -0
- package/build/tools/ebpf-security.d.ts.map +1 -0
- package/build/tools/ebpf-security.js +294 -0
- package/build/tools/encryption.d.ts +9 -0
- package/build/tools/encryption.d.ts.map +1 -0
- package/build/tools/encryption.js +1667 -0
- package/build/tools/firewall.d.ts +9 -0
- package/build/tools/firewall.d.ts.map +1 -0
- package/build/tools/firewall.js +1398 -0
- package/build/tools/hardening.d.ts +10 -0
- package/build/tools/hardening.d.ts.map +1 -0
- package/build/tools/hardening.js +2654 -0
- package/build/tools/ids.d.ts +9 -0
- package/build/tools/ids.d.ts.map +1 -0
- package/build/tools/ids.js +624 -0
- package/build/tools/incident-response.d.ts +10 -0
- package/build/tools/incident-response.d.ts.map +1 -0
- package/build/tools/incident-response.js +1180 -0
- package/build/tools/logging.d.ts +12 -0
- package/build/tools/logging.d.ts.map +1 -0
- package/build/tools/logging.js +454 -0
- package/build/tools/malware.d.ts +10 -0
- package/build/tools/malware.d.ts.map +1 -0
- package/build/tools/malware.js +532 -0
- package/build/tools/meta.d.ts +11 -0
- package/build/tools/meta.d.ts.map +1 -0
- package/build/tools/meta.js +2278 -0
- package/build/tools/network-defense.d.ts +12 -0
- package/build/tools/network-defense.d.ts.map +1 -0
- package/build/tools/network-defense.js +760 -0
- package/build/tools/patch-management.d.ts +3 -0
- package/build/tools/patch-management.d.ts.map +1 -0
- package/build/tools/patch-management.js +708 -0
- package/build/tools/process-security.d.ts +12 -0
- package/build/tools/process-security.d.ts.map +1 -0
- package/build/tools/process-security.js +784 -0
- package/build/tools/reporting.d.ts +11 -0
- package/build/tools/reporting.d.ts.map +1 -0
- package/build/tools/reporting.js +559 -0
- package/build/tools/secrets.d.ts +9 -0
- package/build/tools/secrets.d.ts.map +1 -0
- package/build/tools/secrets.js +596 -0
- package/build/tools/siem-integration.d.ts +18 -0
- package/build/tools/siem-integration.d.ts.map +1 -0
- package/build/tools/siem-integration.js +754 -0
- package/build/tools/sudo-management.d.ts +18 -0
- package/build/tools/sudo-management.d.ts.map +1 -0
- package/build/tools/sudo-management.js +737 -0
- package/build/tools/supply-chain-security.d.ts +8 -0
- package/build/tools/supply-chain-security.d.ts.map +1 -0
- package/build/tools/supply-chain-security.js +256 -0
- package/build/tools/threat-intel.d.ts +22 -0
- package/build/tools/threat-intel.d.ts.map +1 -0
- package/build/tools/threat-intel.js +749 -0
- package/build/tools/vulnerability-management.d.ts +11 -0
- package/build/tools/vulnerability-management.d.ts.map +1 -0
- package/build/tools/vulnerability-management.js +667 -0
- package/build/tools/waf.d.ts +12 -0
- package/build/tools/waf.d.ts.map +1 -0
- package/build/tools/waf.js +843 -0
- package/build/tools/wireless-security.d.ts +19 -0
- package/build/tools/wireless-security.d.ts.map +1 -0
- package/build/tools/wireless-security.js +826 -0
- package/build/tools/zero-trust-network.d.ts +8 -0
- package/build/tools/zero-trust-network.d.ts.map +1 -0
- package/build/tools/zero-trust-network.js +367 -0
- package/docs/SAFEGUARDS.md +518 -0
- package/docs/TOOLS-REFERENCE.md +665 -0
- package/package.json +87 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { executeCommand } from "./executor.js";
|
|
4
|
+
// ── Cache ────────────────────────────────────────────────────────────────────
|
|
5
|
+
let cachedDistro = null;
|
|
6
|
+
// ── Internal helpers ─────────────────────────────────────────────────────────
|
|
7
|
+
function parseOsRelease(content) {
|
|
8
|
+
const result = {};
|
|
9
|
+
for (const line of content.split("\n")) {
|
|
10
|
+
const idx = line.indexOf("=");
|
|
11
|
+
if (idx === -1)
|
|
12
|
+
continue;
|
|
13
|
+
const key = line.substring(0, idx).trim();
|
|
14
|
+
let value = line.substring(idx + 1).trim();
|
|
15
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
16
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
17
|
+
value = value.slice(1, -1);
|
|
18
|
+
}
|
|
19
|
+
result[key] = value;
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
async function binaryExists(name) {
|
|
24
|
+
const result = await executeCommand({ command: "which", args: [name], timeout: 5000 });
|
|
25
|
+
return result.exitCode === 0;
|
|
26
|
+
}
|
|
27
|
+
async function detectWsl() {
|
|
28
|
+
try {
|
|
29
|
+
const content = await readFile("/proc/version", "utf-8");
|
|
30
|
+
return content.toLowerCase().includes("microsoft");
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function idToSpecificDistro(id) {
|
|
37
|
+
const lower = id.toLowerCase().trim();
|
|
38
|
+
if (lower === "debian")
|
|
39
|
+
return "debian";
|
|
40
|
+
if (lower === "ubuntu")
|
|
41
|
+
return "ubuntu";
|
|
42
|
+
if (lower === "kali")
|
|
43
|
+
return "kali";
|
|
44
|
+
if (lower === "fedora")
|
|
45
|
+
return "fedora";
|
|
46
|
+
if (lower === "rhel" || lower === "redhat")
|
|
47
|
+
return "rhel";
|
|
48
|
+
if (lower.startsWith("centos"))
|
|
49
|
+
return "centos";
|
|
50
|
+
if (lower === "arch" || lower === "archlinux")
|
|
51
|
+
return "arch";
|
|
52
|
+
if (lower.startsWith("alpine"))
|
|
53
|
+
return "alpine";
|
|
54
|
+
if (lower.includes("suse") || lower === "sles")
|
|
55
|
+
return "opensuse";
|
|
56
|
+
if (lower === "macos")
|
|
57
|
+
return "macos";
|
|
58
|
+
return "unknown";
|
|
59
|
+
}
|
|
60
|
+
function idToFamily(id) {
|
|
61
|
+
const lower = id.toLowerCase();
|
|
62
|
+
const debianIds = ["debian", "ubuntu", "kali", "linuxmint", "pop", "elementary", "zorin", "mx", "antiX", "parrot", "raspbian"];
|
|
63
|
+
if (debianIds.some((d) => lower.includes(d)))
|
|
64
|
+
return "debian";
|
|
65
|
+
const rhelIds = ["rhel", "centos", "fedora", "rocky", "almalinux", "oracle", "amazon", "redhat"];
|
|
66
|
+
if (rhelIds.some((d) => lower.includes(d)))
|
|
67
|
+
return "rhel";
|
|
68
|
+
if (lower.includes("arch") || lower.includes("manjaro"))
|
|
69
|
+
return "arch";
|
|
70
|
+
if (lower.includes("alpine"))
|
|
71
|
+
return "alpine";
|
|
72
|
+
if (lower.includes("suse") || lower.includes("sles"))
|
|
73
|
+
return "suse";
|
|
74
|
+
return "unknown";
|
|
75
|
+
}
|
|
76
|
+
function familyToPackageManager(family) {
|
|
77
|
+
switch (family) {
|
|
78
|
+
case "debian": return "apt";
|
|
79
|
+
case "rhel": return "dnf";
|
|
80
|
+
case "arch": return "pacman";
|
|
81
|
+
case "alpine": return "apk";
|
|
82
|
+
case "suse": return "zypper";
|
|
83
|
+
default: return "unknown";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ── detectDistro ─────────────────────────────────────────────────────────────
|
|
87
|
+
export async function detectDistro() {
|
|
88
|
+
if (cachedDistro)
|
|
89
|
+
return cachedDistro;
|
|
90
|
+
let id = "unknown";
|
|
91
|
+
let name = "Unknown Linux";
|
|
92
|
+
let version = "unknown";
|
|
93
|
+
let osFamily = "linux";
|
|
94
|
+
// macOS detection
|
|
95
|
+
if (process.platform === "darwin") {
|
|
96
|
+
osFamily = "darwin";
|
|
97
|
+
try {
|
|
98
|
+
const productResult = await executeCommand({ command: "sw_vers", args: ["-productName"], timeout: 5000 });
|
|
99
|
+
const versionResult = await executeCommand({ command: "sw_vers", args: ["-productVersion"], timeout: 5000 });
|
|
100
|
+
if (productResult.exitCode === 0) {
|
|
101
|
+
id = "macos";
|
|
102
|
+
name = productResult.stdout.trim();
|
|
103
|
+
version = versionResult.exitCode === 0 ? versionResult.stdout.trim() : "unknown";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
id = "macos";
|
|
108
|
+
name = "macOS";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// WSL detection
|
|
113
|
+
const isWsl = await detectWsl();
|
|
114
|
+
if (isWsl)
|
|
115
|
+
osFamily = "wsl";
|
|
116
|
+
}
|
|
117
|
+
// /etc/os-release
|
|
118
|
+
if (id === "unknown") {
|
|
119
|
+
try {
|
|
120
|
+
if (existsSync("/etc/os-release")) {
|
|
121
|
+
const content = readFileSync("/etc/os-release", "utf-8");
|
|
122
|
+
const fields = parseOsRelease(content);
|
|
123
|
+
id = fields.ID ?? id;
|
|
124
|
+
name = fields.PRETTY_NAME ?? fields.NAME ?? name;
|
|
125
|
+
version = fields.VERSION_ID ?? fields.VERSION ?? version;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch { /* fallback */ }
|
|
129
|
+
}
|
|
130
|
+
// lsb_release
|
|
131
|
+
if (id === "unknown") {
|
|
132
|
+
try {
|
|
133
|
+
const result = await executeCommand({ command: "lsb_release", args: ["-a"], timeout: 5000 });
|
|
134
|
+
if (result.exitCode === 0) {
|
|
135
|
+
for (const line of result.stdout.split("\n")) {
|
|
136
|
+
if (line.startsWith("Distributor ID:"))
|
|
137
|
+
id = line.split(":")[1]?.trim().toLowerCase() ?? id;
|
|
138
|
+
else if (line.startsWith("Description:"))
|
|
139
|
+
name = line.split(":")[1]?.trim() ?? name;
|
|
140
|
+
else if (line.startsWith("Release:"))
|
|
141
|
+
version = line.split(":")[1]?.trim() ?? version;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch { /* fallback */ }
|
|
146
|
+
}
|
|
147
|
+
// Distro-specific files
|
|
148
|
+
if (id === "unknown") {
|
|
149
|
+
const distroFiles = [
|
|
150
|
+
["/etc/debian_version", "debian"],
|
|
151
|
+
["/etc/redhat-release", "rhel"],
|
|
152
|
+
["/etc/arch-release", "arch"],
|
|
153
|
+
["/etc/alpine-release", "alpine"],
|
|
154
|
+
["/etc/SuSE-release", "suse"],
|
|
155
|
+
];
|
|
156
|
+
for (const [filePath, distroId] of distroFiles) {
|
|
157
|
+
try {
|
|
158
|
+
if (existsSync(filePath)) {
|
|
159
|
+
id = distroId;
|
|
160
|
+
version = readFileSync(filePath, "utf-8").trim().split("\n")[0];
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch { /* try next */ }
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const specificDistro = osFamily === "darwin" ? "macos" : idToSpecificDistro(id);
|
|
168
|
+
const family = idToFamily(id);
|
|
169
|
+
let packageManager = osFamily === "darwin" ? "brew" : familyToPackageManager(family);
|
|
170
|
+
if (family === "rhel") {
|
|
171
|
+
const hasDnf = await binaryExists("dnf");
|
|
172
|
+
packageManager = hasDnf ? "dnf" : "yum";
|
|
173
|
+
}
|
|
174
|
+
let initSystem = "unknown";
|
|
175
|
+
if (osFamily === "darwin") {
|
|
176
|
+
initSystem = "launchd";
|
|
177
|
+
}
|
|
178
|
+
else if (existsSync("/run/systemd/system")) {
|
|
179
|
+
initSystem = "systemd";
|
|
180
|
+
}
|
|
181
|
+
else if (existsSync("/sbin/openrc-run")) {
|
|
182
|
+
initSystem = "openrc";
|
|
183
|
+
}
|
|
184
|
+
else if (existsSync("/etc/init.d")) {
|
|
185
|
+
initSystem = "sysvinit";
|
|
186
|
+
}
|
|
187
|
+
const [hasFirewalld, hasUfw, hasSelinux, hasApparmor] = await Promise.all([
|
|
188
|
+
binaryExists("firewall-cmd"),
|
|
189
|
+
binaryExists("ufw"),
|
|
190
|
+
binaryExists("getenforce"),
|
|
191
|
+
binaryExists("apparmor_status"),
|
|
192
|
+
]);
|
|
193
|
+
cachedDistro = {
|
|
194
|
+
id, name, version,
|
|
195
|
+
osFamily, specificDistro, family,
|
|
196
|
+
packageManager, initSystem,
|
|
197
|
+
hasFirewalld, hasUfw, hasSelinux, hasApparmor,
|
|
198
|
+
};
|
|
199
|
+
console.error(`[distro] Detected: ${name} (${id}) osFamily=${osFamily} family=${family} pkg=${packageManager} init=${initSystem}`);
|
|
200
|
+
return cachedDistro;
|
|
201
|
+
}
|
|
202
|
+
// ── PackageManager factory ───────────────────────────────────────────────────
|
|
203
|
+
export function getPackageManager(nameOrDistro) {
|
|
204
|
+
const mgr = resolvePackageManagerName(nameOrDistro);
|
|
205
|
+
switch (mgr) {
|
|
206
|
+
case "apt": return {
|
|
207
|
+
installCmd: (pkg) => ["apt-get", "install", "-y", pkg],
|
|
208
|
+
removeCmd: (pkg) => ["apt-get", "remove", "-y", pkg],
|
|
209
|
+
updateCmd: () => ["apt-get", "update"],
|
|
210
|
+
searchCmd: (term) => ["apt-cache", "search", term],
|
|
211
|
+
listInstalledCmd: () => ["dpkg", "--get-selections"],
|
|
212
|
+
};
|
|
213
|
+
case "dnf": return {
|
|
214
|
+
installCmd: (pkg) => ["dnf", "install", "-y", pkg],
|
|
215
|
+
removeCmd: (pkg) => ["dnf", "remove", "-y", pkg],
|
|
216
|
+
updateCmd: () => ["dnf", "check-update"],
|
|
217
|
+
searchCmd: (term) => ["dnf", "search", term],
|
|
218
|
+
listInstalledCmd: () => ["dnf", "list", "installed"],
|
|
219
|
+
};
|
|
220
|
+
case "yum": return {
|
|
221
|
+
installCmd: (pkg) => ["yum", "install", "-y", pkg],
|
|
222
|
+
removeCmd: (pkg) => ["yum", "remove", "-y", pkg],
|
|
223
|
+
updateCmd: () => ["yum", "check-update"],
|
|
224
|
+
searchCmd: (term) => ["yum", "search", term],
|
|
225
|
+
listInstalledCmd: () => ["yum", "list", "installed"],
|
|
226
|
+
};
|
|
227
|
+
case "pacman": return {
|
|
228
|
+
installCmd: (pkg) => ["pacman", "-S", "--noconfirm", pkg],
|
|
229
|
+
removeCmd: (pkg) => ["pacman", "-R", "--noconfirm", pkg],
|
|
230
|
+
updateCmd: () => ["pacman", "-Sy"],
|
|
231
|
+
searchCmd: (term) => ["pacman", "-Ss", term],
|
|
232
|
+
listInstalledCmd: () => ["pacman", "-Q"],
|
|
233
|
+
};
|
|
234
|
+
case "brew": return {
|
|
235
|
+
installCmd: (pkg) => ["brew", "install", pkg],
|
|
236
|
+
removeCmd: (pkg) => ["brew", "uninstall", pkg],
|
|
237
|
+
updateCmd: () => ["brew", "update"],
|
|
238
|
+
searchCmd: (term) => ["brew", "search", term],
|
|
239
|
+
listInstalledCmd: () => ["brew", "list"],
|
|
240
|
+
};
|
|
241
|
+
case "apk": return {
|
|
242
|
+
installCmd: (pkg) => ["apk", "add", pkg],
|
|
243
|
+
removeCmd: (pkg) => ["apk", "del", pkg],
|
|
244
|
+
updateCmd: () => ["apk", "update"],
|
|
245
|
+
searchCmd: (term) => ["apk", "search", term],
|
|
246
|
+
listInstalledCmd: () => ["apk", "info"],
|
|
247
|
+
};
|
|
248
|
+
case "zypper": return {
|
|
249
|
+
installCmd: (pkg) => ["zypper", "install", "-y", pkg],
|
|
250
|
+
removeCmd: (pkg) => ["zypper", "remove", "-y", pkg],
|
|
251
|
+
updateCmd: () => ["zypper", "refresh"],
|
|
252
|
+
searchCmd: (term) => ["zypper", "search", term],
|
|
253
|
+
listInstalledCmd: () => ["zypper", "packages", "--installed-only"],
|
|
254
|
+
};
|
|
255
|
+
default: return {
|
|
256
|
+
installCmd: (pkg) => ["echo", `[unknown-pkg-mgr] install ${pkg}`],
|
|
257
|
+
removeCmd: (pkg) => ["echo", `[unknown-pkg-mgr] remove ${pkg}`],
|
|
258
|
+
updateCmd: () => ["echo", "[unknown-pkg-mgr] update"],
|
|
259
|
+
searchCmd: (term) => ["echo", `[unknown-pkg-mgr] search ${term}`],
|
|
260
|
+
listInstalledCmd: () => ["echo", "[unknown-pkg-mgr] list-installed"],
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function resolvePackageManagerName(input) {
|
|
265
|
+
if (!input)
|
|
266
|
+
return "unknown";
|
|
267
|
+
const lower = input.toLowerCase().trim();
|
|
268
|
+
const directNames = ["apt", "dnf", "yum", "pacman", "brew", "apk", "zypper"];
|
|
269
|
+
if (directNames.includes(lower))
|
|
270
|
+
return lower;
|
|
271
|
+
switch (lower) {
|
|
272
|
+
case "debian":
|
|
273
|
+
case "ubuntu":
|
|
274
|
+
case "kali": return "apt";
|
|
275
|
+
case "fedora":
|
|
276
|
+
case "rhel":
|
|
277
|
+
case "centos": return "dnf";
|
|
278
|
+
case "arch": return "pacman";
|
|
279
|
+
case "alpine": return "apk";
|
|
280
|
+
case "opensuse": return "zypper";
|
|
281
|
+
case "macos": return "brew";
|
|
282
|
+
default: return "unknown";
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// ── ServiceManager factory ───────────────────────────────────────────────────
|
|
286
|
+
function detectInitSystemSync() {
|
|
287
|
+
if (process.platform === "darwin")
|
|
288
|
+
return "launchd";
|
|
289
|
+
if (existsSync("/run/systemd/system"))
|
|
290
|
+
return "systemd";
|
|
291
|
+
if (existsSync("/sbin/openrc-run"))
|
|
292
|
+
return "openrc";
|
|
293
|
+
if (existsSync("/etc/init.d"))
|
|
294
|
+
return "sysvinit";
|
|
295
|
+
return "unknown";
|
|
296
|
+
}
|
|
297
|
+
export function getServiceManager(initSystem) {
|
|
298
|
+
const system = initSystem ?? detectInitSystemSync();
|
|
299
|
+
switch (system) {
|
|
300
|
+
case "systemd": return {
|
|
301
|
+
startCmd: (svc) => ["systemctl", "start", svc],
|
|
302
|
+
stopCmd: (svc) => ["systemctl", "stop", svc],
|
|
303
|
+
enableCmd: (svc) => ["systemctl", "enable", svc],
|
|
304
|
+
disableCmd: (svc) => ["systemctl", "disable", svc],
|
|
305
|
+
statusCmd: (svc) => ["systemctl", "status", svc],
|
|
306
|
+
listServicesCmd: () => ["systemctl", "list-units", "--type=service", "--all"],
|
|
307
|
+
};
|
|
308
|
+
case "launchd": return {
|
|
309
|
+
startCmd: (svc) => ["launchctl", "start", svc],
|
|
310
|
+
stopCmd: (svc) => ["launchctl", "stop", svc],
|
|
311
|
+
enableCmd: (svc) => ["launchctl", "load", "-w", svc],
|
|
312
|
+
disableCmd: (svc) => ["launchctl", "unload", "-w", svc],
|
|
313
|
+
statusCmd: (svc) => ["launchctl", "list", svc],
|
|
314
|
+
listServicesCmd: () => ["launchctl", "list"],
|
|
315
|
+
};
|
|
316
|
+
case "openrc": return {
|
|
317
|
+
startCmd: (svc) => ["rc-service", svc, "start"],
|
|
318
|
+
stopCmd: (svc) => ["rc-service", svc, "stop"],
|
|
319
|
+
enableCmd: (svc) => ["rc-update", "add", svc, "default"],
|
|
320
|
+
disableCmd: (svc) => ["rc-update", "del", svc, "default"],
|
|
321
|
+
statusCmd: (svc) => ["rc-service", svc, "status"],
|
|
322
|
+
listServicesCmd: () => ["rc-status", "--all"],
|
|
323
|
+
};
|
|
324
|
+
default: return {
|
|
325
|
+
startCmd: (svc) => ["service", svc, "start"],
|
|
326
|
+
stopCmd: (svc) => ["service", svc, "stop"],
|
|
327
|
+
enableCmd: (svc) => ["update-rc.d", svc, "enable"],
|
|
328
|
+
disableCmd: (svc) => ["update-rc.d", svc, "disable"],
|
|
329
|
+
statusCmd: (svc) => ["service", svc, "status"],
|
|
330
|
+
listServicesCmd: () => ["service", "--status-all"],
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// ── Firewall Backend factory ─────────────────────────────────────────────────
|
|
335
|
+
function buildFirewallBackend(fbName) {
|
|
336
|
+
switch (fbName) {
|
|
337
|
+
case "ufw": return {
|
|
338
|
+
name: fbName,
|
|
339
|
+
allowCmd: (port, proto = "tcp") => ["ufw", "allow", `${port}/${proto}`],
|
|
340
|
+
denyCmd: (port, proto = "tcp") => ["ufw", "deny", `${port}/${proto}`],
|
|
341
|
+
listCmd: () => ["ufw", "status", "verbose"],
|
|
342
|
+
flushCmd: () => ["ufw", "reset"],
|
|
343
|
+
};
|
|
344
|
+
case "firewalld": return {
|
|
345
|
+
name: fbName,
|
|
346
|
+
allowCmd: (port, proto = "tcp") => ["firewall-cmd", "--permanent", `--add-port=${port}/${proto}`],
|
|
347
|
+
denyCmd: (port, proto = "tcp") => ["firewall-cmd", "--permanent", `--remove-port=${port}/${proto}`],
|
|
348
|
+
listCmd: () => ["firewall-cmd", "--list-all"],
|
|
349
|
+
flushCmd: () => ["firewall-cmd", "--complete-reload"],
|
|
350
|
+
};
|
|
351
|
+
case "nftables": return {
|
|
352
|
+
name: fbName,
|
|
353
|
+
allowCmd: (port, proto = "tcp") => ["nft", "add", "rule", "inet", "filter", "input", proto, "dport", String(port), "accept"],
|
|
354
|
+
denyCmd: (port, proto = "tcp") => ["nft", "add", "rule", "inet", "filter", "input", proto, "dport", String(port), "drop"],
|
|
355
|
+
listCmd: () => ["nft", "list", "ruleset"],
|
|
356
|
+
flushCmd: () => ["nft", "flush", "ruleset"],
|
|
357
|
+
};
|
|
358
|
+
case "iptables": return {
|
|
359
|
+
name: fbName,
|
|
360
|
+
allowCmd: (port, proto = "tcp") => ["iptables", "-A", "INPUT", "-p", proto, "--dport", String(port), "-j", "ACCEPT"],
|
|
361
|
+
denyCmd: (port, proto = "tcp") => ["iptables", "-A", "INPUT", "-p", proto, "--dport", String(port), "-j", "DROP"],
|
|
362
|
+
listCmd: () => ["iptables", "-L", "-n", "-v"],
|
|
363
|
+
flushCmd: () => ["iptables", "-F"],
|
|
364
|
+
};
|
|
365
|
+
case "pf": return {
|
|
366
|
+
name: fbName,
|
|
367
|
+
allowCmd: (port, proto = "tcp") => ["pfctl", "-e", "-f", "-"],
|
|
368
|
+
denyCmd: (port, proto = "tcp") => ["pfctl", "-e", "-f", "-"],
|
|
369
|
+
listCmd: () => ["pfctl", "-sr"],
|
|
370
|
+
flushCmd: () => ["pfctl", "-F", "all"],
|
|
371
|
+
};
|
|
372
|
+
default: return {
|
|
373
|
+
name: "unknown",
|
|
374
|
+
allowCmd: () => ["echo", "[unknown-firewall] allow"],
|
|
375
|
+
denyCmd: () => ["echo", "[unknown-firewall] deny"],
|
|
376
|
+
listCmd: () => ["echo", "[unknown-firewall] list"],
|
|
377
|
+
flushCmd: () => ["echo", "[unknown-firewall] flush"],
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
export async function getFirewallBackend() {
|
|
382
|
+
const [hasUfwBin, hasFirewalldBin, hasNft, hasIptables, hasPf] = await Promise.all([
|
|
383
|
+
binaryExists("ufw"),
|
|
384
|
+
binaryExists("firewall-cmd"),
|
|
385
|
+
binaryExists("nft"),
|
|
386
|
+
binaryExists("iptables"),
|
|
387
|
+
binaryExists("pfctl"),
|
|
388
|
+
]);
|
|
389
|
+
if (hasUfwBin)
|
|
390
|
+
return buildFirewallBackend("ufw");
|
|
391
|
+
if (hasFirewalldBin)
|
|
392
|
+
return buildFirewallBackend("firewalld");
|
|
393
|
+
if (hasNft)
|
|
394
|
+
return buildFirewallBackend("nftables");
|
|
395
|
+
if (hasIptables)
|
|
396
|
+
return buildFirewallBackend("iptables");
|
|
397
|
+
if (hasPf)
|
|
398
|
+
return buildFirewallBackend("pf");
|
|
399
|
+
return buildFirewallBackend("unknown");
|
|
400
|
+
}
|
|
401
|
+
// ── Capability detection ─────────────────────────────────────────────────────
|
|
402
|
+
async function safeCap(fn) {
|
|
403
|
+
try {
|
|
404
|
+
return await fn();
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async function fileReadable(path) {
|
|
411
|
+
try {
|
|
412
|
+
await readFile(path, "utf-8");
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
catch {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
export async function canUseAppArmor() {
|
|
420
|
+
return safeCap(async () => (await binaryExists("apparmor_status")) || (await fileReadable("/sys/kernel/security/apparmor")));
|
|
421
|
+
}
|
|
422
|
+
export async function canUseSELinux() {
|
|
423
|
+
return safeCap(async () => (await binaryExists("getenforce")) || (await fileReadable("/sys/fs/selinux")));
|
|
424
|
+
}
|
|
425
|
+
export async function canUseAuditd() {
|
|
426
|
+
return safeCap(() => binaryExists("auditctl"));
|
|
427
|
+
}
|
|
428
|
+
export async function canUseSystemd() {
|
|
429
|
+
return safeCap(async () => existsSync("/run/systemd/system"));
|
|
430
|
+
}
|
|
431
|
+
export async function canUseIPTables() {
|
|
432
|
+
return safeCap(() => binaryExists("iptables"));
|
|
433
|
+
}
|
|
434
|
+
export async function canUseNFTables() {
|
|
435
|
+
return safeCap(() => binaryExists("nft"));
|
|
436
|
+
}
|
|
437
|
+
export async function canUseBPF() {
|
|
438
|
+
return safeCap(async () => (await binaryExists("bpftool")) || existsSync("/sys/fs/bpf"));
|
|
439
|
+
}
|
|
440
|
+
export async function hasTPM() {
|
|
441
|
+
return safeCap(async () => existsSync("/dev/tpm0") || existsSync("/dev/tpmrm0"));
|
|
442
|
+
}
|
|
443
|
+
export async function hasSecureBoot() {
|
|
444
|
+
return safeCap(async () => {
|
|
445
|
+
const r = await executeCommand({ command: "mokutil", args: ["--sb-state"], timeout: 5000 });
|
|
446
|
+
return r.exitCode === 0 && r.stdout.toLowerCase().includes("secureboot enabled");
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
// ── Legacy helpers (backwards compatibility) ─────────────────────────────────
|
|
450
|
+
/** @deprecated Prefer getPackageManager(pkgManager).installCmd(pkg) */
|
|
451
|
+
export function getInstallCommand(pkgManager, pkg) {
|
|
452
|
+
return getPackageManager(pkgManager).installCmd(pkg);
|
|
453
|
+
}
|
|
454
|
+
/** @deprecated Prefer getPackageManager(pkgManager).updateCmd() */
|
|
455
|
+
export function getUpdateCommand(pkgManager) {
|
|
456
|
+
return getPackageManager(pkgManager).updateCmd();
|
|
457
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* encrypted-state.ts — Encrypted storage for sensitive state data.
|
|
3
|
+
*
|
|
4
|
+
* Provides AES-256-GCM encrypted at-rest storage for rollback data,
|
|
5
|
+
* policy files, sudo session tokens, and other sensitive state.
|
|
6
|
+
*
|
|
7
|
+
* Key derivation uses PBKDF2 from a configurable secret via the
|
|
8
|
+
* `KALI_DEFENSE_STATE_KEY` environment variable. If no key is
|
|
9
|
+
* configured, falls back to unencrypted mode with a warning.
|
|
10
|
+
*
|
|
11
|
+
* @module encrypted-state
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Encrypted state storage for sensitive data at rest.
|
|
15
|
+
*
|
|
16
|
+
* Uses AES-256-GCM with PBKDF2-derived keys when `KALI_DEFENSE_STATE_KEY`
|
|
17
|
+
* is set. Falls back to plaintext JSON when no key is configured.
|
|
18
|
+
*/
|
|
19
|
+
export declare class SecureStateStore {
|
|
20
|
+
private readonly stateDir;
|
|
21
|
+
private readonly secret;
|
|
22
|
+
/**
|
|
23
|
+
* @param stateDir - Directory for state files (default: `/tmp/kali-defense/state/`)
|
|
24
|
+
* @param secret - Encryption secret. If omitted, reads from `KALI_DEFENSE_STATE_KEY` env var.
|
|
25
|
+
* Pass empty string or omit to use unencrypted fallback.
|
|
26
|
+
*/
|
|
27
|
+
constructor(stateDir?: string, secret?: string);
|
|
28
|
+
/**
|
|
29
|
+
* Whether the store is operating in encrypted mode.
|
|
30
|
+
*/
|
|
31
|
+
get encrypted(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Save a state object to disk.
|
|
34
|
+
*
|
|
35
|
+
* @param id - Unique identifier for the state (used as filename stem)
|
|
36
|
+
* @param data - JSON-serializable object to persist
|
|
37
|
+
*/
|
|
38
|
+
save(id: string, data: object): void;
|
|
39
|
+
/**
|
|
40
|
+
* Load a state object from disk.
|
|
41
|
+
*
|
|
42
|
+
* @param id - Unique identifier for the state
|
|
43
|
+
* @returns The deserialized object, or `null` if the state file doesn't exist
|
|
44
|
+
*/
|
|
45
|
+
load(id: string): object | null;
|
|
46
|
+
/**
|
|
47
|
+
* Delete a state file from disk.
|
|
48
|
+
*
|
|
49
|
+
* @param id - Unique identifier for the state to delete
|
|
50
|
+
*/
|
|
51
|
+
delete(id: string): void;
|
|
52
|
+
/** Build the full file path for a state ID. */
|
|
53
|
+
private filePath;
|
|
54
|
+
/** Ensure the state directory exists with secure permissions. */
|
|
55
|
+
private ensureStateDir;
|
|
56
|
+
/** Derive an AES-256 key from the secret and a salt. */
|
|
57
|
+
private deriveKey;
|
|
58
|
+
/**
|
|
59
|
+
* Encrypt plaintext JSON using AES-256-GCM.
|
|
60
|
+
* Returns a Buffer: [salt (16)] [iv (12)] [authTag (16)] [ciphertext]
|
|
61
|
+
*/
|
|
62
|
+
private encrypt;
|
|
63
|
+
/**
|
|
64
|
+
* Decrypt an AES-256-GCM encrypted buffer.
|
|
65
|
+
* Expects format: [salt (16)] [iv (12)] [authTag (16)] [ciphertext]
|
|
66
|
+
*/
|
|
67
|
+
private decrypt;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Default singleton SecureStateStore instance.
|
|
71
|
+
*
|
|
72
|
+
* Uses the default state directory and reads the encryption key from
|
|
73
|
+
* the `KALI_DEFENSE_STATE_KEY` environment variable.
|
|
74
|
+
*/
|
|
75
|
+
export declare const secureState: SecureStateStore;
|
|
76
|
+
//# sourceMappingURL=encrypted-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encrypted-state.d.ts","sourceRoot":"","sources":["../../src/core/encrypted-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA4DH;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IAEvC;;;;OAIG;gBACS,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAwB9C;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;;;OAKG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAmBpC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAiB/B;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAcxB,+CAA+C;IAC/C,OAAO,CAAC,QAAQ;IAMhB,iEAAiE;IACjE,OAAO,CAAC,cAAc;IAOtB,wDAAwD;IACxD,OAAO,CAAC,SAAS;IAajB;;;OAGG;IACH,OAAO,CAAC,OAAO;IAgBf;;;OAGG;IACH,OAAO,CAAC,OAAO;CAoChB;AAID;;;;;GAKG;AACH,eAAO,MAAM,WAAW,kBAAyB,CAAC"}
|