1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
import { describe, expect, it } from "vitest";
import {
knownHostToken,
resolveComputer,
resolveComputers,
type SshConfigResolveEnv,
} from "./config.js";
const env = (overrides: Partial<SshConfigResolveEnv> = {}): SshConfigResolveEnv => ({
configText: "",
knownHostsText: "",
defaultUser: "fallback-user",
homeDir: "/home/test",
...overrides,
});
const FIXTURE = `
# top-level comment
Host *
ServerAliveInterval 60
Host myserver
HostName 10.0.0.5
Port 2222
User deploy
IdentityFile ~/.ssh/deploy_key
Host web *.example.com
HostName web.internal
User webuser
Host barehost
# no HostName → falls back to alias
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_key
`;
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 = `
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);
});
});
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 = `
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");
});
});
describe("knownHostToken", () => {
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");
});
});
|