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
|
import { describe, expect, it } from "vitest";
import { decideHostKey, type HostKeyFingerprint, isKnownHost } from "./hostkey.js";
const fp = (token: string, key = "AAA"): HostKeyFingerprint => ({
knownHostToken: token,
keyBase64: key,
keyType: "ssh-ed25519",
});
describe("decideHostKey — present + match → accept, no append", () => {
it("accepts when the pinned key matches exactly", () => {
const known = "myhost ssh-ed25519 AAA\n";
const d = decideHostKey(known, fp("myhost", "AAA"));
expect(d.accept).toBe(true);
expect(d.append).toBeUndefined();
expect(d.reason).toContain("matches");
});
it("matches ignoring leading/trailing whitespace differences", () => {
const known = "myhost ssh-ed25519 AAA\n";
const d = decideHostKey(known, fp("myhost", "AAA"));
expect(d.accept).toBe(true);
expect(d.append).toBeUndefined();
});
it("matches a comma-host token list containing the alias", () => {
const known = "hostA,myhost,hostB ssh-ed25519 AAA\n";
const d = decideHostKey(known, fp("myhost", "AAA"));
expect(d.accept).toBe(true);
});
});
describe("decideHostKey — present + mismatch → REJECT, no append", () => {
it("rejects loudly when the pinned key differs", () => {
const known = "myhost ssh-ed25519 AAA\n";
const d = decideHostKey(known, fp("myhost", "BBB"));
expect(d.accept).toBe(false);
expect(d.append).toBeUndefined(); // never pin a mismatched key
expect(d.reason).toContain("HOST KEY CHANGED");
expect(d.reason).toContain("myhost");
});
it("does not pin on mismatch (the user must clear the stale line)", () => {
const known = "myhost ssh-ed25519 AAA\n";
const d = decideHostKey(known, fp("myhost", "DIFFERENT"));
expect(d.append).toBeUndefined();
});
});
describe("decideHostKey — absent (first connect) → accept + pin", () => {
it("accepts and produces the pin line to append", () => {
const d = decideHostKey("", fp("newhost", "AAA"));
expect(d.accept).toBe(true);
expect(d.append).toBe("newhost ssh-ed25519 AAA");
expect(d.reason).toContain("first connect");
expect(d.reason).toContain("newhost");
});
it("ignores comment + empty lines when searching", () => {
const known = "# a comment\n\n \notherhost ssh-ed25519 ZZZ\n";
const d = decideHostKey(known, fp("newhost", "AAA"));
expect(d.accept).toBe(true);
expect(d.append).toBe("newhost ssh-ed25519 AAA");
});
it("pins a bracketed token for a non-default port", () => {
const d = decideHostKey("", fp("[localhost]:2222", "AAA"));
expect(d.accept).toBe(true);
expect(d.append).toBe("[localhost]:2222 ssh-ed25519 AAA");
});
});
describe("decideHostKey — first field must match the token", () => {
it("does not match a host that appears only as a substring of another token", () => {
const known = "myhost-extra ssh-ed25519 AAA\n";
const d = decideHostKey(known, fp("myhost", "AAA"));
// "myhost" is not an exact first-field (nor comma element) → absent → pin.
expect(d.accept).toBe(true);
expect(d.append).toBe("myhost ssh-ed25519 AAA");
});
});
describe("isKnownHost", () => {
it("returns true when the token is a known_hosts first field", () => {
expect(isKnownHost("a.example ssh-ed25519 AAA\n", "a.example")).toBe(true);
});
it("returns true for a comma-list token", () => {
expect(isKnownHost("a,b,c ssh-ed25519 AAA\n", "b")).toBe(true);
});
it("returns false when the token is absent", () => {
expect(isKnownHost("a.example ssh-ed25519 AAA\n", "b.example")).toBe(false);
});
it("returns false for an empty known_hosts", () => {
expect(isKnownHost("", "anything")).toBe(false);
});
it("ignores comments and blanks", () => {
const known = "# comment\n\nfoo ssh-ed25519 AAA\n";
expect(isKnownHost(known, "foo")).toBe(true);
expect(isKnownHost(known, "bar")).toBe(false);
});
});
|