import { describe, expect, spyOn, test } from "bun:test"; import { cleanupExpiredSessions, createApp } from "../../server/app"; import { hashToken, MemoryAuthStore } from "../../server/auth"; import { MemoryAuditStore } from "../../server/audit-store"; import type { ManagementService } from "../../server/management"; import { MemoryOperationStore, MemoryWorkspaceLeaseProvider, } from "../../server/operation-store"; import { MemoryWorkspaceStore } from "../../server/workspace-store"; function request( path: string, init: RequestInit = {}, token?: string, ): Request { const headers = new Headers(init.headers); if (token) headers.set("authorization", `Bearer ${token}`); return new Request(`https://kuber.astrxl.dev${path}`, { ...init, headers }); } describe("kuber API authentication", () => { test("logs in, resolves identity, and revokes the session", async () => { const store = new MemoryAuthStore(); await store.putUser({ username: "dmgnr", passwordHash: "stored-hash", roles: ["admin"], }); const app = createApp({ store, now: () => Date.parse("2026-09-02T00:00:00.000Z"), verifyPassword: async (password, hash) => password === "correct" && hash === "stored-hash", }); const login = await app( request("/api/v2/login", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ username: "dmgnr", password: "correct", persistent: false, }), }), ); expect(login.status).toBe(200); const session = (await login.json()) as { token: string; expiresAt: string; }; expect(session.expiresAt).toBe("2026-09-03T00:00:00.000Z"); const me = await app(request("/api/v2/me", {}, session.token)); expect(await me.json()).toEqual({ username: "dmgnr", roles: ["admin"] }); const logout = await app( request("/api/v2/logout", { method: "POST" }, session.token), ); expect(logout.status).toBe(204); expect((await app(request("/api/v2/me", {}, session.token))).status).toBe( 401, ); }); test("rejects invalid credentials and unauthenticated requests", async () => { const store = new MemoryAuthStore(); await store.putUser({ username: "dmgnr", passwordHash: "stored-hash", roles: ["admin"], }); const app = createApp({ store, verifyPassword: async () => false, }); const login = await app( request("/api/v2/login", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ username: "dmgnr", password: "wrong" }), }), ); expect(login.status).toBe(401); expect((await app(request("/api/v2/me"))).status).toBe(401); }); test("provides an unauthenticated health endpoint", async () => { const app = createApp({ store: new MemoryAuthStore() }); const response = await app(request("/api/v2/health")); expect(response.status).toBe(200); expect(await response.json()).toEqual({ status: "ok" }); }); test("provides an explicit expired-session startup cleanup helper", async () => { const store = new MemoryAuthStore(); await store.putUser({ username: "user", passwordHash: "hash", roles: ["viewer"], }); await store.putSession({ tokenHash: hashToken("expired"), username: "user", authVersion: 1, expiresAt: "2026-09-01T00:00:00.000Z", }); expect( await cleanupExpiredSessions( store, Date.parse("2026-09-02T00:00:00.000Z"), ), ).toBe(1); }); test("rate limits repeated failed logins", async () => { const app = createApp({ store: new MemoryAuthStore(), now: () => 0, }); const login = () => app( request("/api/v2/login", { method: "POST", body: JSON.stringify({ username: "missing", password: "wrong" }), }), ); for (let attempt = 0; attempt < 5; attempt += 1) { expect((await login()).status).toBe(401); } const limited = await login(); expect(limited.status).toBe(429); expect(limited.headers.get("retry-after")).toBe("300"); }); }); async function authenticatedStore(role: "viewer" | "operator" | "admin") { const store = new MemoryAuthStore(); await store.putUser({ username: role, passwordHash: "hash", roles: [role] }); await store.putSession({ tokenHash: hashToken("token"), username: role, authVersion: 1, expiresAt: "2030-01-01T00:00:00.000Z", }); return store; } describe("kuber v2 HTTP routes", () => { test("uses exact origins, request IDs, and problem+json errors", async () => { const app = createApp({ store: new MemoryAuthStore(), allowedOrigins: ["https://console.example"], requestId: () => "generated-id", }); const denied = await app( request("/api/v2/health", { headers: { origin: "https://console.example.evil" }, }), ); expect(denied.status).toBe(403); expect(denied.headers.get("content-type")).toContain( "application/problem+json", ); expect(denied.headers.get("x-request-id")).toBe("generated-id"); expect(await denied.json()).toMatchObject({ code: "ORIGIN_NOT_ALLOWED", requestId: "generated-id", }); const allowed = await app( request("/api/v2/health", { headers: { origin: "https://console.example", "x-request-id": "caller-id", }, }), ); expect(allowed.headers.get("access-control-allow-origin")).toBe( "https://console.example", ); expect(allowed.headers.get("x-request-id")).toBe("caller-id"); }); test("enforces capabilities and supports user CRUD with revocation", async () => { const viewerStore = await authenticatedStore("viewer"); const viewerApp = createApp({ store: viewerStore }); expect( (await viewerApp(request("/api/v2/users", {}, "token"))).status, ).toBe(403); const store = await authenticatedStore("admin"); const auditStore = new MemoryAuditStore(); const app = createApp({ store, auditStore, hashPassword: async (password) => `hashed:${password}`, }); const created = await app( request( "/api/v2/users", { method: "POST", body: JSON.stringify({ username: "alice", password: "secret", roles: ["operator"], }), }, "token", ), ); expect(created.status).toBe(201); expect(await created.json()).toEqual({ username: "alice", roles: ["operator"], disabled: false, }); expect((await store.getUser("alice"))?.passwordHash).toBe("hashed:secret"); const revoke = await app( request( "/api/v2/users/alice/sessions/revoke", { method: "POST" }, "token", ), ); expect(revoke.status).toBe(200); expect(await revoke.json()).toEqual({ username: "alice", revoked: 0 }); expect((await auditStore.list()).map((event) => event.spec.action)).toEqual( ["user.create", "sessions.revoke"], ); }); test("provides workspace ETags and idempotent synchronous operations", async () => { const store = await authenticatedStore("operator"); const workspaceStore = new MemoryWorkspaceStore({ uid: () => "workspace-uid", now: () => new Date("2026-09-02T00:00:00.000Z"), }); const operationStore = new MemoryOperationStore( () => new Date("2026-09-02T00:00:00.000Z"), () => "operation-uid", ); let stops = 0; const management = { stop: async () => { stops += 1; return ["api"]; }, } as unknown as ManagementService; const app = createApp({ store, workspaceStore, operationStore, management, }); const created = await app( request( "/api/v2/workspaces", { method: "POST", body: JSON.stringify({ id: "demo", source: { uri: "oci://example/demo", digest: "sha256:abc" }, }), }, "token", ), ); expect(created.status).toBe(201); expect(created.headers.get("etag")).toBe('"1"'); const missingPrecondition = await app( request( "/api/v2/workspaces/demo", { method: "PUT", body: JSON.stringify({ source: { uri: "oci://example/demo", digest: "sha256:def" }, }), }, "token", ), ); expect(missingPrecondition.status).toBe(428); const stop = () => app( request( "/api/v2/workspaces/demo/lifecycle", { method: "POST", headers: { "idempotency-key": "stop-once" }, body: JSON.stringify({ action: "stop", services: ["api"] }), }, "token", ), ); expect((await stop()).status).toBe(200); expect((await stop()).status).toBe(200); expect(stops).toBe(1); expect(await operationStore.list("demo")).toHaveLength(1); }); test("rejects JSON bodies over the configured limit", async () => { const app = createApp({ store: await authenticatedStore("admin"), workspaceStore: new MemoryWorkspaceStore(), jsonBodyLimit: 32, }); const result = await app( request( "/api/v2/workspaces", { method: "POST", body: JSON.stringify({ value: "x".repeat(64) }) }, "token", ), ); expect(result.status).toBe(413); expect(await result.json()).toMatchObject({ code: "BODY_TOO_LARGE" }); }); test("does not expose request internals or corrupt success when auditing fails", async () => { const reported = spyOn(console, "error").mockImplementation(() => {}); const workspaceStore = new MemoryWorkspaceStore({ uid: () => "workspace-uid", }); await workspaceStore.create({ id: "demo", source: { uri: "oci://example/demo", digest: "sha256:abc" }, }); const operationStore = new MemoryOperationStore( undefined, () => "operation-uid", ); const app = createApp({ store: await authenticatedStore("operator"), workspaceStore, operationStore, management: { stop: async () => ["api"] } as unknown as ManagementService, auditStore: { append: async () => { throw new Error("audit unavailable"); }, list: async () => [], }, }); const result = await app( request( "/api/v2/workspaces/demo/lifecycle", { method: "POST", headers: { "idempotency-key": "private-request" }, body: JSON.stringify({ action: "stop", password: "do-not-store" }), }, "token", ), ); expect(result.status).toBe(200); const body = (await result.json()) as Record; expect(body.operation.spec).toEqual({ workspaceId: "demo", action: "workspace.stop", }); expect(body.operation.status.state).toBe("succeeded"); expect(reported).toHaveBeenCalledTimes(1); reported.mockRestore(); expect( await operationStore.get("operation-operation-uid"), ).not.toHaveProperty("spec.request"); }); test("fails and identifies operations that cannot acquire the workspace lease", async () => { const workspaceStore = new MemoryWorkspaceStore({ uid: () => "workspace-uid", }); await workspaceStore.create({ id: "demo", source: { uri: "oci://example/demo", digest: "sha256:abc" }, }); const operationStore = new MemoryOperationStore(undefined, () => "blocked"); const leases = new MemoryWorkspaceLeaseProvider(); await leases.acquire("demo", "other"); const app = createApp({ store: await authenticatedStore("operator"), workspaceStore, operationStore, leases, management: { stop: async () => [] } as unknown as ManagementService, }); const result = await app( request( "/api/v2/workspaces/demo/lifecycle", { method: "POST", body: JSON.stringify({ action: "stop" }) }, "token", ), ); expect(result.status).toBe(409); expect(await result.json()).toMatchObject({ code: "WORKSPACE_BUSY", operationId: "operation-blocked", }); expect((await operationStore.get("operation-blocked"))?.status.state).toBe( "failed", ); }); test("routes workspace adoption and keeps platform adoption admin-only", async () => { const workspaceStore = new MemoryWorkspaceStore({ uid: () => "workspace-uid", }); await workspaceStore.create({ id: "demo", source: { uri: "oci://example/demo", digest: "sha256:abc" }, }); const adopted: string[] = []; const adoption = { adopt: async (workspaceId: string, workspaceUid: string) => { adopted.push(`${workspaceId}:${workspaceUid}`); return { workspaceId, workspaceUid, resourcesAdopted: 2 }; }, adoptPlatform: async (workspaceUid: string) => ({ workspaceId: "kuber-system", workspaceUid, resourcesAdopted: 1, }), }; const operatorApp = createApp({ store: await authenticatedStore("operator"), workspaceStore, adoption, }); const regular = await operatorApp( request("/api/v2/workspaces/demo/adopt", { method: "POST" }, "token"), ); expect(regular.status).toBe(200); expect(adopted).toEqual(["demo:workspace-uid"]); expect( ( await operatorApp( request( "/api/v2/platform/kuber-system/adopt", { method: "POST", body: JSON.stringify({ workspaceUid: "platform" }), }, "token", ), ) ).status, ).toBe(403); const adminApp = createApp({ store: await authenticatedStore("admin"), workspaceStore, adoption, }); const platform = await adminApp( request( "/api/v2/platform/kuber-system/adopt", { method: "POST", body: JSON.stringify({ workspaceUid: "platform" }) }, "token", ), ); expect(platform.status).toBe(200); }); });