mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-31 15:45:23 +00:00
feat: convert ssh tunnels into a plugin
This commit is contained in:
1 parent
c85c1fdb86
commit
1682861853
220 files changed
+36928
-11374
No files matched your search
@@ -0,0 +1,83 @@
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import express from "express";
|
||||
import {
|
||||
createMockCtx,
|
||||
createTestDb,
|
||||
type MockPluginContext,
|
||||
type TestDb,
|
||||
} from "@termix/plugin-sdk/testing";
|
||||
import { PluginCapabilityError } from "@termix/plugin-sdk/backend";
|
||||
import { activate } from "../../src/backend/index.js";
|
||||
import {
|
||||
host,
|
||||
manifest,
|
||||
pluginDir,
|
||||
startServer,
|
||||
withHosts,
|
||||
type TestServer,
|
||||
} from "./helpers";
|
||||
|
||||
let db: TestDb | null = null;
|
||||
let server: TestServer | null = null;
|
||||
let mock: MockPluginContext | null = null;
|
||||
|
||||
afterEach(async () => {
|
||||
for (const dispose of [...(mock?.disposals ?? [])].reverse()) await dispose();
|
||||
mock = null;
|
||||
db?.close();
|
||||
db = null;
|
||||
await server?.close();
|
||||
server = null;
|
||||
});
|
||||
|
||||
async function activateWithout(capability: string, actor?: string) {
|
||||
db = await createTestDb(pluginDir);
|
||||
mock = createMockCtx({
|
||||
pluginId: manifest.id,
|
||||
manifest,
|
||||
capabilities: manifest.capabilities.filter((c) => c !== capability),
|
||||
db: db.database,
|
||||
router: () => express.Router(),
|
||||
actor,
|
||||
});
|
||||
return mock;
|
||||
}
|
||||
|
||||
describe("tunnels activate", () => {
|
||||
it("provides tunnels.access and serves the client relay socket", async () => {
|
||||
server = await startServer();
|
||||
const service = server.mock.services.get("tunnels.access") as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
for (const method of ["forward", "start", "stop", "status", "list"]) {
|
||||
expect(typeof service[method]).toBe("function");
|
||||
}
|
||||
expect(server.mock.wsRoutes).toEqual([{ path: "/c2s/stream", raw: false }]);
|
||||
});
|
||||
|
||||
for (const capability of ["db:own", "network:serve"]) {
|
||||
it(`fails closed without ${capability}`, async () => {
|
||||
const ctx = await activateWithout(capability);
|
||||
await expect(activate(ctx.ctx)).rejects.toBeInstanceOf(
|
||||
PluginCapabilityError,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
for (const capability of ["ssh:connect", "credentials:use", "hosts:read"]) {
|
||||
it(`cannot open a tunnel without ${capability}`, async () => {
|
||||
const ctx = await activateWithout(capability, "user-1");
|
||||
// Host lookups stay gated when hosts:read is the one missing.
|
||||
if (capability !== "hosts:read") withHosts(ctx, { "user-1": [host()] });
|
||||
await activate(ctx.ctx);
|
||||
const service = ctx.services.get("tunnels.access") as {
|
||||
forward: (id: number, target: unknown) => Promise<unknown>;
|
||||
};
|
||||
|
||||
await expect(
|
||||
service.forward(7, { targetHost: "127.0.0.1", targetPort: 80 }),
|
||||
).rejects.toBeInstanceOf(PluginCapabilityError);
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user