diff options
| author | Adam Malczewski <[email protected]> | 2026-06-27 01:09:39 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-27 01:09:39 +0900 |
| commit | 61e45e60d699ed1ca46f94a8f181c92a940317c6 (patch) | |
| tree | 2892d9773c5a8e367e1e58cdb1e88d9c6ad3fe6d /packages/ssh/src/config.test.ts | |
| parent | 63c7e64532e85e0bbdd6d9ac6825d8f86be98e7a (diff) | |
| parent | 727c98c9dae516a2070eb950410314380a20c974 (diff) | |
| download | dispatch-61e45e60d699ed1ca46f94a8f181c92a940317c6.tar.gz dispatch-61e45e60d699ed1ca46f94a8f181c92a940317c6.zip | |
Merge branch 'feature/indent-change' into dev
Diffstat (limited to 'packages/ssh/src/config.test.ts')
| -rw-r--r-- | packages/ssh/src/config.test.ts | 650 |
1 files changed, 325 insertions, 325 deletions
diff --git a/packages/ssh/src/config.test.ts b/packages/ssh/src/config.test.ts index 04ccdc5..a54f8d6 100644 --- a/packages/ssh/src/config.test.ts +++ b/packages/ssh/src/config.test.ts @@ -1,19 +1,19 @@ import { describe, expect, it } from "vitest"; import { - isRejected, - knownHostToken, - parseKnownHosts, - resolveComputer, - resolveComputers, - type SshConfigResolveEnv, + isRejected, + knownHostToken, + parseKnownHosts, + resolveComputer, + resolveComputers, + type SshConfigResolveEnv, } from "./config.js"; const env = (overrides: Partial<SshConfigResolveEnv> = {}): SshConfigResolveEnv => ({ - configText: "", - knownHostsText: "", - defaultUser: "fallback-user", - homeDir: "/home/test", - ...overrides, + configText: "", + knownHostsText: "", + defaultUser: "fallback-user", + homeDir: "/home/test", + ...overrides, }); const FIXTURE = ` @@ -41,376 +41,376 @@ Host github.com `; describe("resolveComputers", () => { - it("returns one Computer per named (non-wildcard) Host alias, sorted", () => { - const computers = resolveComputers(env({ configText: FIXTURE })); - expect(computers.map((c) => c.alias)).toEqual(["barehost", "github.com", "myserver", "web"]); - }); - - it("skips wildcard-only Host patterns (* and ?)", () => { - const computers = resolveComputers(env({ configText: FIXTURE })); - // The bare `*` host is a pattern, not a computer — excluded. - expect(computers.find((c) => c.alias === "*")).toBeUndefined(); - }); - - it("skips wildcard aliases within a multi-alias Host line (*.example.com)", () => { - const computers = resolveComputers(env({ configText: FIXTURE })); - expect(computers.find((c) => c.alias === "*.example.com")).toBeUndefined(); - // but the named alias on the SAME line (web) is included. - expect(computers.find((c) => c.alias === "web")).toBeDefined(); - }); - - it("resolves HostName/Port/User/IdentityFile from the config (first-match-wins)", () => { - const computers = resolveComputers(env({ configText: FIXTURE })); - const my = computers.find((c) => c.alias === "myserver"); - expect(my).toEqual({ - alias: "myserver", - hostName: "10.0.0.5", - port: 2222, - user: "deploy", - identityFile: "/home/test/.ssh/deploy_key", - knownHost: false, - }); - }); - - it("falls back HostName → alias when no HostName is set", () => { - const computers = resolveComputers(env({ configText: FIXTURE })); - const bare = computers.find((c) => c.alias === "barehost"); - expect(bare?.hostName).toBe("barehost"); - expect(bare?.port).toBe(22); - expect(bare?.user).toBe("fallback-user"); - expect(bare?.identityFile).toBeNull(); - }); - - it("expands ~ in IdentityFile to homeDir", () => { - const computers = resolveComputers(env({ configText: FIXTURE })); - const gh = computers.find((c) => c.alias === "github.com"); - expect(gh?.identityFile).toBe("/home/test/.ssh/github_key"); - }); - - it("resolves a Host block whose first alias is a wildcard but later alias is named", () => { - const computers = resolveComputers(env({ configText: FIXTURE })); - const web = computers.find((c) => c.alias === "web"); - expect(web?.hostName).toBe("web.internal"); - expect(web?.user).toBe("webuser"); - }); - - it("de-dups aliases listed in multiple Host lines (first wins)", () => { - const dup = ` + it("returns one Computer per named (non-wildcard) Host alias, sorted", () => { + const computers = resolveComputers(env({ configText: FIXTURE })); + expect(computers.map((c) => c.alias)).toEqual(["barehost", "github.com", "myserver", "web"]); + }); + + it("skips wildcard-only Host patterns (* and ?)", () => { + const computers = resolveComputers(env({ configText: FIXTURE })); + // The bare `*` host is a pattern, not a computer — excluded. + expect(computers.find((c) => c.alias === "*")).toBeUndefined(); + }); + + it("skips wildcard aliases within a multi-alias Host line (*.example.com)", () => { + const computers = resolveComputers(env({ configText: FIXTURE })); + expect(computers.find((c) => c.alias === "*.example.com")).toBeUndefined(); + // but the named alias on the SAME line (web) is included. + expect(computers.find((c) => c.alias === "web")).toBeDefined(); + }); + + it("resolves HostName/Port/User/IdentityFile from the config (first-match-wins)", () => { + const computers = resolveComputers(env({ configText: FIXTURE })); + const my = computers.find((c) => c.alias === "myserver"); + expect(my).toEqual({ + alias: "myserver", + hostName: "10.0.0.5", + port: 2222, + user: "deploy", + identityFile: "/home/test/.ssh/deploy_key", + knownHost: false, + }); + }); + + it("falls back HostName → alias when no HostName is set", () => { + const computers = resolveComputers(env({ configText: FIXTURE })); + const bare = computers.find((c) => c.alias === "barehost"); + expect(bare?.hostName).toBe("barehost"); + expect(bare?.port).toBe(22); + expect(bare?.user).toBe("fallback-user"); + expect(bare?.identityFile).toBeNull(); + }); + + it("expands ~ in IdentityFile to homeDir", () => { + const computers = resolveComputers(env({ configText: FIXTURE })); + const gh = computers.find((c) => c.alias === "github.com"); + expect(gh?.identityFile).toBe("/home/test/.ssh/github_key"); + }); + + it("resolves a Host block whose first alias is a wildcard but later alias is named", () => { + const computers = resolveComputers(env({ configText: FIXTURE })); + const web = computers.find((c) => c.alias === "web"); + expect(web?.hostName).toBe("web.internal"); + expect(web?.user).toBe("webuser"); + }); + + it("de-dups aliases listed in multiple Host lines (first wins)", () => { + const dup = ` Host dup HostName first.example Host dup HostName second.example `; - const computers = resolveComputers(env({ configText: dup })); - expect(computers).toHaveLength(1); - expect(computers[0]?.hostName).toBe("first.example"); - }); - - it("knownHost=true when the resolved HostName:port token is in known_hosts", () => { - // myserver is port 2222 → token is [10.0.0.5]:2222; web is port 22 → bare host. - const known = "[10.0.0.5]:2222 ssh-ed25519 AAA\nweb.internal ssh-ed25519 BBB\n"; - const computers = resolveComputers(env({ configText: FIXTURE, knownHostsText: known })); - expect(computers.find((c) => c.alias === "myserver")?.knownHost).toBe(true); - // default port 22 → token is just the hostName (no bracket). - expect(computers.find((c) => c.alias === "web")?.knownHost).toBe(true); - expect(computers.find((c) => c.alias === "barehost")?.knownHost).toBe(false); - }); - - it("knownHost keys a non-default port as [host]:port", () => { - const known = "[10.0.0.5]:2222 ssh-ed25519 AAA\n"; - const computers = resolveComputers(env({ configText: FIXTURE, knownHostsText: known })); - expect(computers.find((c) => c.alias === "myserver")?.knownHost).toBe(true); - }); + const computers = resolveComputers(env({ configText: dup })); + expect(computers).toHaveLength(1); + expect(computers[0]?.hostName).toBe("first.example"); + }); + + it("knownHost=true when the resolved HostName:port token is in known_hosts", () => { + // myserver is port 2222 → token is [10.0.0.5]:2222; web is port 22 → bare host. + const known = "[10.0.0.5]:2222 ssh-ed25519 AAA\nweb.internal ssh-ed25519 BBB\n"; + const computers = resolveComputers(env({ configText: FIXTURE, knownHostsText: known })); + expect(computers.find((c) => c.alias === "myserver")?.knownHost).toBe(true); + // default port 22 → token is just the hostName (no bracket). + expect(computers.find((c) => c.alias === "web")?.knownHost).toBe(true); + expect(computers.find((c) => c.alias === "barehost")?.knownHost).toBe(false); + }); + + it("knownHost keys a non-default port as [host]:port", () => { + const known = "[10.0.0.5]:2222 ssh-ed25519 AAA\n"; + const computers = resolveComputers(env({ configText: FIXTURE, knownHostsText: known })); + expect(computers.find((c) => c.alias === "myserver")?.knownHost).toBe(true); + }); }); describe("resolveComputer (single alias)", () => { - it("resolves a named alias", () => { - const c = resolveComputer("myserver", env({ configText: FIXTURE })); - expect(c?.hostName).toBe("10.0.0.5"); - expect(c?.port).toBe(2222); - }); - - it("returns null for an unknown alias", () => { - expect(resolveComputer("nope", env({ configText: FIXTURE }))).toBeNull(); - }); - - it("returns null for a wildcard alias (not a selectable computer)", () => { - expect(resolveComputer("*.example.com", env({ configText: FIXTURE }))).toBeNull(); - }); - - it("applies top-level wildcard defaults to a named host (first-match-wins)", () => { - const cfg = ` + it("resolves a named alias", () => { + const c = resolveComputer("myserver", env({ configText: FIXTURE })); + expect(c?.hostName).toBe("10.0.0.5"); + expect(c?.port).toBe(2222); + }); + + it("returns null for an unknown alias", () => { + expect(resolveComputer("nope", env({ configText: FIXTURE }))).toBeNull(); + }); + + it("returns null for a wildcard alias (not a selectable computer)", () => { + expect(resolveComputer("*.example.com", env({ configText: FIXTURE }))).toBeNull(); + }); + + it("applies top-level wildcard defaults to a named host (first-match-wins)", () => { + const cfg = ` Host * ServerAliveInterval 60 User stardefault Host named HostName named.example `; - const c = resolveComputer("named", env({ configText: cfg })); - // User inherited from the `Host *` block via first-match-wins. - expect(c?.user).toBe("stardefault"); - expect(c?.hostName).toBe("named.example"); - }); + const c = resolveComputer("named", env({ configText: cfg })); + // User inherited from the `Host *` block via first-match-wins. + expect(c?.user).toBe("stardefault"); + expect(c?.hostName).toBe("named.example"); + }); }); describe("knownHostToken", () => { - it("returns the bare host for the default port (22)", () => { - expect(knownHostToken("host.example", 22)).toBe("host.example"); - }); + it("returns the bare host for the default port (22)", () => { + expect(knownHostToken("host.example", 22)).toBe("host.example"); + }); - it("returns [host]:port for a non-default port", () => { - expect(knownHostToken("host.example", 2222)).toBe("[host.example]:2222"); - }); + it("returns [host]:port for a non-default port", () => { + expect(knownHostToken("host.example", 2222)).toBe("[host.example]:2222"); + }); }); // ─── known_hosts discovery ───────────────────────────────────────────────── const KNOWN_HOSTS_FIXTURE = [ - "# comment line", - "arch-razer ssh-ed25519 AAAA1", - "xenifse1 ssh-ed25519 AAAA2", - "xenifse1 ssh-rsa AAAA3", - "xenifse1 ecdsa-sha2-nistp256 AAAA4", - "[xenifse1]:2222 ssh-ed25519 AAAA5", - "github.com ssh-ed25519 AAAA6", - "|1|+W4/jC7U8rJwiEC2m0KvG2A7uAA=|rWwV8p5J1FfR3k= ssh-ed25519 AAAA7", - "localhost ssh-ed25519 AAAA8", - "[localhost]:2222 ssh-ed25519 AAAA9", + "# comment line", + "arch-razer ssh-ed25519 AAAA1", + "xenifse1 ssh-ed25519 AAAA2", + "xenifse1 ssh-rsa AAAA3", + "xenifse1 ecdsa-sha2-nistp256 AAAA4", + "[xenifse1]:2222 ssh-ed25519 AAAA5", + "github.com ssh-ed25519 AAAA6", + "|1|+W4/jC7U8rJwiEC2m0KvG2A7uAA=|rWwV8p5J1FfR3k= ssh-ed25519 AAAA7", + "localhost ssh-ed25519 AAAA8", + "[localhost]:2222 ssh-ed25519 AAAA9", ].join("\n"); describe("parseKnownHosts", () => { - it("extracts hostnames with default port 22 from bare entries", () => { - const entries = parseKnownHosts(KNOWN_HOSTS_FIXTURE); - const arch = entries.find((e) => e.hostname === "arch-razer"); - expect(arch).toEqual({ hostname: "arch-razer", port: 22 }); - }); - - it("extracts hostname + port from [host]:port notation", () => { - const entries = parseKnownHosts(KNOWN_HOSTS_FIXTURE); - // xenifse1 has entries on port 22 (first) and port 2222 — first wins. - const xen = entries.find((e) => e.hostname === "xenifse1"); - expect(xen?.port).toBe(22); - // localhost appears as port 22 (first) and [localhost]:2222 — first wins. - const local = entries.find((e) => e.hostname === "localhost"); - expect(local?.port).toBe(22); - }); - - it("deduplicates by hostname (first port wins)", () => { - const entries = parseKnownHosts(KNOWN_HOSTS_FIXTURE); - const xenCount = entries.filter((e) => e.hostname === "xenifse1").length; - expect(xenCount).toBe(1); - // Multiple key types (ed25519, rsa, ecdsa) for the same host:port = 1 entry. - expect(entries).toHaveLength(4); // arch-razer, xenifse1, github.com, localhost - }); - - it("skips hashed entries (|1|...)", () => { - const entries = parseKnownHosts(KNOWN_HOSTS_FIXTURE); - expect(entries.find((e) => e.hostname.startsWith("|"))).toBeUndefined(); - }); - - it("skips comment lines and empty lines", () => { - const entries = parseKnownHosts("\n# comment\n\n \nhost1 ssh-ed25519 AAA\n"); - expect(entries).toHaveLength(1); - expect(entries[0]?.hostname).toBe("host1"); - }); - - it("returns empty for empty text", () => { - expect(parseKnownHosts("")).toEqual([]); - expect(parseKnownHosts(" \n\n ")).toEqual([]); - }); - - it("handles comma-separated host markers", () => { - const entries = parseKnownHosts("hostA,hostB ssh-ed25519 AAA\n"); - expect(entries.map((e) => e.hostname)).toEqual(["hostA", "hostB"]); - }); - - it("preserves non-default port when the host only has [host]:port entries", () => { - const entries = parseKnownHosts("[specialhost]:9999 ssh-ed25519 AAA\n"); - expect(entries[0]).toEqual({ hostname: "specialhost", port: 9999 }); - }); + it("extracts hostnames with default port 22 from bare entries", () => { + const entries = parseKnownHosts(KNOWN_HOSTS_FIXTURE); + const arch = entries.find((e) => e.hostname === "arch-razer"); + expect(arch).toEqual({ hostname: "arch-razer", port: 22 }); + }); + + it("extracts hostname + port from [host]:port notation", () => { + const entries = parseKnownHosts(KNOWN_HOSTS_FIXTURE); + // xenifse1 has entries on port 22 (first) and port 2222 — first wins. + const xen = entries.find((e) => e.hostname === "xenifse1"); + expect(xen?.port).toBe(22); + // localhost appears as port 22 (first) and [localhost]:2222 — first wins. + const local = entries.find((e) => e.hostname === "localhost"); + expect(local?.port).toBe(22); + }); + + it("deduplicates by hostname (first port wins)", () => { + const entries = parseKnownHosts(KNOWN_HOSTS_FIXTURE); + const xenCount = entries.filter((e) => e.hostname === "xenifse1").length; + expect(xenCount).toBe(1); + // Multiple key types (ed25519, rsa, ecdsa) for the same host:port = 1 entry. + expect(entries).toHaveLength(4); // arch-razer, xenifse1, github.com, localhost + }); + + it("skips hashed entries (|1|...)", () => { + const entries = parseKnownHosts(KNOWN_HOSTS_FIXTURE); + expect(entries.find((e) => e.hostname.startsWith("|"))).toBeUndefined(); + }); + + it("skips comment lines and empty lines", () => { + const entries = parseKnownHosts("\n# comment\n\n \nhost1 ssh-ed25519 AAA\n"); + expect(entries).toHaveLength(1); + expect(entries[0]?.hostname).toBe("host1"); + }); + + it("returns empty for empty text", () => { + expect(parseKnownHosts("")).toEqual([]); + expect(parseKnownHosts(" \n\n ")).toEqual([]); + }); + + it("handles comma-separated host markers", () => { + const entries = parseKnownHosts("hostA,hostB ssh-ed25519 AAA\n"); + expect(entries.map((e) => e.hostname)).toEqual(["hostA", "hostB"]); + }); + + it("preserves non-default port when the host only has [host]:port entries", () => { + const entries = parseKnownHosts("[specialhost]:9999 ssh-ed25519 AAA\n"); + expect(entries[0]).toEqual({ hostname: "specialhost", port: 9999 }); + }); }); // ─── known_hosts discovery merged into resolveComputers ─────────────────── describe("resolveComputers with known_hosts discovery", () => { - it("discovers computers from known_hosts when no ~/.ssh/config exists", () => { - const computers = resolveComputers(env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); - const aliases = computers.map((c) => c.alias); - expect(aliases).toContain("arch-razer"); - expect(aliases).toContain("xenifse1"); - expect(aliases).toContain("github.com"); - expect(aliases).toContain("localhost"); - }); - - it("defaulted params for known_hosts-discovered computers", () => { - const computers = resolveComputers(env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); - const arch = computers.find((c) => c.alias === "arch-razer"); - expect(arch).toEqual({ - alias: "arch-razer", - hostName: "arch-razer", - port: 22, - user: "fallback-user", - identityFile: null, - knownHost: true, - }); - }); - - it("config entries take precedence over known_hosts (no duplication)", () => { - const cfg = ` + it("discovers computers from known_hosts when no ~/.ssh/config exists", () => { + const computers = resolveComputers(env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); + const aliases = computers.map((c) => c.alias); + expect(aliases).toContain("arch-razer"); + expect(aliases).toContain("xenifse1"); + expect(aliases).toContain("github.com"); + expect(aliases).toContain("localhost"); + }); + + it("defaulted params for known_hosts-discovered computers", () => { + const computers = resolveComputers(env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); + const arch = computers.find((c) => c.alias === "arch-razer"); + expect(arch).toEqual({ + alias: "arch-razer", + hostName: "arch-razer", + port: 22, + user: "fallback-user", + identityFile: null, + knownHost: true, + }); + }); + + it("config entries take precedence over known_hosts (no duplication)", () => { + const cfg = ` Host arch-razer HostName 192.168.1.100 User root Port 2222 `; - const computers = resolveComputers( - env({ configText: cfg, knownHostsText: KNOWN_HOSTS_FIXTURE }), - ); - const arch = computers.filter((c) => c.alias === "arch-razer"); - expect(arch).toHaveLength(1); - // Config params win, not the known_hosts defaults. - expect(arch[0]?.hostName).toBe("192.168.1.100"); - expect(arch[0]?.user).toBe("root"); - expect(arch[0]?.port).toBe(2222); - }); - - it("merges config + known_hosts entries (union, sorted)", () => { - const cfg = ` + const computers = resolveComputers( + env({ configText: cfg, knownHostsText: KNOWN_HOSTS_FIXTURE }), + ); + const arch = computers.filter((c) => c.alias === "arch-razer"); + expect(arch).toHaveLength(1); + // Config params win, not the known_hosts defaults. + expect(arch[0]?.hostName).toBe("192.168.1.100"); + expect(arch[0]?.user).toBe("root"); + expect(arch[0]?.port).toBe(2222); + }); + + it("merges config + known_hosts entries (union, sorted)", () => { + const cfg = ` Host server-a HostName 10.0.0.1 `; - const computers = resolveComputers( - env({ configText: cfg, knownHostsText: KNOWN_HOSTS_FIXTURE }), - ); - const aliases = computers.map((c) => c.alias); - // config entry + known_hosts entries, all unique, sorted. - expect(aliases).toEqual(["arch-razer", "github.com", "localhost", "server-a", "xenifse1"]); - }); + const computers = resolveComputers( + env({ configText: cfg, knownHostsText: KNOWN_HOSTS_FIXTURE }), + ); + const aliases = computers.map((c) => c.alias); + // config entry + known_hosts entries, all unique, sorted. + expect(aliases).toEqual(["arch-razer", "github.com", "localhost", "server-a", "xenifse1"]); + }); }); // ─── reject-list filtering ──────────────────────────────────────────────── describe("resolveComputers with rejectPatterns", () => { - it("filters out exact-match rejected hostnames", () => { - const computers = resolveComputers( - env({ - knownHostsText: KNOWN_HOSTS_FIXTURE, - rejectPatterns: ["github.com"], - }), - ); - expect(computers.find((c) => c.alias === "github.com")).toBeUndefined(); - expect(computers.find((c) => c.alias === "arch-razer")).toBeDefined(); - }); - - it("filters out glob patterns (* matches any sequence)", () => { - const computers = resolveComputers( - env({ - knownHostsText: KNOWN_HOSTS_FIXTURE, - rejectPatterns: ["*.com"], - }), - ); - expect(computers.find((c) => c.alias === "github.com")).toBeUndefined(); - expect(computers.find((c) => c.alias === "arch-razer")).toBeDefined(); - }); - - it("filters multiple patterns", () => { - const computers = resolveComputers( - env({ - knownHostsText: KNOWN_HOSTS_FIXTURE, - rejectPatterns: ["github.com", "localhost"], - }), - ); - const aliases = computers.map((c) => c.alias); - expect(aliases).toEqual(["arch-razer", "xenifse1"]); - }); - - it("does NOT filter resolveComputer (single alias lookup ignores reject list)", () => { - // resolveComputer is for specific lookups (status, test, connect) — - // the reject list is a discovery/catalog filter, not access control. - const c = resolveComputer( - "github.com", - env({ knownHostsText: KNOWN_HOSTS_FIXTURE, rejectPatterns: ["github.com"] }), - ); - expect(c).not.toBeNull(); - expect(c?.alias).toBe("github.com"); - }); - - it("empty rejectPatterns does not filter anything", () => { - const computers = resolveComputers( - env({ knownHostsText: KNOWN_HOSTS_FIXTURE, rejectPatterns: [] }), - ); - expect(computers).toHaveLength(4); - }); - - it("absent rejectPatterns does not filter anything", () => { - const computers = resolveComputers(env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); - expect(computers).toHaveLength(4); - }); + it("filters out exact-match rejected hostnames", () => { + const computers = resolveComputers( + env({ + knownHostsText: KNOWN_HOSTS_FIXTURE, + rejectPatterns: ["github.com"], + }), + ); + expect(computers.find((c) => c.alias === "github.com")).toBeUndefined(); + expect(computers.find((c) => c.alias === "arch-razer")).toBeDefined(); + }); + + it("filters out glob patterns (* matches any sequence)", () => { + const computers = resolveComputers( + env({ + knownHostsText: KNOWN_HOSTS_FIXTURE, + rejectPatterns: ["*.com"], + }), + ); + expect(computers.find((c) => c.alias === "github.com")).toBeUndefined(); + expect(computers.find((c) => c.alias === "arch-razer")).toBeDefined(); + }); + + it("filters multiple patterns", () => { + const computers = resolveComputers( + env({ + knownHostsText: KNOWN_HOSTS_FIXTURE, + rejectPatterns: ["github.com", "localhost"], + }), + ); + const aliases = computers.map((c) => c.alias); + expect(aliases).toEqual(["arch-razer", "xenifse1"]); + }); + + it("does NOT filter resolveComputer (single alias lookup ignores reject list)", () => { + // resolveComputer is for specific lookups (status, test, connect) — + // the reject list is a discovery/catalog filter, not access control. + const c = resolveComputer( + "github.com", + env({ knownHostsText: KNOWN_HOSTS_FIXTURE, rejectPatterns: ["github.com"] }), + ); + expect(c).not.toBeNull(); + expect(c?.alias).toBe("github.com"); + }); + + it("empty rejectPatterns does not filter anything", () => { + const computers = resolveComputers( + env({ knownHostsText: KNOWN_HOSTS_FIXTURE, rejectPatterns: [] }), + ); + expect(computers).toHaveLength(4); + }); + + it("absent rejectPatterns does not filter anything", () => { + const computers = resolveComputers(env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); + expect(computers).toHaveLength(4); + }); }); // ─── resolveComputer known_hosts fallback ───────────────────────────────── describe("resolveComputer with known_hosts fallback", () => { - it("resolves a host from known_hosts when not in config", () => { - const c = resolveComputer("arch-razer", env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); - expect(c).toEqual({ - alias: "arch-razer", - hostName: "arch-razer", - port: 22, - user: "fallback-user", - identityFile: null, - knownHost: true, - }); - }); - - it("returns null for a host in neither config nor known_hosts", () => { - const c = resolveComputer("nonexistent", env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); - expect(c).toBeNull(); - }); - - it("config takes precedence over known_hosts for resolveComputer", () => { - const cfg = ` + it("resolves a host from known_hosts when not in config", () => { + const c = resolveComputer("arch-razer", env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); + expect(c).toEqual({ + alias: "arch-razer", + hostName: "arch-razer", + port: 22, + user: "fallback-user", + identityFile: null, + knownHost: true, + }); + }); + + it("returns null for a host in neither config nor known_hosts", () => { + const c = resolveComputer("nonexistent", env({ knownHostsText: KNOWN_HOSTS_FIXTURE })); + expect(c).toBeNull(); + }); + + it("config takes precedence over known_hosts for resolveComputer", () => { + const cfg = ` Host arch-razer HostName 192.168.1.100 User root `; - const c = resolveComputer( - "arch-razer", - env({ configText: cfg, knownHostsText: KNOWN_HOSTS_FIXTURE }), - ); - expect(c?.hostName).toBe("192.168.1.100"); - expect(c?.user).toBe("root"); - }); + const c = resolveComputer( + "arch-razer", + env({ configText: cfg, knownHostsText: KNOWN_HOSTS_FIXTURE }), + ); + expect(c?.hostName).toBe("192.168.1.100"); + expect(c?.user).toBe("root"); + }); }); // ─── isRejected glob matching ────────────────────────────────────────────── describe("isRejected", () => { - it("matches exact hostname", () => { - expect(isRejected("github.com", ["github.com"])).toBe(true); - expect(isRejected("arch-razer", ["github.com"])).toBe(false); - }); - - it("matches * glob (any sequence)", () => { - expect(isRejected("foo.ts.net", ["*.ts.net"])).toBe(true); - // * matches zero chars, but the remaining ".ts.net" (with literal dot) - // still doesn't match "ts.net" — the dot is required. - expect(isRejected("ts.net", ["*.ts.net"])).toBe(false); - expect(isRejected("foo.other.net", ["*.ts.net"])).toBe(false); - }); - - it("matches ? glob (single char)", () => { - expect(isRejected("host1", ["host?"])).toBe(true); - expect(isRejected("host12", ["host?"])).toBe(false); // ? = exactly one char - }); - - it("is case-insensitive", () => { - expect(isRejected("GitHub.Com", ["github.com"])).toBe(true); - expect(isRejected("FOO.TS.NET", ["*.ts.net"])).toBe(true); - }); - - it("returns false for absent or empty patterns", () => { - expect(isRejected("anything")).toBe(false); - expect(isRejected("anything", [])).toBe(false); - expect(isRejected("anything", undefined)).toBe(false); - }); + it("matches exact hostname", () => { + expect(isRejected("github.com", ["github.com"])).toBe(true); + expect(isRejected("arch-razer", ["github.com"])).toBe(false); + }); + + it("matches * glob (any sequence)", () => { + expect(isRejected("foo.ts.net", ["*.ts.net"])).toBe(true); + // * matches zero chars, but the remaining ".ts.net" (with literal dot) + // still doesn't match "ts.net" — the dot is required. + expect(isRejected("ts.net", ["*.ts.net"])).toBe(false); + expect(isRejected("foo.other.net", ["*.ts.net"])).toBe(false); + }); + + it("matches ? glob (single char)", () => { + expect(isRejected("host1", ["host?"])).toBe(true); + expect(isRejected("host12", ["host?"])).toBe(false); // ? = exactly one char + }); + + it("is case-insensitive", () => { + expect(isRejected("GitHub.Com", ["github.com"])).toBe(true); + expect(isRejected("FOO.TS.NET", ["*.ts.net"])).toBe(true); + }); + + it("returns false for absent or empty patterns", () => { + expect(isRejected("anything")).toBe(false); + expect(isRejected("anything", [])).toBe(false); + expect(isRejected("anything", undefined)).toBe(false); + }); }); |
