Files
Termix/plugins/warpgate/tests/backend/warpgate.test.ts
T

114 lines
3.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { PluginCapabilityError } from "@termix/plugin-sdk/backend";
import { createMockCtx } from "@termix/plugin-sdk/testing";
import type { PluginManifest } from "@termix/plugin-sdk/manifest";
import manifestJson from "../../manifest.json";
import { activate } from "../../src/backend/index.js";
import { detectWarpgateRound } from "../../src/backend/detect.js";
import { hostImportNormalizer } from "../../src/backend/host-import.js";
const manifest = manifestJson as unknown as PluginManifest;
const HOST = { id: 1, ip: "10.0.0.1", port: 22, username: "root" };
async function register() {
const mock = createMockCtx({
pluginId: manifest.id,
manifest,
capabilities: manifest.capabilities,
});
await activate(mock.ctx);
return mock.auth.keyboardInteractiveHandlers[0];
}
describe("detectWarpgateRound", () => {
it("claims a Warpgate round with its URL and security key", () => {
expect(
detectWarpgateRound({
name: "Warpgate authentication",
instructions:
"Open https://gate.example/@warpgate#/login/abc to continue. Security key: a b c d",
prompts: [{ prompt: "Press Enter when done: " }],
}),
).toEqual({
kind: "browser",
url: "https://gate.example/@warpgate#/login/abc",
code: "a b c d",
instructions:
"Open https://gate.example/@warpgate#/login/abc to continue. Security key: a b c d",
});
});
it("finds the marker in a prompt too, and says N/A without a key", () => {
expect(
detectWarpgateRound({
name: "",
instructions: "",
prompts: [
{ prompt: "Warpgate authentication: visit https://gate.example/x" },
],
}),
).toMatchObject({ url: "https://gate.example/x", code: "N/A" });
});
it("leaves other rounds, and a Warpgate round without a URL, alone", () => {
expect(
detectWarpgateRound({
name: "",
instructions: "",
prompts: [{ prompt: "Verification code:" }],
}),
).toBeNull();
expect(
detectWarpgateRound({
name: "Warpgate authentication",
instructions: "",
prompts: [],
}),
).toBeNull();
});
});
describe("the warpgate handler", () => {
it("registers under its id and label", async () => {
const handler = await register();
expect(handler).toMatchObject({ id: "warpgate", label: "Warpgate" });
});
it("answers password prompts itself only on hosts with the setting on", async () => {
const handler = await register();
expect(handler.autoAnswerPasswords!(HOST, { useWarpgate: true })).toBe(
true,
);
expect(handler.autoAnswerPasswords!(HOST, { useWarpgate: false })).toBe(
false,
);
expect(handler.autoAnswerPasswords!(HOST, {})).toBe(false);
});
it("fails closed without auth:provide", async () => {
const mock = createMockCtx({
pluginId: manifest.id,
manifest,
capabilities: [],
});
await expect(activate(mock.ctx)).rejects.toThrow(PluginCapabilityError);
});
});
describe("hostImportNormalizer", () => {
it("reads the plugin's own settings first, then the 2.8 host field", () => {
expect(
hostImportNormalizer({
pluginSettings: { warpgate: { useWarpgate: true } },
}),
).toEqual({ useWarpgate: true });
expect(hostImportNormalizer({ useWarpgate: 1 })).toEqual({
useWarpgate: true,
});
expect(hostImportNormalizer({ useWarpgate: false })).toEqual({
useWarpgate: false,
});
expect(hostImportNormalizer({ name: "x" })).toBeNull();
});
});