mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
100 lines
3.7 KiB
TypeScript
100 lines
3.7 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { createHash } from "node:crypto";
|
|
import { readFile } from "node:fs/promises";
|
|
import test from "node:test";
|
|
import { validatePiSshConfig } from "../src/config.ts";
|
|
import { effectiveIdentityAgent, effectiveValue, effectiveValues, parseSshG } from "../src/import.ts";
|
|
import { fingerprintHostKey } from "../src/ssh2-transport.ts";
|
|
|
|
test("parses the effective ssh -G output including repeated identity files", () => {
|
|
const parsed = parseSshG([
|
|
"host packaging-server",
|
|
"hostname 192.0.2.20",
|
|
"user builder",
|
|
"port 2222",
|
|
"identityfile ~/.ssh/first",
|
|
"identityfile ~/.ssh/second",
|
|
"proxyjump none",
|
|
].join("\n"));
|
|
assert.equal(effectiveValue(parsed, "hostname"), "192.0.2.20");
|
|
assert.equal(effectiveValue(parsed, "port"), "2222");
|
|
assert.deepEqual(effectiveValues(parsed, "identityfile"), ["~/.ssh/first", "~/.ssh/second"]);
|
|
});
|
|
|
|
test("resolves IdentityAgent socket paths and SSH_AUTH_SOCK references", () => {
|
|
assert.equal(
|
|
effectiveIdentityAgent(parseSshG("identityagent /Users/test/.1password/agent.sock"), {}),
|
|
"/Users/test/.1password/agent.sock",
|
|
);
|
|
assert.equal(
|
|
effectiveIdentityAgent(parseSshG("identityagent $SSH_AUTH_SOCK"), { SSH_AUTH_SOCK: "/tmp/agent.sock" }),
|
|
"/tmp/agent.sock",
|
|
);
|
|
assert.equal(effectiveIdentityAgent(parseSshG("identityagent none"), { SSH_AUTH_SOCK: "/tmp/agent.sock" }), undefined);
|
|
});
|
|
|
|
test("validates password, private-key, and agent host definitions", () => {
|
|
const password = validatePiSshConfig({
|
|
version: 1,
|
|
hosts: {
|
|
build: {
|
|
hostName: "build.example.test",
|
|
user: "builder",
|
|
port: 22,
|
|
auth: { type: "password", password: "secret" },
|
|
hostKey: { algorithm: "ssh-ed25519", fingerprint: "SHA256:value" },
|
|
},
|
|
},
|
|
groups: { builders: { label: "Builders", hosts: ["build"] } },
|
|
});
|
|
assert.equal(password.hosts.build.auth.type, "password");
|
|
|
|
const agent = validatePiSshConfig({
|
|
version: 1,
|
|
hosts: {
|
|
build: {
|
|
hostName: "build.example.test",
|
|
user: "builder",
|
|
port: 22,
|
|
auth: { type: "agent", socketPath: "~/.1password/agent.sock" },
|
|
hostKey: { algorithm: "ssh-ed25519", fingerprint: "SHA256:value" },
|
|
},
|
|
},
|
|
});
|
|
assert.deepEqual(agent.hosts.build.auth, { type: "agent", socketPath: "~/.1password/agent.sock" });
|
|
|
|
assert.throws(() => validatePiSshConfig({
|
|
version: 1,
|
|
hosts: {
|
|
build: {
|
|
hostName: "build.example.test",
|
|
user: "builder",
|
|
port: 22,
|
|
auth: { type: "agent", socketPath: "" },
|
|
hostKey: { algorithm: "ssh-ed25519", fingerprint: "SHA256:value" },
|
|
},
|
|
},
|
|
}), /socketPath/);
|
|
});
|
|
|
|
test("formats SSH host keys as pinned SHA256 fingerprints", () => {
|
|
const algorithm = Buffer.from("ssh-ed25519", "ascii");
|
|
const length = Buffer.alloc(4);
|
|
length.writeUInt32BE(algorithm.length);
|
|
const key = Buffer.concat([length, algorithm, Buffer.from("public-key-fixture")]);
|
|
const expected = createHash("sha256").update(key).digest("base64").replace(/=+$/, "");
|
|
assert.deepEqual(fingerprintHostKey(key), {
|
|
algorithm: "ssh-ed25519",
|
|
fingerprint: `SHA256:${expected}`,
|
|
});
|
|
});
|
|
|
|
test("configuration import validates remote HOME and cwd with framed probes", async () => {
|
|
const source = await readFile(new URL("../scripts/ssh-config.mjs", import.meta.url), "utf8");
|
|
assert.match(source, /probeRemotePath\(transport, "home"\)/);
|
|
assert.match(source, /probeRemotePath\(transport, "cwd"\)/);
|
|
assert.doesNotMatch(source, /transport\.capture\(/);
|
|
assert.match(source, /Authentication \[agent\/key\/password\]/);
|
|
assert.match(source, /effectiveIdentityAgent\(effective\)/);
|
|
});
|