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,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SudoSession — singleton that manages elevated privilege credentials.
|
|
3
|
+
*
|
|
4
|
+
* The MCP server runs non-interactively via stdio transport, so `sudo`
|
|
5
|
+
* cannot prompt for a password through a TTY. This module stores the
|
|
6
|
+
* user's password in a zeroable Buffer and transparently provides it
|
|
7
|
+
* to `sudo -S` via stdin piping in the executor.
|
|
8
|
+
*
|
|
9
|
+
* Security features:
|
|
10
|
+
* - Password stored in a Buffer and remains as Buffer through the entire
|
|
11
|
+
* stdin pipeline (never converted to a V8 string, can be zeroed)
|
|
12
|
+
* - Auto-expires after a configurable timeout (default 15 minutes)
|
|
13
|
+
* - Explicit `drop()` zeroes the buffer immediately
|
|
14
|
+
* - Process exit handler zeroes the buffer on shutdown
|
|
15
|
+
* - Validates credentials before storing (test with `sudo -S -v`)
|
|
16
|
+
* - Never logs or exposes the password in any output
|
|
17
|
+
*
|
|
18
|
+
* Child process spawning goes through spawn-safe.ts which enforces the
|
|
19
|
+
* command allowlist and shell: false without creating circular dependencies.
|
|
20
|
+
*/
|
|
21
|
+
import { spawnSafe } from "./spawn-safe.js";
|
|
22
|
+
function runSimple(command, args, stdin, timeoutMs = 10000) {
|
|
23
|
+
return new Promise((resolve) => {
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
let child;
|
|
26
|
+
try {
|
|
27
|
+
child = spawnSafe(command, args, {
|
|
28
|
+
signal: controller.signal,
|
|
29
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
resolve({ stdout: "", stderr: `spawn failed for: ${command}`, exitCode: 1 });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const stdoutChunks = [];
|
|
37
|
+
const stderrChunks = [];
|
|
38
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
39
|
+
child.stdout?.on("data", (c) => stdoutChunks.push(c));
|
|
40
|
+
child.stderr?.on("data", (c) => stderrChunks.push(c));
|
|
41
|
+
if (stdin && child.stdin) {
|
|
42
|
+
// Write as Buffer to avoid creating immutable V8 strings from passwords
|
|
43
|
+
child.stdin.write(Buffer.isBuffer(stdin) ? stdin : Buffer.from(stdin, "utf-8"));
|
|
44
|
+
child.stdin.end();
|
|
45
|
+
}
|
|
46
|
+
child.on("close", (code) => {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
resolve({
|
|
49
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
50
|
+
stderr: Buffer.concat(stderrChunks).toString("utf-8"),
|
|
51
|
+
exitCode: code ?? 1,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
child.on("error", () => {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
resolve({
|
|
57
|
+
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
58
|
+
stderr: Buffer.concat(stderrChunks).toString("utf-8"),
|
|
59
|
+
exitCode: 1,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// ── SudoSession singleton ────────────────────────────────────────────────────
|
|
65
|
+
// SECURITY (CORE-021): Module-scoped singleton variable prevents external
|
|
66
|
+
// mutation via (SudoSession as any).instance — inaccessible outside module.
|
|
67
|
+
let _sudoSessionInstance = null;
|
|
68
|
+
export class SudoSession {
|
|
69
|
+
/** Password stored in a Buffer so we can zero it (not interned by V8). */
|
|
70
|
+
passwordBuf = null;
|
|
71
|
+
/** Username that authenticated. */
|
|
72
|
+
username = null;
|
|
73
|
+
/**
|
|
74
|
+
* SECURITY (CICD-028): OS-level user ID that created this session.
|
|
75
|
+
* Used for session isolation tracking. Defaults to process.getuid().
|
|
76
|
+
*
|
|
77
|
+
* NOTE: Concurrent multi-user sessions are NOT currently supported.
|
|
78
|
+
* This server should not be used in multi-tenant environments where
|
|
79
|
+
* multiple users share the same process. Each user should run their
|
|
80
|
+
* own server instance.
|
|
81
|
+
*/
|
|
82
|
+
sessionUserId = null;
|
|
83
|
+
/** Timestamp (epoch ms) when the session expires. */
|
|
84
|
+
expiresAt = null;
|
|
85
|
+
/** Handle for the auto-expiry timer. */
|
|
86
|
+
expiryTimer = null;
|
|
87
|
+
/** Default session timeout in milliseconds (15 min). */
|
|
88
|
+
defaultTimeoutMs = 15 * 60 * 1000;
|
|
89
|
+
constructor() {
|
|
90
|
+
// Zero the password on process exit/crash
|
|
91
|
+
const cleanup = () => this.drop();
|
|
92
|
+
process.once("exit", cleanup);
|
|
93
|
+
process.once("SIGINT", cleanup);
|
|
94
|
+
process.once("SIGTERM", cleanup);
|
|
95
|
+
process.once("uncaughtException", cleanup);
|
|
96
|
+
}
|
|
97
|
+
/** Get the singleton instance. */
|
|
98
|
+
static getInstance() {
|
|
99
|
+
if (!_sudoSessionInstance) {
|
|
100
|
+
_sudoSessionInstance = new SudoSession();
|
|
101
|
+
}
|
|
102
|
+
return _sudoSessionInstance;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Reset the singleton instance (for testing only).
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
static resetInstance() {
|
|
109
|
+
_sudoSessionInstance = null;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Set the session timeout in milliseconds.
|
|
113
|
+
* Only affects future `elevate()` calls.
|
|
114
|
+
*/
|
|
115
|
+
setDefaultTimeout(ms) {
|
|
116
|
+
if (ms > 0) {
|
|
117
|
+
this.defaultTimeoutMs = ms;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Attempt to elevate privileges by validating the given password.
|
|
122
|
+
*
|
|
123
|
+
* Runs `sudo -S -k -v` with the password piped on stdin.
|
|
124
|
+
* `-k` invalidates cached credentials so we always test our password.
|
|
125
|
+
* `-v` validates without running a command.
|
|
126
|
+
* `-S` reads password from stdin.
|
|
127
|
+
* `-p ""` suppresses the password prompt text.
|
|
128
|
+
*
|
|
129
|
+
* @returns result indicating success or failure with error message.
|
|
130
|
+
*/
|
|
131
|
+
async elevate(password, timeoutMs) {
|
|
132
|
+
// SECURITY (CORE-005): JavaScript strings are immutable and interned by V8,
|
|
133
|
+
// making them impossible to reliably zero from memory. Convert password to
|
|
134
|
+
// Buffer immediately to minimize credential lifetime as a V8 string.
|
|
135
|
+
// Buffer contents can be explicitly zeroed with .fill(0) after use.
|
|
136
|
+
const passwordBuf = Buffer.isBuffer(password)
|
|
137
|
+
? Buffer.from(password) // defensive copy so caller's buffer isn't affected
|
|
138
|
+
: Buffer.from(password, "utf-8");
|
|
139
|
+
// Determine who we are first
|
|
140
|
+
const whoami = await runSimple("whoami", []);
|
|
141
|
+
const currentUser = whoami.stdout.trim() || "unknown";
|
|
142
|
+
// If already running as root, no password needed
|
|
143
|
+
if (currentUser === "root") {
|
|
144
|
+
this.username = "root";
|
|
145
|
+
this.expiresAt = null;
|
|
146
|
+
// Store an empty buffer — the executor will skip stdin piping for root
|
|
147
|
+
this.passwordBuf = Buffer.alloc(0);
|
|
148
|
+
// Zero the local buffer — not needed for root
|
|
149
|
+
passwordBuf.fill(0);
|
|
150
|
+
return { success: true };
|
|
151
|
+
}
|
|
152
|
+
// Validate the password with sudo -S -k -v
|
|
153
|
+
const validationBuf = Buffer.concat([passwordBuf, Buffer.from("\n")]);
|
|
154
|
+
const result = await runSimple("sudo", ["-S", "-k", "-v", "-p", ""], validationBuf, 10000);
|
|
155
|
+
// Zero the validation buffer immediately after use
|
|
156
|
+
validationBuf.fill(0);
|
|
157
|
+
if (result.exitCode === 0) {
|
|
158
|
+
// Password is valid — store it (storePassword makes its own defensive copy)
|
|
159
|
+
this.storePassword(passwordBuf, timeoutMs);
|
|
160
|
+
// Zero our local copy since storePassword made its own
|
|
161
|
+
passwordBuf.fill(0);
|
|
162
|
+
this.username = currentUser;
|
|
163
|
+
// SECURITY (CICD-028): Track the OS-level user ID for session isolation
|
|
164
|
+
this.sessionUserId = process.getuid?.() ?? null;
|
|
165
|
+
console.error(`[sudo-session] Elevated privileges for user '${currentUser}' (uid=${this.sessionUserId ?? "unknown"})`);
|
|
166
|
+
return { success: true };
|
|
167
|
+
}
|
|
168
|
+
// Zero password buffer on all failure paths
|
|
169
|
+
passwordBuf.fill(0);
|
|
170
|
+
// Check for common failure reasons
|
|
171
|
+
const stderr = result.stderr.toLowerCase();
|
|
172
|
+
if (stderr.includes("not in the sudoers file")) {
|
|
173
|
+
return {
|
|
174
|
+
success: false,
|
|
175
|
+
error: `User '${currentUser}' is not in the sudoers file. Cannot elevate privileges.`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
if (stderr.includes("incorrect password") || stderr.includes("sorry")) {
|
|
179
|
+
return {
|
|
180
|
+
success: false,
|
|
181
|
+
error: "Incorrect password. Please try again.",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
error: `sudo validation failed (exit ${result.exitCode}): ${result.stderr.substring(0, 200)}`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Returns a **copy** of the password Buffer for piping to sudo -S,
|
|
191
|
+
* or null if not elevated.
|
|
192
|
+
*
|
|
193
|
+
* The caller MUST zero the returned Buffer with `.fill(0)` after use.
|
|
194
|
+
* A copy is returned so the original can be zeroed independently via `drop()`.
|
|
195
|
+
*/
|
|
196
|
+
getPassword() {
|
|
197
|
+
if (!this.passwordBuf || this.passwordBuf.length === 0) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
if (this.isExpired()) {
|
|
201
|
+
this.drop();
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
// Return a COPY so original can be zeroed independently
|
|
205
|
+
const copy = Buffer.alloc(this.passwordBuf.length);
|
|
206
|
+
this.passwordBuf.copy(copy);
|
|
207
|
+
return copy;
|
|
208
|
+
}
|
|
209
|
+
/** Check whether we have an active elevated session. */
|
|
210
|
+
isElevated() {
|
|
211
|
+
if (!this.passwordBuf)
|
|
212
|
+
return false;
|
|
213
|
+
if (this.username === "root")
|
|
214
|
+
return true; // root never expires
|
|
215
|
+
if (this.isExpired()) {
|
|
216
|
+
this.drop();
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
/** Get current session status (safe to expose via MCP). */
|
|
222
|
+
getStatus() {
|
|
223
|
+
if (!this.isElevated()) {
|
|
224
|
+
return {
|
|
225
|
+
elevated: false,
|
|
226
|
+
username: null,
|
|
227
|
+
expiresAt: null,
|
|
228
|
+
remainingSeconds: null,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const remaining = this.expiresAt
|
|
232
|
+
? Math.max(0, Math.round((this.expiresAt - Date.now()) / 1000))
|
|
233
|
+
: null;
|
|
234
|
+
return {
|
|
235
|
+
elevated: true,
|
|
236
|
+
username: this.username,
|
|
237
|
+
expiresAt: this.expiresAt ? new Date(this.expiresAt).toISOString() : null,
|
|
238
|
+
remainingSeconds: remaining,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Drop elevated privileges immediately.
|
|
243
|
+
* Zeroes the password buffer and clears all session state.
|
|
244
|
+
*/
|
|
245
|
+
drop() {
|
|
246
|
+
if (this.passwordBuf) {
|
|
247
|
+
// Zero the buffer contents
|
|
248
|
+
this.passwordBuf.fill(0);
|
|
249
|
+
this.passwordBuf = null;
|
|
250
|
+
}
|
|
251
|
+
this.username = null;
|
|
252
|
+
this.expiresAt = null;
|
|
253
|
+
if (this.expiryTimer) {
|
|
254
|
+
clearTimeout(this.expiryTimer);
|
|
255
|
+
this.expiryTimer = null;
|
|
256
|
+
}
|
|
257
|
+
// Also invalidate the system sudo cache (fire and forget)
|
|
258
|
+
try {
|
|
259
|
+
runSimple("sudo", ["-k"], undefined, 3000).catch(() => { });
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// Best effort
|
|
263
|
+
}
|
|
264
|
+
console.error("[sudo-session] Privileges dropped, password zeroed");
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Extend the session timeout by the given milliseconds (or the default).
|
|
268
|
+
*/
|
|
269
|
+
extend(extraMs) {
|
|
270
|
+
if (!this.isElevated())
|
|
271
|
+
return false;
|
|
272
|
+
if (this.username === "root")
|
|
273
|
+
return true; // root sessions don't expire
|
|
274
|
+
const ms = extraMs ?? this.defaultTimeoutMs;
|
|
275
|
+
this.expiresAt = Date.now() + ms;
|
|
276
|
+
// Reset the timer
|
|
277
|
+
if (this.expiryTimer) {
|
|
278
|
+
clearTimeout(this.expiryTimer);
|
|
279
|
+
}
|
|
280
|
+
this.expiryTimer = setTimeout(() => this.drop(), ms);
|
|
281
|
+
// Prevent the timer from keeping the process alive
|
|
282
|
+
if (this.expiryTimer && typeof this.expiryTimer === "object" && "unref" in this.expiryTimer) {
|
|
283
|
+
this.expiryTimer.unref();
|
|
284
|
+
}
|
|
285
|
+
console.error(`[sudo-session] Session extended, expires at ${new Date(this.expiresAt).toISOString()}`);
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
// ── Private helpers ──────────────────────────────────────────────────────
|
|
289
|
+
storePassword(password, timeoutMs) {
|
|
290
|
+
// Zero any existing buffer
|
|
291
|
+
if (this.passwordBuf) {
|
|
292
|
+
this.passwordBuf.fill(0);
|
|
293
|
+
}
|
|
294
|
+
// Store in a new buffer (accept both string and Buffer to avoid V8 string interning)
|
|
295
|
+
this.passwordBuf = Buffer.isBuffer(password)
|
|
296
|
+
? Buffer.from(password) // defensive copy
|
|
297
|
+
: Buffer.from(password, "utf-8");
|
|
298
|
+
// Set expiry
|
|
299
|
+
const ms = timeoutMs ?? this.defaultTimeoutMs;
|
|
300
|
+
this.expiresAt = Date.now() + ms;
|
|
301
|
+
// Auto-drop on expiry
|
|
302
|
+
if (this.expiryTimer) {
|
|
303
|
+
clearTimeout(this.expiryTimer);
|
|
304
|
+
}
|
|
305
|
+
this.expiryTimer = setTimeout(() => {
|
|
306
|
+
console.error("[sudo-session] Session expired, dropping privileges");
|
|
307
|
+
this.drop();
|
|
308
|
+
}, ms);
|
|
309
|
+
// Don't let the timer keep the process alive
|
|
310
|
+
if (this.expiryTimer && typeof this.expiryTimer === "object" && "unref" in this.expiryTimer) {
|
|
311
|
+
this.expiryTimer.unref();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
isExpired() {
|
|
315
|
+
if (this.expiresAt === null)
|
|
316
|
+
return false; // root sessions don't expire
|
|
317
|
+
return Date.now() >= this.expiresAt;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool-to-dependency mapping for Defense MCP Server.
|
|
3
|
+
*
|
|
4
|
+
* Maps each registered MCP tool name to the system binaries it requires.
|
|
5
|
+
* Used by the dependency validator to ensure all required tools are
|
|
6
|
+
* installed before execution — either at server startup or on-demand.
|
|
7
|
+
*
|
|
8
|
+
* After the v0.5.0 tool consolidation (157 → 78 tools), extended to 94
|
|
9
|
+
* tools across 32 modules in v0.6.0. Each entry represents a consolidated
|
|
10
|
+
* tool whose dependencies are the UNION of all the individual tools it
|
|
11
|
+
* absorbed. Action-specific binaries are listed as `optionalBinaries`
|
|
12
|
+
* because the tool handles missing ones gracefully based on which `action`
|
|
13
|
+
* the caller selects.
|
|
14
|
+
*/
|
|
15
|
+
import { type ToolRequirement } from "./installer.js";
|
|
16
|
+
/**
|
|
17
|
+
* Dependency specification for an MCP tool.
|
|
18
|
+
*/
|
|
19
|
+
export interface ToolDependency {
|
|
20
|
+
/** The MCP tool name (e.g. "ids_rootkit_scan") */
|
|
21
|
+
toolName: string;
|
|
22
|
+
/** System binaries required for this tool to function */
|
|
23
|
+
requiredBinaries: string[];
|
|
24
|
+
/** System binaries that are optional (enhance functionality) */
|
|
25
|
+
optionalBinaries?: string[];
|
|
26
|
+
/** Whether this tool is critical (server should warn loudly if deps missing) */
|
|
27
|
+
critical?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Returns the ToolRequirement for a given binary name, if known.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getToolRequirementForBinary(binary: string): ToolRequirement | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Complete mapping of MCP tool names to their system binary dependencies.
|
|
35
|
+
*
|
|
36
|
+
* 78 consolidated tools across 21 modules. Each entry specifies:
|
|
37
|
+
* - requiredBinaries: must be present for the tool to work at all
|
|
38
|
+
* - optionalBinaries: enhance functionality but aren't strictly needed
|
|
39
|
+
* - critical: if true, missing deps trigger a startup warning
|
|
40
|
+
*/
|
|
41
|
+
export declare const TOOL_DEPENDENCIES: ToolDependency[];
|
|
42
|
+
/**
|
|
43
|
+
* Returns the dependency specification for a given MCP tool name.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getDependenciesForTool(toolName: string): ToolDependency | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Returns all unique required binaries across all tools.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getAllRequiredBinaries(): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Returns all unique binaries (required + optional) across all tools.
|
|
52
|
+
*/
|
|
53
|
+
export declare function getAllBinaries(): {
|
|
54
|
+
required: string[];
|
|
55
|
+
optional: string[];
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Returns all critical tool dependencies (tools that should always work).
|
|
59
|
+
*/
|
|
60
|
+
export declare function getCriticalDependencies(): ToolDependency[];
|
|
61
|
+
//# sourceMappingURL=tool-dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-dependencies.d.ts","sourceRoot":"","sources":["../../src/core/tool-dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAIvE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAaD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,GACb,eAAe,GAAG,SAAS,CAE7B;AAID;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAAc,EAogB7C,CAAC;AAUF;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GACf,cAAc,GAAG,SAAS,CAE5B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAQjD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAiB3E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,cAAc,EAAE,CAE1D"}
|