defense-mcp-server 0.9.2 → 0.9.3
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/build/core/auto-installer.js +31 -31
- package/build/core/command-allowlist.js +1 -1
- package/build/core/dependency-validator.js +9 -9
- package/build/core/distro-adapter.d.ts +0 -5
- package/build/core/distro-adapter.d.ts.map +1 -1
- package/build/core/distro-adapter.js +0 -7
- package/build/core/distro.d.ts +0 -11
- package/build/core/distro.d.ts.map +1 -1
- package/build/core/distro.js +0 -48
- package/build/core/encrypted-state.d.ts +0 -7
- package/build/core/encrypted-state.d.ts.map +1 -1
- package/build/core/encrypted-state.js +0 -7
- package/build/core/logger.js +1 -1
- package/build/core/pam-utils.js +1 -1
- package/build/core/parsers.js +1 -1
- package/build/core/preflight.d.ts +4 -4
- package/build/core/preflight.js +13 -13
- package/build/core/progress.js +20 -20
- package/build/core/run-command.d.ts +14 -0
- package/build/core/run-command.d.ts.map +1 -0
- package/build/core/run-command.js +46 -0
- package/build/core/spawn-safe.d.ts +6 -6
- package/build/core/spawn-safe.d.ts.map +1 -1
- package/build/core/sudo-guard.js +4 -4
- package/build/core/third-party-installer.js +4 -4
- package/build/core/tool-wrapper.js +3 -3
- package/build/tools/access-control.js +6 -6
- package/build/tools/api-security.d.ts.map +1 -1
- package/build/tools/api-security.js +5 -51
- package/build/tools/app-hardening.d.ts.map +1 -1
- package/build/tools/app-hardening.js +23 -25
- package/build/tools/cloud-security.d.ts.map +1 -1
- package/build/tools/cloud-security.js +5 -51
- package/build/tools/compliance.d.ts.map +1 -1
- package/build/tools/compliance.js +9 -13
- package/build/tools/container-security.d.ts.map +1 -1
- package/build/tools/container-security.js +51 -52
- package/build/tools/deception.d.ts.map +1 -1
- package/build/tools/deception.js +8 -54
- package/build/tools/dns-security.d.ts.map +1 -1
- package/build/tools/dns-security.js +2 -48
- package/build/tools/encryption.d.ts.map +1 -1
- package/build/tools/encryption.js +86 -87
- package/build/tools/firewall.d.ts.map +1 -1
- package/build/tools/firewall.js +324 -30
- package/build/tools/hardening.d.ts.map +1 -1
- package/build/tools/hardening.js +12 -13
- package/build/tools/incident-response.d.ts.map +1 -1
- package/build/tools/incident-response.js +3 -3
- package/build/tools/logging.d.ts.map +1 -1
- package/build/tools/logging.js +17 -59
- package/build/tools/malware.js +2 -2
- package/build/tools/meta.d.ts.map +1 -1
- package/build/tools/meta.js +86 -165
- package/build/tools/network-defense.d.ts.map +1 -1
- package/build/tools/network-defense.js +3 -3
- package/build/tools/patch-management.js +8 -8
- package/build/tools/process-security.d.ts.map +1 -1
- package/build/tools/process-security.js +38 -92
- package/build/tools/sudo-management.js +36 -36
- package/build/tools/threat-intel.d.ts.map +1 -1
- package/build/tools/threat-intel.js +2 -48
- package/build/tools/vulnerability-management.d.ts.map +1 -1
- package/build/tools/vulnerability-management.js +3 -49
- package/build/tools/waf.d.ts.map +1 -1
- package/build/tools/waf.js +47 -93
- package/build/tools/wireless-security.d.ts.map +1 -1
- package/build/tools/wireless-security.js +9 -55
- package/package.json +4 -2
package/build/core/preflight.js
CHANGED
|
@@ -236,7 +236,7 @@ export class PreflightEngine {
|
|
|
236
236
|
};
|
|
237
237
|
result.summary = this.formatSummary(result);
|
|
238
238
|
this.cacheResult(toolName, result);
|
|
239
|
-
console.error(`[preflight]
|
|
239
|
+
console.error(`[preflight] WARNING: No manifest for '${toolName}' — skipping (${Date.now() - startTime}ms)`);
|
|
240
240
|
return result;
|
|
241
241
|
}
|
|
242
242
|
// ── Step 3–4: Use cached dep results or run fresh checks ───────────
|
|
@@ -305,7 +305,7 @@ export class PreflightEngine {
|
|
|
305
305
|
`${safeguardResult.warnings.length} warning(s)`);
|
|
306
306
|
}
|
|
307
307
|
catch (err) {
|
|
308
|
-
console.error(`[preflight]
|
|
308
|
+
console.error(`[preflight] WARNING: Safeguard check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
309
309
|
// Safeguard failure is non-blocking — log and continue
|
|
310
310
|
}
|
|
311
311
|
}
|
|
@@ -339,11 +339,11 @@ export class PreflightEngine {
|
|
|
339
339
|
console.error(`[preflight] Dependencies: ${depCount} checked, ${missingCount} missing`);
|
|
340
340
|
if (manifest.sudo !== "never") {
|
|
341
341
|
const sudoStatus = privileges.satisfied
|
|
342
|
-
? "session active
|
|
342
|
+
? "session active OK"
|
|
343
343
|
: `${privileges.issues.length} issue(s)`;
|
|
344
344
|
console.error(`[preflight] Privileges: sudo ${manifest.sudo} — ${sudoStatus}`);
|
|
345
345
|
}
|
|
346
|
-
console.error(`[preflight] ${passed ? "
|
|
346
|
+
console.error(`[preflight] ${passed ? "OK" : "FAIL"} Pre-flight ${passed ? "passed" : "FAILED"} (${duration}ms)`);
|
|
347
347
|
return result;
|
|
348
348
|
}
|
|
349
349
|
// ── Individual check phases ────────────────────────────────────────────
|
|
@@ -497,7 +497,7 @@ export class PreflightEngine {
|
|
|
497
497
|
*
|
|
498
498
|
* @example Passing
|
|
499
499
|
* ```
|
|
500
|
-
*
|
|
500
|
+
* PASS: Pre-flight passed for 'firewall_iptables_list'
|
|
501
501
|
* Dependencies: 2/2 available (iptables, ip6tables)
|
|
502
502
|
* Privileges: sudo session active
|
|
503
503
|
* Ready to execute.
|
|
@@ -505,7 +505,7 @@ export class PreflightEngine {
|
|
|
505
505
|
*
|
|
506
506
|
* @example Failing
|
|
507
507
|
* ```
|
|
508
|
-
*
|
|
508
|
+
* Pre-flight FAILED for 'compliance_oscap_scan'
|
|
509
509
|
* Missing dependencies:
|
|
510
510
|
* • oscap (binary) — Install with: sudo apt-get install -y libopenscap8
|
|
511
511
|
* Privilege issues:
|
|
@@ -522,7 +522,7 @@ export class PreflightEngine {
|
|
|
522
522
|
const autoNote = autoInstalledCount > 0
|
|
523
523
|
? ` (auto-installed ${autoInstalledCount} ${autoInstalledCount === 1 ? "dependency" : "dependencies"})`
|
|
524
524
|
: "";
|
|
525
|
-
lines.push(
|
|
525
|
+
lines.push(`Pre-flight passed for '${result.toolName}'${autoNote}`);
|
|
526
526
|
// Dependencies line
|
|
527
527
|
const requiredChecks = result.dependencies.checked.filter((c) => c.required);
|
|
528
528
|
const requiredFound = requiredChecks.filter((c) => c.found);
|
|
@@ -559,7 +559,7 @@ export class PreflightEngine {
|
|
|
559
559
|
}
|
|
560
560
|
else {
|
|
561
561
|
// ── Failing summary ──────────────────────────────────────────────
|
|
562
|
-
lines.push(
|
|
562
|
+
lines.push(`Pre-flight FAILED for '${result.toolName}'`);
|
|
563
563
|
// Missing dependencies
|
|
564
564
|
if (result.dependencies.missing.length > 0) {
|
|
565
565
|
lines.push(" Missing dependencies:");
|
|
@@ -583,7 +583,7 @@ export class PreflightEngine {
|
|
|
583
583
|
result.safeguards.blockers.length > 0) {
|
|
584
584
|
lines.push(" Safety blockers:");
|
|
585
585
|
for (const blocker of result.safeguards.blockers) {
|
|
586
|
-
lines.push(`
|
|
586
|
+
lines.push(` ${blocker}`);
|
|
587
587
|
}
|
|
588
588
|
}
|
|
589
589
|
lines.push(" Cannot proceed until issues are resolved.");
|
|
@@ -593,8 +593,8 @@ export class PreflightEngine {
|
|
|
593
593
|
/**
|
|
594
594
|
* Generate a shorter status message for prepending to tool output.
|
|
595
595
|
*
|
|
596
|
-
* - Passed (no issues): `"[pre-flight
|
|
597
|
-
* - Passed (warnings): `"[pre-flight
|
|
596
|
+
* - Passed (no issues): `"[pre-flight OK] All checks passed (2 deps, sudo active)"`
|
|
597
|
+
* - Passed (warnings): `"[pre-flight OK] Passed with warnings: optional dep 'nmap' not found"`
|
|
598
598
|
* - Failed: returns the full error summary from {@link formatSummary}
|
|
599
599
|
*/
|
|
600
600
|
formatStatusMessage(result) {
|
|
@@ -614,9 +614,9 @@ export class PreflightEngine {
|
|
|
614
614
|
const missingNames = optionalMissing
|
|
615
615
|
.map((c) => c.name)
|
|
616
616
|
.join("', '");
|
|
617
|
-
return `[pre-flight
|
|
617
|
+
return `[pre-flight OK] Passed with warnings: optional dep '${missingNames}' not found`;
|
|
618
618
|
}
|
|
619
|
-
return `[pre-flight
|
|
619
|
+
return `[pre-flight OK] All checks passed (${depCount} deps${privStatus})`;
|
|
620
620
|
}
|
|
621
621
|
// ── Cache management ───────────────────────────────────────────────────
|
|
622
622
|
/**
|
package/build/core/progress.js
CHANGED
|
@@ -36,10 +36,10 @@ export function renderProgressBar(percent, options) {
|
|
|
36
36
|
}
|
|
37
37
|
// ── Complexity Badges ────────────────────────────────────────────────────────
|
|
38
38
|
const COMPLEXITY_BADGES = {
|
|
39
|
-
low: "
|
|
40
|
-
medium: "
|
|
41
|
-
high: "
|
|
42
|
-
critical: "
|
|
39
|
+
low: "LOW",
|
|
40
|
+
medium: "MEDIUM",
|
|
41
|
+
high: "HIGH",
|
|
42
|
+
critical: "WARNING: CRITICAL",
|
|
43
43
|
};
|
|
44
44
|
// ── Pre-Execution Banner ─────────────────────────────────────────────────────
|
|
45
45
|
/**
|
|
@@ -58,28 +58,28 @@ export function generateDurationBanner(toolName, action, timeoutMs) {
|
|
|
58
58
|
const estimate = getDurationEstimate(toolName, action);
|
|
59
59
|
if (!estimate) {
|
|
60
60
|
// No estimate available — return minimal info
|
|
61
|
-
return
|
|
61
|
+
return `Timeout: ${formatElapsed(timeoutMs)}\n`;
|
|
62
62
|
}
|
|
63
63
|
const durationStr = formatDurationEstimate(estimate);
|
|
64
64
|
const complexityBadge = COMPLEXITY_BADGES[estimate.complexity];
|
|
65
65
|
const longRunning = isLongRunning(toolName, action);
|
|
66
66
|
if (!longRunning) {
|
|
67
67
|
// Quick tool — compact one-liner
|
|
68
|
-
return
|
|
68
|
+
return `Est: ${durationStr} | ${complexityBadge}\n`;
|
|
69
69
|
}
|
|
70
70
|
// Long-running tool — detailed banner
|
|
71
71
|
const lines = [];
|
|
72
72
|
lines.push("┌─────────────────────────────────────────────────────────┐");
|
|
73
|
-
lines.push(`│
|
|
73
|
+
lines.push(`│ ${estimate.description.padEnd(54)}│`);
|
|
74
74
|
lines.push("├─────────────────────────────────────────────────────────┤");
|
|
75
|
-
lines.push(`│
|
|
76
|
-
lines.push(`│
|
|
77
|
-
lines.push(`│
|
|
75
|
+
lines.push(`│ Duration estimate: ${durationStr.padEnd(36)}│`);
|
|
76
|
+
lines.push(`│ Complexity: ${complexityBadge.padEnd(42)}│`);
|
|
77
|
+
lines.push(`│ Timeout: ${formatElapsed(timeoutMs).padEnd(45)}│`);
|
|
78
78
|
if (estimate.supportsProgress) {
|
|
79
|
-
lines.push(`│
|
|
79
|
+
lines.push(`│ Progress tracking: enabled${" ".repeat(28)}│`);
|
|
80
80
|
}
|
|
81
81
|
if (estimate.durationFactors.length > 0) {
|
|
82
|
-
lines.push(`│
|
|
82
|
+
lines.push(`│ Factors: ${estimate.durationFactors.slice(0, 2).join(", ").padEnd(45)}│`);
|
|
83
83
|
}
|
|
84
84
|
lines.push("└─────────────────────────────────────────────────────────┘");
|
|
85
85
|
return lines.join("\n") + "\n\n";
|
|
@@ -100,22 +100,22 @@ export function generateTimingSummary(toolName, action, actualMs) {
|
|
|
100
100
|
const estimate = getDurationEstimate(toolName, action);
|
|
101
101
|
const actualStr = formatElapsed(actualMs);
|
|
102
102
|
if (!estimate) {
|
|
103
|
-
return `\
|
|
103
|
+
return `\nCompleted in ${actualStr}`;
|
|
104
104
|
}
|
|
105
105
|
const minMs = estimate.minSeconds * 1000;
|
|
106
106
|
const maxMs = estimate.maxSeconds * 1000;
|
|
107
107
|
const estimatedStr = formatDurationEstimate(estimate);
|
|
108
108
|
let indicator;
|
|
109
109
|
if (actualMs < minMs) {
|
|
110
|
-
indicator = "
|
|
110
|
+
indicator = "Faster than expected";
|
|
111
111
|
}
|
|
112
112
|
else if (actualMs > maxMs) {
|
|
113
|
-
indicator = "
|
|
113
|
+
indicator = "Slower than expected";
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
116
|
-
indicator = "
|
|
116
|
+
indicator = "PASS: Within estimate";
|
|
117
117
|
}
|
|
118
|
-
return `\
|
|
118
|
+
return `\nCompleted in ${actualStr} (est: ${estimatedStr}) — ${indicator}`;
|
|
119
119
|
}
|
|
120
120
|
// ── Timing Context Helpers ───────────────────────────────────────────────────
|
|
121
121
|
/**
|
|
@@ -181,12 +181,12 @@ export function generatePhaseBanner(phaseName, phaseNumber, tools) {
|
|
|
181
181
|
const totalMinMin = Math.ceil(totalMinSec / 60);
|
|
182
182
|
const totalMaxMin = Math.ceil(totalMaxSec / 60);
|
|
183
183
|
const avgMin = Math.ceil((totalMinMin + totalMaxMin) / 2);
|
|
184
|
-
lines.push(`║
|
|
184
|
+
lines.push(`║ TOTAL ESTIMATE: ${totalMinMin}-${totalMaxMin} min (avg: ~${avgMin} min)${" ".repeat(Math.max(0, 20 - String(totalMaxMin).length - String(avgMin).length))}║`);
|
|
185
185
|
}
|
|
186
186
|
if (hasLongRunning) {
|
|
187
|
-
lines.push("║
|
|
187
|
+
lines.push("║ WARNING: Long-running phase — progress updates included ║");
|
|
188
188
|
}
|
|
189
|
-
lines.push("║
|
|
189
|
+
lines.push("║ OK All tools will run to completion (no timeouts) ║");
|
|
190
190
|
lines.push("║ ║");
|
|
191
191
|
lines.push("╚════════════════════════════════════════════════════════════╝");
|
|
192
192
|
return lines.join("\n");
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared async command runner using spawnSafe.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the duplicate runCommand() implementations found in 11 tool files.
|
|
5
|
+
* Wraps spawnSafe in a Promise that collects stdout/stderr and handles
|
|
6
|
+
* timeouts, spawn errors, and process errors gracefully.
|
|
7
|
+
*/
|
|
8
|
+
export interface CommandResult {
|
|
9
|
+
stdout: string;
|
|
10
|
+
stderr: string;
|
|
11
|
+
exitCode: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function runCommand(command: string, args: string[], timeoutMs?: number): Promise<CommandResult>;
|
|
14
|
+
//# sourceMappingURL=run-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-command.d.ts","sourceRoot":"","sources":["../../src/core/run-command.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,SAAS,GACjB,OAAO,CAAC,aAAa,CAAC,CAyCxB"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared async command runner using spawnSafe.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the duplicate runCommand() implementations found in 11 tool files.
|
|
5
|
+
* Wraps spawnSafe in a Promise that collects stdout/stderr and handles
|
|
6
|
+
* timeouts, spawn errors, and process errors gracefully.
|
|
7
|
+
*/
|
|
8
|
+
import { spawnSafe } from "./spawn-safe.js";
|
|
9
|
+
export async function runCommand(command, args, timeoutMs = 30_000) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
let child;
|
|
12
|
+
try {
|
|
13
|
+
child = spawnSafe(command, args);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
resolve({ stdout: "", stderr: err instanceof Error ? err.message : String(err), exitCode: -1 });
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
let stdout = "";
|
|
20
|
+
let stderr = "";
|
|
21
|
+
let resolved = false;
|
|
22
|
+
const timer = setTimeout(() => {
|
|
23
|
+
if (!resolved) {
|
|
24
|
+
resolved = true;
|
|
25
|
+
child.kill("SIGTERM");
|
|
26
|
+
resolve({ stdout, stderr: stderr + "\n[TIMEOUT]", exitCode: -1 });
|
|
27
|
+
}
|
|
28
|
+
}, timeoutMs);
|
|
29
|
+
child.stdout?.on("data", (data) => { stdout += data.toString(); });
|
|
30
|
+
child.stderr?.on("data", (data) => { stderr += data.toString(); });
|
|
31
|
+
child.on("close", (code) => {
|
|
32
|
+
if (!resolved) {
|
|
33
|
+
resolved = true;
|
|
34
|
+
clearTimeout(timer);
|
|
35
|
+
resolve({ stdout, stderr, exitCode: code ?? -1 });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
child.on("error", (err) => {
|
|
39
|
+
if (!resolved) {
|
|
40
|
+
resolved = true;
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
resolve({ stdout, stderr: err.message, exitCode: -1 });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
* 2. shell: false always
|
|
14
14
|
* 3. Audit logging to stderr
|
|
15
15
|
*/
|
|
16
|
-
import { type SpawnOptions, type ExecFileSyncOptions, type ChildProcess } from "node:child_process";
|
|
17
|
-
export
|
|
18
|
-
}
|
|
19
|
-
export
|
|
20
|
-
|
|
16
|
+
import { type SpawnOptions, type ExecFileSyncOptions, type ChildProcess as NodeChildProcess } from "node:child_process";
|
|
17
|
+
/** Re-export ChildProcess type so tool files can import it without touching node:child_process directly. */
|
|
18
|
+
export type { NodeChildProcess as ChildProcess };
|
|
19
|
+
export type SpawnSafeOptions = SpawnOptions;
|
|
20
|
+
export type ExecFileSafeOptions = ExecFileSyncOptions;
|
|
21
21
|
/**
|
|
22
22
|
* Redact sensitive arguments from a command's argument array for safe logging.
|
|
23
23
|
*
|
|
@@ -41,7 +41,7 @@ export declare function redactArgs(command: string, args: readonly string[]): st
|
|
|
41
41
|
* @param options - SpawnOptions (shell is always forced to false)
|
|
42
42
|
* @throws {Error} If the command is not in the allowlist
|
|
43
43
|
*/
|
|
44
|
-
export declare function spawnSafe(command: string, args: string[], options?: SpawnSafeOptions):
|
|
44
|
+
export declare function spawnSafe(command: string, args: string[], options?: SpawnSafeOptions): NodeChildProcess;
|
|
45
45
|
/**
|
|
46
46
|
* Execute a file synchronously with allowlist enforcement and shell: false.
|
|
47
47
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn-safe.d.ts","sourceRoot":"","sources":["../../src/core/spawn-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"spawn-safe.d.ts","sourceRoot":"","sources":["../../src/core/spawn-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,YAAY,IAAI,gBAAgB,EACtC,MAAM,oBAAoB,CAAC;AAE5B,4GAA4G;AAC5G,YAAY,EAAE,gBAAgB,IAAI,YAAY,EAAE,CAAC;AAKjD,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAE5C,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AAUtD;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAgC7E;AAID;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,gBAAgB,GACzB,gBAAgB,CAUlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,GAAG,MAAM,CAiCjB"}
|
package/build/core/sudo-guard.js
CHANGED
|
@@ -188,14 +188,14 @@ export class SudoGuard {
|
|
|
188
188
|
const reasonText = reason ?? "This tool requires elevated (root) privileges to function.";
|
|
189
189
|
// Build the prompt message for AI clients.
|
|
190
190
|
const lines = [];
|
|
191
|
-
lines.push("
|
|
192
|
-
lines.push("
|
|
191
|
+
lines.push("Sudo session required");
|
|
192
|
+
lines.push("");
|
|
193
193
|
lines.push("");
|
|
194
194
|
lines.push(`Tool: ${toolName}`);
|
|
195
195
|
lines.push(`Reason: ${reasonText}`);
|
|
196
196
|
lines.push("");
|
|
197
197
|
if (status.elevated && status.remainingSeconds !== null && status.remainingSeconds <= 0) {
|
|
198
|
-
lines.push("
|
|
198
|
+
lines.push("WARNING: Your sudo session has expired.");
|
|
199
199
|
lines.push("");
|
|
200
200
|
lines.push("ACTION: Call sudo_session with action=elevate_gui to re-authenticate,");
|
|
201
201
|
lines.push("or action=extend to extend an active session.");
|
|
@@ -210,7 +210,7 @@ export class SudoGuard {
|
|
|
210
210
|
lines.push("stored in a zeroable memory buffer, and never visible to the AI.");
|
|
211
211
|
if (originalError) {
|
|
212
212
|
lines.push("");
|
|
213
|
-
lines.push("
|
|
213
|
+
lines.push("");
|
|
214
214
|
lines.push("Original error:");
|
|
215
215
|
lines.push(originalError.substring(0, 500));
|
|
216
216
|
}
|
|
@@ -471,7 +471,7 @@ async function installGithubRelease(entry) {
|
|
|
471
471
|
dryRun: false,
|
|
472
472
|
success: true,
|
|
473
473
|
}));
|
|
474
|
-
console.error(`[third-party-installer]
|
|
474
|
+
console.error(`[third-party-installer] OK ${entry.name} v${entry.version} installed successfully`);
|
|
475
475
|
return {
|
|
476
476
|
binary: entry.binary,
|
|
477
477
|
success: true,
|
|
@@ -585,7 +585,7 @@ async function installAptRepo(entry) {
|
|
|
585
585
|
console.error(`[third-party-installer] Running apt-get update...`);
|
|
586
586
|
const updateResult = execWithSudo(["apt-get", "update"], { timeoutMs: 120_000 });
|
|
587
587
|
if (!updateResult.success) {
|
|
588
|
-
console.error(`[third-party-installer]
|
|
588
|
+
console.error(`[third-party-installer] WARNING: apt-get update had issues: ${updateResult.stderr.slice(0, 200)}`);
|
|
589
589
|
}
|
|
590
590
|
const packages = entry.aptPinnedPackages ?? [entry.binary];
|
|
591
591
|
for (const pkg of packages) {
|
|
@@ -609,7 +609,7 @@ async function installAptRepo(entry) {
|
|
|
609
609
|
dryRun: false,
|
|
610
610
|
success: true,
|
|
611
611
|
}));
|
|
612
|
-
console.error(`[third-party-installer]
|
|
612
|
+
console.error(`[third-party-installer] OK ${entry.name} v${entry.version} installed successfully via APT`);
|
|
613
613
|
return {
|
|
614
614
|
binary: entry.binary,
|
|
615
615
|
success: true,
|
|
@@ -658,7 +658,7 @@ async function installNpmLocal(entry) {
|
|
|
658
658
|
dryRun: false,
|
|
659
659
|
success: true,
|
|
660
660
|
}));
|
|
661
|
-
console.error(`[third-party-installer]
|
|
661
|
+
console.error(`[third-party-installer] OK ${entry.name} v${entry.version} installed via npm`);
|
|
662
662
|
return {
|
|
663
663
|
binary: entry.binary,
|
|
664
664
|
success: true,
|
|
@@ -195,7 +195,7 @@ function createWrappedHandler(toolName, originalHandler, ctx) {
|
|
|
195
195
|
content: [
|
|
196
196
|
{
|
|
197
197
|
type: "text",
|
|
198
|
-
text:
|
|
198
|
+
text: `WARNING: Rate limit exceeded\n\n${rateLimitResult.reason}`,
|
|
199
199
|
},
|
|
200
200
|
],
|
|
201
201
|
isError: true,
|
|
@@ -269,12 +269,12 @@ function createWrappedHandler(toolName, originalHandler, ctx) {
|
|
|
269
269
|
catch (err) {
|
|
270
270
|
// Pre-flight itself threw — return error instead of running without dependency checking
|
|
271
271
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
272
|
-
console.error(`[preflight]
|
|
272
|
+
console.error(`[preflight] WARNING: Pre-flight failed unexpectedly for '${toolName}': ${errMsg}`);
|
|
273
273
|
return {
|
|
274
274
|
content: [
|
|
275
275
|
{
|
|
276
276
|
type: "text",
|
|
277
|
-
text:
|
|
277
|
+
text: `WARNING: Pre-flight internal error for '${toolName}'\n\nThe pre-flight dependency checking system encountered an unexpected error and the tool was not executed.\n\nError: ${errMsg}\n\nPlease retry the operation or check the pre-flight configuration. If this persists, the tool's dependency manifest may need attention.`,
|
|
278
278
|
},
|
|
279
279
|
],
|
|
280
280
|
isError: true,
|
|
@@ -879,8 +879,8 @@ export function registerAccessControlTools(server) {
|
|
|
879
879
|
? "CRITICAL: Weak SSH algorithms detected. Apply Mozilla Modern SSH configuration immediately."
|
|
880
880
|
: warnCount > 0
|
|
881
881
|
? "WARNING: SSH algorithms not explicitly configured. Set explicit algorithms in sshd_config."
|
|
882
|
-
: "
|
|
883
|
-
}
|
|
882
|
+
: "SSH cryptographic configuration meets modern standards.",
|
|
883
|
+
}))],
|
|
884
884
|
};
|
|
885
885
|
}
|
|
886
886
|
catch (error) {
|
|
@@ -1154,7 +1154,7 @@ export function registerAccessControlTools(server) {
|
|
|
1154
1154
|
content: [
|
|
1155
1155
|
createTextContent(`[DRY-RUN] Would write the following to ${targetFile}:\n\n` +
|
|
1156
1156
|
configLines.map((l) => ` ${l}`).join("\n") +
|
|
1157
|
-
(pwqSanityWarnings ? `\n\
|
|
1157
|
+
(pwqSanityWarnings ? `\n\nWARNING: Sanity warnings:\n${pwqSanityWarnings}` : "")),
|
|
1158
1158
|
],
|
|
1159
1159
|
};
|
|
1160
1160
|
}
|
|
@@ -1200,7 +1200,7 @@ export function registerAccessControlTools(server) {
|
|
|
1200
1200
|
content: [
|
|
1201
1201
|
createTextContent(`pam_pwquality configured in ${targetFile}:\n\n` +
|
|
1202
1202
|
configLines.map((l) => ` ${l}`).join("\n") +
|
|
1203
|
-
(pwqSanityWarnings ? `\n\
|
|
1203
|
+
(pwqSanityWarnings ? `\n\nWARNING: Sanity warnings:\n${pwqSanityWarnings}` : "")),
|
|
1204
1204
|
],
|
|
1205
1205
|
};
|
|
1206
1206
|
}
|
|
@@ -1276,7 +1276,7 @@ export function registerAccessControlTools(server) {
|
|
|
1276
1276
|
createTextContent(`[DRY-RUN] Would add/update pam_faillock.so in ${targetFile}:\n\n` +
|
|
1277
1277
|
` ${preLine}\n ${authLine}\n\n` +
|
|
1278
1278
|
`Settings: ${JSON.stringify(merged)}` +
|
|
1279
|
-
(flSanityWarnings ? `\n\
|
|
1279
|
+
(flSanityWarnings ? `\n\nWARNING: Sanity warnings:\n${flSanityWarnings}` : "")),
|
|
1280
1280
|
],
|
|
1281
1281
|
};
|
|
1282
1282
|
}
|
|
@@ -1332,7 +1332,7 @@ export function registerAccessControlTools(server) {
|
|
|
1332
1332
|
` ${preLine}\n ${authLine}\n\n` +
|
|
1333
1333
|
`Settings: ${JSON.stringify(merged)}\n` +
|
|
1334
1334
|
`Backup: ${backupEntry.backupPath}` +
|
|
1335
|
-
(flSanityWarnings ? `\n\
|
|
1335
|
+
(flSanityWarnings ? `\n\nWARNING: Sanity warnings:\n${flSanityWarnings}` : "")),
|
|
1336
1336
|
],
|
|
1337
1337
|
};
|
|
1338
1338
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-security.d.ts","sourceRoot":"","sources":["../../src/tools/api-security.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"api-security.d.ts","sourceRoot":"","sources":["../../src/tools/api-security.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA2xBpE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6WhE"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* verification, TLS configuration checking, and CORS policy analysis.
|
|
9
9
|
*/
|
|
10
10
|
import { z } from "zod";
|
|
11
|
-
import {
|
|
11
|
+
import { runCommand } from "../core/run-command.js";
|
|
12
12
|
import { createTextContent, createErrorContent, formatToolOutput, } from "../core/parsers.js";
|
|
13
13
|
// ── Constants ──────────────────────────────────────────────────────────────────
|
|
14
14
|
const DEFAULT_PORT_RANGE = "80,443,3000,4000,5000,8000,8080,8443,9000";
|
|
@@ -21,53 +21,7 @@ const COMMON_API_PATHS = [
|
|
|
21
21
|
"/openapi.json",
|
|
22
22
|
"/.well-known/openid-configuration",
|
|
23
23
|
];
|
|
24
|
-
|
|
25
|
-
* Run a command via spawnSafe and collect output as a promise.
|
|
26
|
-
* Handles errors gracefully — returns error info instead of throwing.
|
|
27
|
-
*/
|
|
28
|
-
async function runCommand(command, args, timeoutMs = 30_000) {
|
|
29
|
-
return new Promise((resolve) => {
|
|
30
|
-
let child;
|
|
31
|
-
try {
|
|
32
|
-
child = spawnSafe(command, args);
|
|
33
|
-
}
|
|
34
|
-
catch (err) {
|
|
35
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
36
|
-
resolve({ stdout: "", stderr: msg, exitCode: -1 });
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
let stdout = "";
|
|
40
|
-
let stderr = "";
|
|
41
|
-
let resolved = false;
|
|
42
|
-
const timer = setTimeout(() => {
|
|
43
|
-
if (!resolved) {
|
|
44
|
-
resolved = true;
|
|
45
|
-
child.kill("SIGTERM");
|
|
46
|
-
resolve({ stdout, stderr: stderr + "\n[TIMEOUT]", exitCode: -1 });
|
|
47
|
-
}
|
|
48
|
-
}, timeoutMs);
|
|
49
|
-
child.stdout?.on("data", (data) => {
|
|
50
|
-
stdout += data.toString();
|
|
51
|
-
});
|
|
52
|
-
child.stderr?.on("data", (data) => {
|
|
53
|
-
stderr += data.toString();
|
|
54
|
-
});
|
|
55
|
-
child.on("close", (code) => {
|
|
56
|
-
if (!resolved) {
|
|
57
|
-
resolved = true;
|
|
58
|
-
clearTimeout(timer);
|
|
59
|
-
resolve({ stdout, stderr, exitCode: code ?? -1 });
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
child.on("error", (err) => {
|
|
63
|
-
if (!resolved) {
|
|
64
|
-
resolved = true;
|
|
65
|
-
clearTimeout(timer);
|
|
66
|
-
resolve({ stdout, stderr: err.message, exitCode: -1 });
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
}
|
|
24
|
+
// ── Helpers ────────────────────────────────────────────────────────────────────
|
|
71
25
|
/**
|
|
72
26
|
* Validate and normalize a target URL.
|
|
73
27
|
* Returns the normalized URL or null if invalid.
|
|
@@ -692,7 +646,7 @@ export function registerApiSecurityTools(server) {
|
|
|
692
646
|
text += `Auth Type: ${authResult.authType}\n`;
|
|
693
647
|
text += `Status without auth: ${authResult.statusWithoutAuth}\n`;
|
|
694
648
|
text += `Status with auth: ${authResult.statusWithAuth}\n`;
|
|
695
|
-
text += `Verbose Errors: ${authResult.verboseErrors ? "YES
|
|
649
|
+
text += `Verbose Errors: ${authResult.verboseErrors ? "YES WARNING" : "no"}\n`;
|
|
696
650
|
if (authResult.errorDetails.length > 0) {
|
|
697
651
|
text += `\nError Details:\n`;
|
|
698
652
|
for (const detail of authResult.errorDetails) {
|
|
@@ -864,8 +818,8 @@ export function registerApiSecurityTools(server) {
|
|
|
864
818
|
text += `Allow-Origin: ${corsResult.allowOrigin}\n`;
|
|
865
819
|
text += `Allow-Credentials: ${corsResult.allowCredentials}\n`;
|
|
866
820
|
text += `Allow-Methods: ${corsResult.allowMethods || "not specified"}\n`;
|
|
867
|
-
text += `Wildcard Origin: ${corsResult.wildcardOrigin ? "YES
|
|
868
|
-
text += `Origin Reflection: ${corsResult.originReflection ? "YES
|
|
821
|
+
text += `Wildcard Origin: ${corsResult.wildcardOrigin ? "YES WARNING" : "no"}\n`;
|
|
822
|
+
text += `Origin Reflection: ${corsResult.originReflection ? "YES WARNING" : "no"}\n`;
|
|
869
823
|
}
|
|
870
824
|
if (corsResult.criticalIssues.length > 0) {
|
|
871
825
|
text += `\nCritical Issues:\n`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-hardening.d.ts","sourceRoot":"","sources":["../../src/tools/app-hardening.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6dpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"app-hardening.d.ts","sourceRoot":"","sources":["../../src/tools/app-hardening.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6dpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6XjE"}
|