Files
NetMesh/domain/terminalHostResolution.test.ts
zhaolei 3c72efcb7f
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

491 lines
12 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import type { GroupConfig, Host, ProxyProfile, TerminalSession } from "./models";
import {
resolveTerminalChainHosts,
resolveTerminalSessionHost,
} from "./terminalHostResolution";
const baseSession: TerminalSession = {
id: "session-1",
hostId: "target",
hostLabel: "Target",
hostname: "target.example.test",
username: "alice",
port: 22,
protocol: "ssh",
status: "connected",
createdAt: 1,
};
const proxyProfiles: ProxyProfile[] = [{
id: "proxy-1",
label: "Office proxy",
config: {
type: "http",
host: "proxy.example.test",
port: 3128,
username: "proxy-user",
},
createdAt: 1,
}];
test("resolveTerminalSessionHost materializes a saved proxy profile for popup terminals", () => {
const host: Host = {
id: "target",
label: "Target",
hostname: "target.example.test",
username: "alice",
port: 22,
protocol: "ssh",
tags: [],
os: "linux",
proxyProfileId: "proxy-1",
};
const resolved = resolveTerminalSessionHost({
session: baseSession,
hosts: [host],
groupConfigs: [],
proxyProfiles,
localOs: "linux",
});
assert.equal(resolved.proxyProfileId, "proxy-1");
assert.deepEqual(resolved.proxyConfig, proxyProfiles[0].config);
});
test("resolveTerminalSessionHost applies group default proxy profiles before opening popup terminals", () => {
const host: Host = {
id: "target",
label: "Target",
hostname: "target.example.test",
username: "alice",
port: 22,
protocol: "ssh",
tags: [],
os: "linux",
group: "prod/web",
};
const groupConfigs: GroupConfig[] = [
{ path: "prod", proxyProfileId: "proxy-1" },
];
const resolved = resolveTerminalSessionHost({
session: baseSession,
hosts: [host],
groupConfigs,
proxyProfiles,
localOs: "linux",
});
assert.equal(resolved.proxyProfileId, "proxy-1");
assert.deepEqual(resolved.proxyConfig, proxyProfiles[0].config);
});
test("resolveTerminalSessionHost defaults missing saved remote sessions to SSH", () => {
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
protocol: undefined,
},
hosts: [],
groupConfigs: [],
proxyProfiles,
localOs: "macos",
});
assert.equal(resolved.protocol, "ssh");
assert.equal(resolved.hostname, "target.example.test");
assert.equal(resolved.username, "alice");
assert.equal(resolved.os, "linux");
});
test("resolveTerminalSessionHost keeps explicit missing local sessions local", () => {
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
protocol: "local",
hostname: "localhost",
username: "local",
},
hosts: [],
groupConfigs: [],
proxyProfiles,
localOs: "macos",
});
assert.equal(resolved.protocol, "local");
assert.equal(resolved.os, "macos");
});
test("resolveTerminalSessionHost restores a missing plugin host from the session snapshot", () => {
const providerId = "com.example.transport.connection";
const pluginConnection = {
providerId,
configuration: { endpoint: "saved.example", mode: "opaque" },
};
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
hostId: "missing-plugin-host",
protocol: `plugin:${providerId}`,
pluginConnection,
},
hosts: [],
groupConfigs: [],
proxyProfiles,
localOs: "macos",
});
assert.equal(resolved.protocol, `plugin:${providerId}`);
assert.deepEqual(resolved.pluginConnection, pluginConnection);
});
test("resolveTerminalSessionHost keeps the session plugin configuration when the Vault host changes", () => {
const providerId = "com.example.transport.connection";
const protocol = `plugin:${providerId}` as const;
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
protocol,
pluginConnection: { providerId, configuration: { endpoint: "session.example" } },
},
hosts: [{
id: "target",
label: "Target",
hostname: providerId,
username: "",
tags: [],
os: "linux",
protocol,
pluginConnection: { providerId, configuration: { endpoint: "vault.example" } },
}],
groupConfigs: [],
proxyProfiles,
localOs: "linux",
});
assert.deepEqual(resolved.pluginConnection, {
providerId,
configuration: { endpoint: "session.example" },
});
});
test("resolveTerminalSessionHost carries local session start directory into fallback host", () => {
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
protocol: "local",
hostname: "localhost",
username: "local",
localStartDir: "/Users/alice/project",
},
hosts: [],
groupConfigs: [],
proxyProfiles,
localOs: "macos",
});
assert.equal(resolved.protocol, "local");
assert.equal(resolved.localStartDir, "/Users/alice/project");
});
test("resolveTerminalSessionHost carries serial Ctrl-H backspace behavior into quick sessions", () => {
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
hostId: "serial-session-1",
hostLabel: "Serial: COM3",
hostname: "COM3",
username: "",
protocol: "serial",
serialConfig: {
path: "COM3",
baudRate: 115200,
backspaceBehavior: "ctrl-h",
},
},
hosts: [],
groupConfigs: [],
proxyProfiles,
localOs: "windows",
});
assert.equal(resolved.protocol, "serial");
assert.equal(resolved.backspaceBehavior, "ctrl-h");
});
test("resolveTerminalSessionHost applies serial Ctrl-H backspace behavior from saved hosts", () => {
const host: Host = {
id: "target",
label: "Serial: COM3",
hostname: "COM3",
username: "",
port: 115200,
protocol: "serial",
tags: [],
os: "linux",
serialConfig: {
path: "COM3",
baudRate: 115200,
backspaceBehavior: "ctrl-h",
},
};
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
hostLabel: "Serial: COM3",
hostname: "COM3",
username: "",
port: undefined,
protocol: "serial",
},
hosts: [host],
groupConfigs: [],
proxyProfiles,
localOs: "windows",
});
assert.equal(resolved.protocol, "serial");
assert.equal(resolved.backspaceBehavior, "ctrl-h");
});
test("resolveTerminalSessionHost preserves inherited Ctrl-H for legacy restored serial sessions", () => {
const host: Host = {
id: "target",
label: "Serial: COM3",
hostname: "COM3",
username: "",
port: 115200,
protocol: "serial",
tags: [],
os: "linux",
group: "serial-devices",
serialConfig: {
path: "COM3",
baudRate: 115200,
},
};
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
hostLabel: "Serial: COM3",
hostname: "COM3",
username: "",
port: undefined,
protocol: "serial",
serialConfig: {
path: "COM3",
baudRate: 115200,
},
},
hosts: [host],
groupConfigs: [{ path: "serial-devices", backspaceBehavior: "ctrl-h" }],
proxyProfiles,
localOs: "windows",
});
assert.equal(resolved.backspaceBehavior, "ctrl-h");
});
test("resolveTerminalSessionHost keeps the serial Backspace behavior captured by the session", () => {
const host: Host = {
id: "target",
label: "Serial: COM3",
hostname: "COM3",
username: "",
port: 115200,
protocol: "serial",
tags: [],
os: "linux",
serialConfig: {
path: "COM3",
baudRate: 115200,
backspaceBehavior: "default",
},
};
const ctrlHSession = resolveTerminalSessionHost({
session: {
...baseSession,
hostname: "COM3",
username: "",
protocol: "serial",
serialConfig: {
path: "COM3",
baudRate: 115200,
backspaceBehavior: "ctrl-h",
},
},
hosts: [host],
groupConfigs: [],
proxyProfiles,
localOs: "windows",
});
const defaultSession = resolveTerminalSessionHost({
session: {
...baseSession,
hostname: "COM3",
username: "",
protocol: "serial",
serialConfig: {
path: "COM3",
baudRate: 115200,
backspaceBehavior: "default",
},
},
hosts: [{
...host,
serialConfig: {
...host.serialConfig!,
backspaceBehavior: "ctrl-h",
},
}],
groupConfigs: [],
proxyProfiles,
localOs: "windows",
});
assert.equal(ctrlHSession.backspaceBehavior, "ctrl-h");
assert.equal(defaultSession.backspaceBehavior, undefined);
});
test("resolveTerminalSessionHost suppresses inherited network device mode for Mosh sessions", () => {
const host: Host = {
id: "target",
label: "Target",
hostname: "target.example.test",
username: "alice",
port: 22,
protocol: "ssh",
tags: [],
os: "linux",
group: "prod/web",
};
const groupConfigs: GroupConfig[] = [
{ path: "prod", deviceType: "network" },
{ path: "prod/web", moshEnabled: true },
];
const resolved = resolveTerminalSessionHost({
session: baseSession,
hosts: [host],
groupConfigs,
proxyProfiles,
localOs: "linux",
});
assert.equal(resolved.moshEnabled, true);
assert.equal(resolved.deviceType, undefined);
});
test("resolveTerminalSessionHost suppresses explicit network device mode for ET session overrides", () => {
const host: Host = {
id: "target",
label: "Target",
hostname: "target.example.test",
username: "alice",
port: 22,
protocol: "ssh",
tags: [],
os: "linux",
deviceType: "network",
};
const resolved = resolveTerminalSessionHost({
session: {
...baseSession,
etEnabled: true,
},
hosts: [host],
groupConfigs: [],
proxyProfiles,
localOs: "linux",
});
assert.equal(resolved.etEnabled, true);
assert.equal(resolved.deviceType, undefined);
assert.equal(host.deviceType, "network");
});
test("resolveTerminalChainHosts materializes proxy profiles on jump hosts", () => {
const target: Host = {
id: "target",
label: "Target",
hostname: "target.example.test",
username: "alice",
port: 22,
protocol: "ssh",
tags: [],
os: "linux",
hostChain: { hostIds: ["jump-1"] },
};
const jumpHost: Host = {
id: "jump-1",
label: "Jump",
hostname: "jump.example.test",
username: "jump",
port: 22,
protocol: "ssh",
tags: [],
os: "linux",
proxyProfileId: "proxy-1",
};
const resolved = resolveTerminalChainHosts({
host: target,
hosts: [target, jumpHost],
groupConfigs: [],
proxyProfiles,
});
assert.equal(resolved.length, 1);
assert.equal(resolved[0]?.id, "jump-1");
assert.deepEqual(resolved[0]?.proxyConfig, proxyProfiles[0].config);
});
test("resolveTerminalChainHosts applies group default proxy profiles to jump hosts", () => {
const target: Host = {
id: "target",
label: "Target",
hostname: "target.example.test",
username: "alice",
port: 22,
protocol: "ssh",
tags: [],
os: "linux",
hostChain: { hostIds: ["jump-1"] },
};
const jumpHost: Host = {
id: "jump-1",
label: "Jump",
hostname: "jump.example.test",
username: "jump",
port: 22,
protocol: "ssh",
tags: [],
os: "linux",
group: "bastion",
};
const groupConfigs: GroupConfig[] = [
{ path: "bastion", proxyProfileId: "proxy-1" },
];
const resolved = resolveTerminalChainHosts({
host: target,
hosts: [target, jumpHost],
groupConfigs,
proxyProfiles,
});
assert.equal(resolved.length, 1);
assert.equal(resolved[0]?.id, "jump-1");
assert.equal(resolved[0]?.proxyProfileId, "proxy-1");
assert.deepEqual(resolved[0]?.proxyConfig, proxyProfiles[0].config);
});