Files
pikasTech-unidesk/scripts/src/ssh.test.ts
T
2026-06-20 07:23:11 +00:00

112 lines
4.5 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import {
createSshStdoutForwarder,
formatSshStdoutTruncationHint,
parseSshInvocation,
sshStdoutStreamMaxBytes,
sshStdoutTruncationHint,
windowsPowerShellScriptPrelude,
} from "./ssh";
describe("ssh windows PowerShell safety prelude", () => {
test("shadows ConvertTo-Json and strips filesystem ETS metadata", () => {
const prelude = windowsPowerShellScriptPrelude("C:\\test");
expect(prelude).toContain("function ConvertTo-UniDeskPlainJsonValue");
expect(prelude).toContain("function ConvertTo-Json");
expect(prelude).toContain("'PSPath','PSParentPath','PSChildName','PSDrive','PSProvider','ReadCount'");
expect(prelude).toContain("Microsoft.PowerShell.Utility\\ConvertTo-Json");
expect(prelude).toContain("Set-Location -LiteralPath 'C:\\test'");
});
});
describe("ssh stdout bounded streaming", () => {
test("uses bounded defaults and clamps env override", () => {
expect(sshStdoutStreamMaxBytes({} as NodeJS.ProcessEnv)).toBe(256 * 1024);
expect(sshStdoutStreamMaxBytes({ UNIDESK_SSH_STDOUT_STREAM_MAX_BYTES: "8192" } as NodeJS.ProcessEnv)).toBe(8192);
expect(sshStdoutStreamMaxBytes({ UNIDESK_SSH_STDOUT_STREAM_MAX_BYTES: "1" } as NodeJS.ProcessEnv)).toBe(4096);
expect(sshStdoutStreamMaxBytes({ UNIDESK_SSH_STDOUT_STREAM_MAX_BYTES: String(64 * 1024 * 1024) } as NodeJS.ProcessEnv)).toBe(16 * 1024 * 1024);
});
test("formats truncation hint without echoing remote command", () => {
const invocation = parseSshInvocation("D601:win", ["ps"]);
expect(invocation.parsed.remoteCommand).not.toBeNull();
const hint = sshStdoutTruncationHint({
invocation,
transport: "backend-core-broker",
thresholdBytes: 4096,
observedBytesAtTruncation: 5000,
dumpPath: "/tmp/unidesk-cli-output/sample.stdout.bin",
});
const formatted = formatSshStdoutTruncationHint(hint);
expect(formatted.startsWith("UNIDESK_SSH_STDOUT_TRUNCATED ")).toBe(true);
const payload = JSON.parse(formatted.slice("UNIDESK_SSH_STDOUT_TRUNCATED ".length)) as Record<string, unknown>;
expect(payload.code).toBe("ssh-stdout-truncated");
expect(payload.providerId).toBe("D601");
expect(payload.route).toBe("D601:win");
expect(payload.thresholdBytes).toBe(4096);
expect(formatted).not.toContain("Get-Content");
});
test("forwarder bounds stdout and emits one truncation hint", () => {
const invocation = parseSshInvocation("D601:win", ["ps"]);
const forwarded: Buffer[] = [];
const stdout = {
write(chunk: string | Buffer): boolean {
forwarded.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
return true;
},
} as NodeJS.WritableStream;
const forwarder = createSshStdoutForwarder({
invocation,
transport: "frontend-websocket",
maxBytes: 5,
stdout,
});
expect(forwarder.write(Buffer.from("abc"))).toBeNull();
const hint = forwarder.write(Buffer.from("defgh"));
expect(hint).not.toBeNull();
expect(forwarder.write(Buffer.from("ijkl"))).toBeNull();
expect(Buffer.concat(forwarded).toString("utf8")).toBe("abcde");
expect(hint).toContain("UNIDESK_SSH_STDOUT_TRUNCATED");
expect(hint).toContain("\"transport\":\"frontend-websocket\"");
});
});
describe("ssh removed shell aliases", () => {
test("reports route-aware replacement examples for trans script", () => {
const previousEntrypoint = process.env.UNIDESK_SSH_ENTRYPOINT;
process.env.UNIDESK_SSH_ENTRYPOINT = "trans";
try {
parseSshInvocation("D601:/tmp", ["script", "--", "pwd"]);
throw new Error("expected script alias to fail");
} catch (error) {
expect(error).toBeInstanceOf(Error);
const payload = error as Error & {
code?: string;
entrypoint?: string;
route?: string;
operation?: string;
replacementExamples?: {
posixSh?: string;
bash?: string;
};
};
expect(payload.code).toBe("ssh-removed-shell-alias");
expect(payload.entrypoint).toBe("trans");
expect(payload.route).toBe("D601:/tmp");
expect(payload.operation).toBe("script");
expect(payload.replacementExamples?.posixSh).toBe("trans D601:/tmp sh -- 'pwd'");
expect(payload.replacementExamples?.bash).toBe("trans D601:/tmp bash -- 'pwd'");
} finally {
if (previousEntrypoint === undefined) {
delete process.env.UNIDESK_SSH_ENTRYPOINT;
} else {
process.env.UNIDESK_SSH_ENTRYPOINT = previousEntrypoint;
}
}
});
});