92 lines
3.8 KiB
JavaScript
92 lines
3.8 KiB
JavaScript
|
|
const test = require("node:test");
|
||
|
|
const assert = require("node:assert/strict");
|
||
|
|
const { EventEmitter } = require("node:events");
|
||
|
|
|
||
|
|
const {
|
||
|
|
DEFAULT_REUSED_SHELL_LIVENESS_MS,
|
||
|
|
remoteAllowsIdleParkedShellReuse,
|
||
|
|
remoteNeedsReusedShellLivenessCheck,
|
||
|
|
shouldConfirmReusedShellLiveness,
|
||
|
|
resolveReusedShellLivenessMs,
|
||
|
|
waitForReusedShellLiveness,
|
||
|
|
} = require("./sshIdleParkPolicy.cjs");
|
||
|
|
|
||
|
|
test("TERM-SSHD cannot host a later shell on a parked transport", () => {
|
||
|
|
assert.equal(remoteAllowsIdleParkedShellReuse("TERM-SSHD"), false);
|
||
|
|
assert.equal(remoteAllowsIdleParkedShellReuse("SSH-2.0-TERM-SSHD"), false);
|
||
|
|
assert.equal(remoteAllowsIdleParkedShellReuse("term-sshd"), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("OpenSSH and Dropbear still allow idle-park shell reuse", () => {
|
||
|
|
assert.equal(remoteAllowsIdleParkedShellReuse("OpenSSH_9.6"), true);
|
||
|
|
assert.equal(remoteAllowsIdleParkedShellReuse("SSH-2.0-OpenSSH_9.6"), true);
|
||
|
|
assert.equal(remoteAllowsIdleParkedShellReuse("dropbear_2024.85"), true);
|
||
|
|
assert.equal(remoteAllowsIdleParkedShellReuse(""), true);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("shouldConfirmReusedShellLiveness covers idle park and SFTP-held last-shell close", () => {
|
||
|
|
assert.equal(shouldConfirmReusedShellLiveness({
|
||
|
|
state: "idle",
|
||
|
|
remoteSshVersion: "CustomBastion_1.0",
|
||
|
|
}), true);
|
||
|
|
assert.equal(shouldConfirmReusedShellLiveness({
|
||
|
|
state: "live",
|
||
|
|
pendingShellReconnectRisk: { oldShellPids: [], hasUnknownOldShell: true },
|
||
|
|
remoteSshVersion: "TERM-SSHD",
|
||
|
|
}), true);
|
||
|
|
assert.equal(shouldConfirmReusedShellLiveness({
|
||
|
|
state: "live",
|
||
|
|
remoteSshVersion: "CustomBastion_1.0",
|
||
|
|
}), false);
|
||
|
|
assert.equal(shouldConfirmReusedShellLiveness({
|
||
|
|
state: "idle",
|
||
|
|
remoteSshVersion: "OpenSSH_9.0",
|
||
|
|
}), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("unknown banners get a reused-shell liveness check; OpenSSH does not", () => {
|
||
|
|
assert.equal(remoteNeedsReusedShellLivenessCheck("TERM-SSHD"), true);
|
||
|
|
assert.equal(remoteNeedsReusedShellLivenessCheck("CustomBastion_1.0"), true);
|
||
|
|
assert.equal(remoteNeedsReusedShellLivenessCheck(""), true);
|
||
|
|
assert.equal(remoteNeedsReusedShellLivenessCheck("OpenSSH_9.0"), false);
|
||
|
|
assert.equal(remoteNeedsReusedShellLivenessCheck("SSH-2.0-OpenSSH_9.0"), false);
|
||
|
|
assert.equal(remoteNeedsReusedShellLivenessCheck("dropbear_2022.83"), false);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("resolveReusedShellLivenessMs clamps invalid values to the default", () => {
|
||
|
|
assert.equal(resolveReusedShellLivenessMs(undefined), DEFAULT_REUSED_SHELL_LIVENESS_MS);
|
||
|
|
assert.equal(resolveReusedShellLivenessMs(-1), DEFAULT_REUSED_SHELL_LIVENESS_MS);
|
||
|
|
assert.equal(resolveReusedShellLivenessMs("nope"), DEFAULT_REUSED_SHELL_LIVENESS_MS);
|
||
|
|
assert.equal(resolveReusedShellLivenessMs(40), 40);
|
||
|
|
assert.equal(resolveReusedShellLivenessMs(0), 0);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("waitForReusedShellLiveness fails when the channel exits before settle", async () => {
|
||
|
|
const stream = new EventEmitter();
|
||
|
|
const pending = waitForReusedShellLiveness(stream, { settleMs: 50 });
|
||
|
|
stream.emit("exit", 0);
|
||
|
|
stream.emit("close");
|
||
|
|
const result = await pending;
|
||
|
|
assert.equal(result.alive, false);
|
||
|
|
assert.equal(result.reason, "exit");
|
||
|
|
assert.equal(result.code, 0);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("waitForReusedShellLiveness keeps buffered output when the shell stays up", async () => {
|
||
|
|
const stream = new EventEmitter();
|
||
|
|
const pending = waitForReusedShellLiveness(stream, { settleMs: 15 });
|
||
|
|
stream.emit("data", Buffer.from("banner\n"));
|
||
|
|
const result = await pending;
|
||
|
|
assert.equal(result.alive, true);
|
||
|
|
assert.equal(result.reason, "settle");
|
||
|
|
assert.equal(Buffer.concat(result.buffered).toString(), "banner\n");
|
||
|
|
});
|
||
|
|
|
||
|
|
test("waitForReusedShellLiveness treats an already-closed stream as dead", async () => {
|
||
|
|
const stream = new EventEmitter();
|
||
|
|
stream.closed = true;
|
||
|
|
const result = await waitForReusedShellLiveness(stream, { settleMs: 50 });
|
||
|
|
assert.equal(result.alive, false);
|
||
|
|
assert.equal(result.reason, "already-closed");
|
||
|
|
});
|