"use strict"; const test = require("node:test"); const assert = require("node:assert/strict"); const { spawnSync } = require("node:child_process"); const { EventEmitter } = require("node:events"); const fs = require("node:fs"); const path = require("node:path"); const { createSystemManagerBridge } = require("./systemManagerBridge.cjs"); function createFakeExecStream(stdout, options = {}) { const stream = new EventEmitter(); stream.stderr = new EventEmitter(); process.nextTick(() => { if (stdout) stream.emit("data", stdout); if (options.stderr) stream.stderr.emit("data", options.stderr); stream.emit("close", options.code ?? 0); }); return stream; } function runProcessCommandWithBusyBoxPs(command, { supportsWide = true, supportsTop = true, topHasCpuColumn = false, topUsesPercentSymbols = true, } = {}) { const prefix = "exec sh -c '"; assert.ok(command.startsWith(prefix) && command.endsWith("'")); const innerScript = command.slice(prefix.length, -1); const processOutput = [ " PID USER VSZ STAT COMMAND", " 1 root 1356 S /sbin/procd", " 411 root 97.6m S /sbin/ubusd", ]; const printProcessOutput = processOutput .map((line) => `printf '%s\\n' '${line}'`) .join("\n"); const fakePs = [ "exec 3>&2", "top() {", " printf '__TOP_CALL__=%s\\n' \"$*\" >&3", supportsTop ? " :" : " return 1", " printf '%s\\n' 'Mem: 2059948K used, 14365980K free, 52256K shrd, 204K buff, 599840K cached'", " printf '%s\\n' 'CPU: 0% usr 0% sys 0% nic 99% idle 0% io 0% irq 0% sirq'", topHasCpuColumn ? " printf '%s\\n' ' PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND'" : " printf '%s\\n' ' PID PPID USER STAT VSZ %VSZ %CPU COMMAND'", topHasCpuColumn ? ` printf '%s\\n' ' 1 0 root S 1356 1${topUsesPercentSymbols ? "%" : ".0"} 0 2${topUsesPercentSymbols ? "%" : ".0"} /sbin/procd'` : ` printf '%s\\n' ' 1 0 root S 1356 1${topUsesPercentSymbols ? "%" : ".0"} 2${topUsesPercentSymbols ? "%" : ".0"} /sbin/procd'`, topHasCpuColumn ? ` printf '%s\\n' ' 411 1 root R 97.6m 10${topUsesPercentSymbols ? "%" : ".0"} 3 7${topUsesPercentSymbols ? "%" : ".0"} /sbin/ubusd'` : ` printf '%s\\n' ' 411 1 root R 97.6m 10${topUsesPercentSymbols ? "%" : ".0"} 7${topUsesPercentSymbols ? "%" : ".0"} /sbin/ubusd'`, "}", "ps() {", " printf '__PS_CALL__=%s\\n' \"$*\" >&3", " if [ \"$1\" = '-eo' ]; then", " printf '%s\\n' 'ps: unrecognized option: e' >&2", " return 1", " fi", " if [ \"$#\" -eq 1 ] && [ \"$1\" = 'ww' ]; then", supportsWide ? printProcessOutput : " return 1", " return 0", " fi", " if [ \"$#\" -eq 0 ]; then", printProcessOutput, " return 0", " fi", " return 1", "}", innerScript, ].join("\n"); const result = spawnSync("sh", ["-c", fakePs], { encoding: "utf8" }); const calls = String(result.stderr || "") .split("\n") .filter((line) => line.startsWith("__PS_CALL__=")) .map((line) => line.slice("__PS_CALL__=".length)); const topCalls = String(result.stderr || "") .split("\n") .filter((line) => line.startsWith("__TOP_CALL__=")) .map((line) => line.slice("__TOP_CALL__=".length)); return { stdout: String(result.stdout || ""), stderr: String(result.stderr || ""), code: result.status ?? 1, calls, topCalls, }; } test("listProcesses preserves BusyBox top CPU and memory percentages", async () => { let seenTopCalls = []; const conn = { exec(command, callback) { const execution = runProcessCommandWithBusyBoxPs(command); seenTopCalls = execution.topCalls; callback(null, createFakeExecStream(execution.stdout, execution)); }, }; const sessions = new Map([["openwrt", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.listProcesses(null, { sessionId: "openwrt" }); assert.equal(result.success, true); assert.equal(result.processes[0].cpuPercent, 2); assert.equal(result.processes[0].memPercent, 1); assert.equal(result.processes[1].cpuPercent, 7); assert.equal(result.processes[1].memPercent, 10); assert.deepEqual(seenTopCalls, ["-b -n 1"]); }); test("listProcesses accepts BusyBox top output with a CPU column", async () => { const conn = { exec(command, callback) { const execution = runProcessCommandWithBusyBoxPs(command, { topHasCpuColumn: true }); callback(null, createFakeExecStream(execution.stdout, execution)); }, }; const sessions = new Map([["openwrt", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.listProcesses(null, { sessionId: "openwrt" }); assert.equal(result.success, true); assert.equal(result.processes.length, 2); assert.deepEqual(result.processes.map(({ pid, cpuPercent, memPercent, command }) => ({ pid, cpuPercent, memPercent, command, })), [ { pid: 1, cpuPercent: 2, memPercent: 1, command: "/sbin/procd" }, { pid: 411, cpuPercent: 7, memPercent: 10, command: "/sbin/ubusd" }, ]); }); test("listProcesses accepts BusyBox top percentages without percent symbols", async () => { const conn = { exec(command, callback) { const execution = runProcessCommandWithBusyBoxPs(command, { topHasCpuColumn: true, topUsesPercentSymbols: false, }); callback(null, createFakeExecStream(execution.stdout, execution)); }, }; const sessions = new Map([["openwrt", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.listProcesses(null, { sessionId: "openwrt" }); assert.equal(result.success, true); assert.deepEqual(result.processes.map(({ pid, cpuPercent, memPercent, command }) => ({ pid, cpuPercent, memPercent, command, })), [ { pid: 1, cpuPercent: 2, memPercent: 1, command: "/sbin/procd" }, { pid: 411, cpuPercent: 7, memPercent: 10, command: "/sbin/ubusd" }, ]); }); test("listProcesses uses a ps format that works on CentOS 7 procps", async () => { const compatiblePsFormat = "ps -eo pid= -o ppid= -o user= -o stat= -o pcpu= -o pmem= -o rss= -o vsz= -o etime= -o args="; const badCentos7Output = [ ",ppid=,user=,stat=,pcpu=,pmem=,rss=,vsz=,etime=,args=", " 1", ].join("\n"); const compatibleOutput = [ " 1 0 root Ss 0.0 0.0 4060 191024 2-19:23:42 /usr/lib/systemd/systemd --switched-root --system --deserialize 21", ].join("\n"); let seenCommand = ""; const conn = { exec(command, callback) { seenCommand = command; const stdout = command.includes(compatiblePsFormat) ? compatibleOutput : badCentos7Output; callback(null, createFakeExecStream(stdout)); }, }; const sessions = new Map([["s1", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.listProcesses(null, { sessionId: "s1" }); assert.equal(result.success, true); assert.equal(result.processes.length, 1); assert.equal(result.processes[0].pid, 1); assert.equal(result.processes[0].command, "/usr/lib/systemd/systemd --switched-root --system --deserialize 21"); assert.doesNotMatch(seenCommand, /head\s+-n\s+2000/); }); test("listProcesses returns processes from the default OpenWrt BusyBox top format", async () => { let seenCommand = ""; let seenPsCalls = []; const conn = { exec(command, callback) { seenCommand = command; const execution = runProcessCommandWithBusyBoxPs(command); seenPsCalls = execution.calls; callback(null, createFakeExecStream(execution.stdout, execution)); }, }; const sessions = new Map([["openwrt", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.listProcesses(null, { sessionId: "openwrt" }); assert.equal(result.success, true); assert.equal(result.processes.length, 2); assert.deepEqual(result.processes[0], { pid: 1, ppid: 0, user: "root", stat: "S", cpuPercent: 2, memPercent: 1, rssKb: 0, vszKb: 1356, elapsed: "", command: "/sbin/procd", }); assert.equal(result.processes[1].vszKb, 99942); assert.match(seenCommand, /ps ww/); assert.equal(seenPsCalls.length, 1); assert.match(seenPsCalls[0], /^-eo pid=/); }); test("listProcesses falls back to plain BusyBox ps when wide output is unavailable", async () => { let seenPsCalls = []; const conn = { exec(command, callback) { const execution = runProcessCommandWithBusyBoxPs(command, { supportsWide: false, supportsTop: false }); seenPsCalls = execution.calls; callback(null, createFakeExecStream(execution.stdout, execution)); }, }; const sessions = new Map([["openwrt", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.listProcesses(null, { sessionId: "openwrt" }); assert.equal(result.success, true); assert.equal(result.processes.length, 2); assert.equal(result.processes[0].command, "/sbin/procd"); assert.equal(result.processes[1].vszKb, 99942); assert.equal(seenPsCalls.length, 3); assert.match(seenPsCalls[0], /^-eo pid=/); assert.equal(seenPsCalls[1], "ww"); assert.equal(seenPsCalls[2], ""); }); test("process listing commands do not hard-cap the visible list at 2000 entries", () => { const source = fs.readFileSync(path.join(__dirname, "systemManagerBridge.cjs"), "utf8"); assert.doesNotMatch(source, /head\s+-n\s+2000/); assert.doesNotMatch(source, /Select-Object\s+-First\s+2000/); }); test("listProcesses gives ET process listing enough output buffer for dense hosts", async () => { let seenOptions = null; const sessions = new Map([["s1", { type: "et", etStatsAuth: { knownHosts: [] }, }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, execOnEtSession: async (_session, _command, _timeoutMs, options) => { seenOptions = options; return { success: true, stdout: "" }; }, }); const result = await bridge.listProcesses(null, { sessionId: "s1" }); assert.equal(result.success, true); assert.ok(seenOptions.maxBuffer > 10 * 1024 * 1024); }); test("listProcesses gives Windows process listing enough output buffer for dense local hosts", () => { const source = fs.readFileSync(path.join(__dirname, "systemManagerBridge.cjs"), "utf8"); assert.match( source, /execOnLocalMachine\(\s*"Get-CimInstance Win32_Process[\s\S]+10000,\s*\{\s*maxBuffer:\s*PROCESS_LIST_MAX_BUFFER\s*\}/, ); }); test("probeCapabilities reports Docker when docker is installed even if plain docker access is denied", async () => { const conn = { exec(command, callback) { assert.match(command, /command -v docker/); assert.match(command, /command -v nvidia-smi/); assert.match(command, /command -v npu-smi/); assert.match(command, /command -v ss/); assert.match(command, /command -v systemctl/); assert.doesNotMatch(command, /docker info/); assert.doesNotMatch(command, /docker\.sock/); callback(null, createFakeExecStream( "__NC_OS__=Linux\n__NC_DOCKER__=1\n__NC_NVIDIA_SMI__=1\n__NC_SS__=1\n__NC_SYSTEMCTL__=1\n", )); }, }; const sessions = new Map([["s1", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.probeCapabilities(null, { sessionId: "s1" }); assert.equal(result.success, true); assert.equal(result.capabilities.hasDocker, true); assert.equal(result.capabilities.hasNvidiaSmi, true); assert.equal(result.capabilities.hasNpuSmi, false); assert.equal(result.capabilities.hasSs, true); assert.equal(result.capabilities.hasSystemctl, true); }); test("setupOsc7Tracking runs the setup command through the active session executor", async () => { let seenCommand = ""; const conn = { exec(command, callback) { seenCommand = command; callback(null, createFakeExecStream("__NETCATTY_OSC7_SETUP_SHELL__=bash\n")); }, }; const sessions = new Map([["s1", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.setupOsc7Tracking(null, { sessionId: "s1", command: "printf setup-script", }); assert.equal(result.success, true); assert.equal(result.stdout, "__NETCATTY_OSC7_SETUP_SHELL__=bash\n"); assert.equal(seenCommand, "printf setup-script"); }); test("setupOsc7Tracking reports non-zero setup exits as failures", async () => { const conn = { exec(_command, callback) { callback(null, createFakeExecStream("", { code: 2, stderr: "unsupported shell\n" })); }, }; const sessions = new Map([["s1", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.setupOsc7Tracking(null, { sessionId: "s1", command: "printf setup-script", }); assert.equal(result.success, false); assert.equal(result.code, 2); assert.match(result.error, /unsupported shell/); }); test("signalProcess reports non-zero kill exits as failures", async () => { const conn = { exec(_command, callback) { callback(null, createFakeExecStream("", { code: 1, stderr: "kill: (99999): No such process\n" })); }, }; const sessions = new Map([["s1", { conn, type: "ssh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.signalProcess(null, { sessionId: "s1", pid: 99999, signal: "TERM", }); assert.equal(result.success, false); assert.equal(result.code, 1); assert.match(result.error, /No such process/); }); test("signalProcess propagates pending when the SSH channel is unavailable", async () => { const sessions = new Map([["mosh1", { type: "mosh" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process, }); const result = await bridge.signalProcess(null, { sessionId: "mosh1", pid: 42, signal: "TERM", }); assert.equal(result.success, false); assert.equal(result.pending, true); }); test("signalProcess rejects Windows-only STOP/CONT on local win32 sessions", async () => { const sessions = new Map([["local", { type: "local" }]]); const bridge = createSystemManagerBridge({ getSessions: () => sessions, process: { ...process, platform: "win32" }, }); const result = await bridge.signalProcess(null, { sessionId: "local", pid: 42, signal: "STOP", }); assert.equal(result.success, false); assert.match(result.error, /not supported on Windows/i); });