/**
* mcp/skills/checkFirewallStatus.ts — check_firewall_status skill
*
* Reports the current state of the operating system firewall. Useful during
* security compliance checks, network troubleshooting, or when verifying
* security agent health.
*
* Platform strategy
* -----------------
* darwin ApplicationFirewall socketfilterfw CLI flags
* win32 PowerShell Get-NetFirewallProfile | ConvertTo-Json
*
* Smoke test
* npx tsx -r dotenv/config mcp/skills/checkFirewallStatus.ts
*/
import * as os from "os" ;
import { exec } from "child_process" ;
import { promisify } from "util" ;
import { z } from "zod" ;
const execAsync = promisify (exec);
// -- Meta ---------------------------------------------------------------------
export const meta = {
name: "check_firewall_status" ,
description:
"Reports the current state of the operating system firewall. " +
"Use during security compliance checks, network troubleshooting, or when " +
"verifying security agent health." ,
riskLevel: "low" ,
destructive: false ,
requiresConsent: false ,
supportsDryRun: false ,
affectedScope: [ "user" ],
auditRequired: false ,
schema: {} as Record < string , z . ZodTypeAny >,
} as const ;
// -- Types --------------------------------------------------------------------
interface WinFirewallProfile {
Name : string ;
Enabled : boolean ;
}
interface FirewallResult {
platform : string ;
enabled : boolean ;
stealthMode : boolean ;
blockAllConnections : boolean ;
profiles ?: WinFirewallProfile [];
error ?: string ;
}
// -- PowerShell helper --------------------------------------------------------
async function runPS ( script : string ) : Promise < string > {
const encoded = Buffer. from (script, "utf16le" ). toString ( "base64" );
const { stdout } = await execAsync (
`powershell.exe -NoProfile -NonInteractive -EncodedCommand ${ encoded }` ,
{ maxBuffer: 10 * 1024 * 1024 },
);
return stdout. trim ();
}
// -- darwin implementation ----------------------------------------------------
const SOCKETFILTERFW = "/usr/libexec/ApplicationFirewall/socketfilterfw" ;
async function queryFirewallFlag ( flag : string ) : Promise < boolean > {
try {
const { stdout } = await execAsync ( `${ SOCKETFILTERFW } ${ flag } 2>&1` );
// Output is like "Firewall is enabled. (State = 1)"
// or "Block all INCOMING connections mode disabled! (State = 0)"
return / State \s * = \s * 1 / . test (stdout) || / \b enabled \b / i . test (stdout);
} catch {
return false ;
}
}
async function checkFirewallDarwin () : Promise < FirewallResult > {
const [ enabled , stealthMode , blockAllConnections ] = await Promise . all ([
queryFirewallFlag ( "--getglobalstate" ),
queryFirewallFlag ( "--getstealthmode" ),
queryFirewallFlag ( "--getblockall" ),
]);
return {
platform: "darwin" ,
enabled,
stealthMode,
blockAllConnections,
};
}
// -- win32 implementation -----------------------------------------------------
async function checkFirewallWin32 () : Promise < FirewallResult > {
const ps = `
$ErrorActionPreference = 'SilentlyContinue'
Get-NetFirewallProfile | Select-Object Name, Enabled | ConvertTo-Json -Depth 2 -Compress` . trim ();
try {
const raw = await runPS (ps);
const parsed = JSON . parse (raw) as WinFirewallProfile | WinFirewallProfile [];
const profiles = Array. isArray (parsed) ? parsed : [parsed];
const anyEnabled = profiles. some (( p ) => p.Enabled === true );
return {
platform: "win32" ,
enabled: anyEnabled,
stealthMode: false , // Windows uses different concept (stealth is per-rule)
blockAllConnections: false , // Not a single toggle in Windows; per-profile
profiles,
};
} catch (err) {
return {
platform: "win32" ,
enabled: false ,
stealthMode: false ,
blockAllConnections: false ,
error: (err as Error ).message,
};
}
}
// -- Exported run function ----------------------------------------------------
export async function run ( _args : Record < string , never > = {} as Record < string , never >) {
const platform = os. platform ();
return platform === "win32"
? checkFirewallWin32 ()
: checkFirewallDarwin ();
}
// -- CLI smoke test -----------------------------------------------------------
if ( false ) {
run ({})
. then (( r ) => console. log ( JSON . stringify (r, null , 2 )))
. catch (( err : Error ) => { console. error (err.message); process. exit ( 1 ); });
}