feat: ssh transport providers, core ssh relay and plugin folders api

This commit is contained in:
LukeGus committed 2026-10-19 19:20:32 -05:00
1 parent 3caf6cca62
commit 901a235de4
20 files changed
+736 -77

No files matched your search

@@ -30,6 +30,8 @@ const h = vi.hoisted(() => ({
existingAccess: [] as Array<{ id: number }>,
revoked: [] as number[],
protocolWrites: [] as Array<{ hostId: number; protocols: string[] }>,
folderCalls: [] as Array<unknown[]>,
folderEmpty: true,
roles: [] as Array<{
id: number;
name: string;
@@ -96,6 +98,15 @@ vi.mock("../../database/repositories/factory.js", () => ({
createCurrentUserRepository: () => ({
listAll: async () => h.users,
}),
createCurrentHostFolderRepository: () => ({
upsertMetadata: async (...args: unknown[]) => {
h.folderCalls.push(["ensure", ...args]);
},
deleteEmptyFolderRecords: async (...args: unknown[]) => {
h.folderCalls.push(["remove", ...args]);
return h.folderEmpty;
},
}),
createCurrentHostRepository: () => ({
createEncryptedForUser: async (
userId: string,
@@ -961,3 +972,45 @@ describe("ctx.hosts.locks", () => {
expect(h.updates).toHaveLength(1);
});
});
describe("ctx.hosts.folders", () => {
beforeEach(() => {
h.granted = new Set(["hosts:write"]);
h.actor = "user-1";
h.folderCalls = [];
h.folderEmpty = true;
});
it("needs hosts:write", async () => {
h.granted = new Set();
const hosts = createPluginHosts({
manifest: manifest(["hosts:write"]),
audit: vi.fn(async () => {}),
});
await expect(hosts.folders.ensure("Site")).rejects.toThrow(
PluginCapabilityError,
);
});
it("creates the folder row for the acting user with its style", async () => {
const hosts = createPluginHosts({
manifest: manifest(["hosts:write"]),
audit: vi.fn(async () => {}),
});
await hosts.folders.ensure("Site", { icon: "cloud-cog" });
expect(h.folderCalls).toEqual([
["ensure", "user-1", "Site", null, "cloud-cog"],
]);
});
it("removes only an empty folder", async () => {
const hosts = createPluginHosts({
manifest: manifest(["hosts:write"]),
audit: vi.fn(async () => {}),
});
expect(await hosts.folders.removeEmpty("Site")).toBe(true);
h.folderEmpty = false;
expect(await hosts.folders.removeEmpty("Site")).toBe(false);
expect(h.folderCalls[0]).toEqual(["remove", "user-1", "Site"]);
});
});
+20
View File
@@ -154,6 +154,26 @@ describe("ctx.ws routing", () => {
if (result.outcome === "open") result.socket.close();
});
it("serves a socket core owns without any plugin grant", async () => {
state.granted = new Set();
const seen: string[] = [];
ws.registerCoreWsRoute("/relay", ({ userId }) => {
seen.push(userId);
});
const base = await startServer();
const signedIn = await connect(
`${base}/plugin-ws/core/relay`,
authProtocols(state.validToken),
);
const anonymous = await connect(`${base}/plugin-ws/core/relay`);
expect(signedIn.outcome).toBe("open");
expect(anonymous.outcome).toBe(401);
expect(seen).toEqual([state.userId]);
if (signedIn.outcome === "open") signedIn.socket.close();
});
it("404s a path nothing registered", async () => {
const base = await startServer();