import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { clearDenSession } from "../src/app/lib/den"; import { createOpenworkServerClient } from "../src/app/lib/openwork-server"; import { createClient } from "../src/app/lib/opencode"; import type { ResolvedWorkspaceEndpoint } from "../src/app/lib/workspace-endpoint"; import type { ProviderListItem, WorkspaceDisplay } from "../src/app/types"; import { createSessionOpenworkServer } from "../src/react-app/domains/connections/provider-auth/session-openwork-server"; import { createProviderAuthStore } from "../src/react-app/domains/connections/provider-auth/store"; /** * Regression tests for #3671 (org-published LLM providers never reach * signed-in desktops): the session route — the app's default surface — used to * feed the provider-auth store a fabricated openwork-server snapshot without * the `providerSync` capability or host-token auth, so * `serverHandlesProviderSync()` was permanently false there. After sign-in * the store therefore never PUT the Den session to the local server * (server-side sync never started) and instead ran the legacy renderer-side * import loop against Den. * * These tests drive the real store through the real session-route snapshot * builder (`createSessionOpenworkServer`) and assert the store takes the * server-side path for local endpoints: PUT /den-session with the host token, * POST /cloud-provider-sync/run, and zero renderer-side Den provider fetches. */ const originalWindow = globalThis.window; const originalFetch = globalThis.fetch; const originalConsoleInfo = console.info; const originalDeployment = process.env.VITE_OPENWORK_DEPLOYMENT; const LOCAL_SERVER_ORIGIN = "http://127.0.0.1:7899"; const REMOTE_SERVER_ORIGIN = "https://worker.example"; type RecordedRequest = { url: string; method: string; body: string | null; headers: Record; }; function memoryStorage(): Storage { const map = new Map(); return { get length() { return map.size; }, clear() { map.clear(); }, getItem(key: string) { return map.get(key) ?? null; }, key(index: number) { return Array.from(map.keys())[index] ?? null; }, removeItem(key: string) { map.delete(key); }, setItem(key: string, value: string) { map.set(key, value); }, }; } function installWindow(): Storage { const localStorage = memoryStorage(); const listeners = new Map>(); Object.defineProperty(globalThis, "window", { configurable: true, value: { addEventListener: (type: string, listener: EventListener) => { const registered = listeners.get(type) ?? new Set(); registered.add(listener); listeners.set(type, registered); }, removeEventListener: (type: string, listener: EventListener) => { listeners.get(type)?.delete(listener); }, dispatchEvent: (event: Event) => { for (const listener of listeners.get(event.type) ?? []) listener(event); return true; }, localStorage, location: { origin: "https://self-hosted.example" }, __OPENWORK_GATEWAY__: undefined, }, }); return localStorage; } function installCloudSession(storage: Storage) { storage.setItem("openwork.den.baseUrl", "https://den.example"); storage.setItem("openwork.den.authToken", "den-token"); storage.setItem("openwork.den.activeOrgId", "org_test"); } function getRequestUrl(input: RequestInfo | URL): string { if (input instanceof URL) return input.toString(); if (typeof input === "string") return input; return input.url; } function getRequestMethod(input: RequestInfo | URL, init?: RequestInit): string { if (init?.method) return init.method; if (input instanceof Request) return input.method; return "GET"; } function normalizeHeaders(init?: RequestInit): Record { const raw = init?.headers; if (!raw) return {}; if (raw instanceof Headers) { const entries: Record = {}; raw.forEach((value, key) => { entries[key.toLowerCase()] = value; }); return entries; } if (Array.isArray(raw)) { return Object.fromEntries(raw.map(([key, value]) => [key.toLowerCase(), value])); } return Object.fromEntries(Object.entries(raw).map(([key, value]) => [key.toLowerCase(), String(value)])); } function jsonResponse(payload: unknown, status = 200) { return new Response(JSON.stringify(payload), { status, headers: { "content-type": "application/json" }, }); } function cloudProviderPayload() { return { id: "lpr_test", source: "custom", providerId: "openai", name: "Team OpenAI", providerConfig: { env: ["OPENAI_API_KEY"] }, hasApiKey: true, apiKey: "sk-test", models: [{ id: "gpt-test", name: "GPT Test", config: {}, createdAt: null }], createdAt: null, updatedAt: "2026-08-10T00:00:00.000Z", }; } function installFetchMock( requests: RecordedRequest[], options: { runStatuses?: Array<{ status: "applied" | "noop" | "failed" | "no_session"; message?: string }>; providerResponse?: Promise; } = {}, ) { let runIndex = 0; Object.defineProperty(globalThis, "fetch", { configurable: true, value: async (input: RequestInfo | URL, init?: RequestInit) => { const url = new URL(getRequestUrl(input)); const method = getRequestMethod(input, init); requests.push({ url: url.toString(), method, body: typeof init?.body === "string" ? init.body : null, headers: normalizeHeaders(init), }); if (url.origin === "https://den.example" && url.pathname === "/api/den/v1/llm-providers") { return options.providerResponse ?? jsonResponse({ llmProviders: [cloudProviderPayload()] }); } if (url.origin === "https://den.example" && url.pathname === "/api/den/v1/llm-providers/lpr_test/connect") { return jsonResponse({ llmProvider: cloudProviderPayload() }); } if (url.pathname === "/den-session" && method === "PUT") { return new Response(null, { status: 204 }); } if (url.pathname === "/cloud-provider-sync/run" && method === "POST") { const statuses = options.runStatuses ?? [{ status: "noop" }]; const result = statuses[Math.min(runIndex, statuses.length - 1)]; runIndex += 1; return jsonResponse(result); } if (url.pathname === "/cloud-provider-sync/status" && method === "GET") { return jsonResponse({ hasSession: true, lastRun: null, providers: [] }); } if (url.pathname === "/workspace/ws_1/config" && method === "GET") { return jsonResponse({ opencode: {}, openwork: {} }); } if (url.pathname === "/workspace/ws_1/config" && method === "PATCH") { return jsonResponse({ updatedAt: 1 }); } if (url.pathname === "/workspace/ws_1/opencode-config") { return jsonResponse(null); } if (url.pathname === "/env") { return jsonResponse({ ok: true }); } if (url.pathname === "/workspace/ws_1/engine/reload") { return jsonResponse({ ok: true, reloadedAt: 1 }); } if (url.pathname === "/global/health") { return jsonResponse({ healthy: true, version: "1.17.11" }); } if (url.pathname === "/provider") { return jsonResponse({ all: [], connected: [], default: {} }); } if (url.pathname === "/config") { return jsonResponse({ disabled_providers: [] }); } return jsonResponse({}); }, }); } function makeEndpoint(options: { origin: string; isRemote: boolean }): ResolvedWorkspaceEndpoint { const client = createOpenworkServerClient({ baseUrl: options.origin, token: "client-token" }); const mountedBaseUrl = `${options.origin}/workspace/ws_1`; return { baseUrl: options.origin, token: "client-token", workspaceId: "ws_1", isRemote: options.isRemote, client, mountedBaseUrl, opencodeBaseUrl: `${mountedBaseUrl}/opencode`, }; } function createSessionRouteStore(options: { endpoint: ResolvedWorkspaceEndpoint | null; hostToken: string; connectedProviderIds?: string[]; }) { const opencodeClient = createClient("https://engine.example", "/tmp/workspace_test", { token: "engine-token", mode: "openwork", }); const workspace = { id: "workspace_test", name: "Test workspace", path: "/tmp/workspace_test", preset: "default", workspaceType: options.endpoint?.isRemote ? "remote" : "local", } satisfies WorkspaceDisplay; let providers: ProviderListItem[] = []; let providerDefaults: Record = {}; let providerConnectedIds: string[] = options.connectedProviderIds ?? []; let disabledProviders: string[] = []; return createProviderAuthStore({ client: () => opencodeClient, providers: () => providers, providerDefaults: () => providerDefaults, providerConnectedIds: () => providerConnectedIds, disabledProviders: () => disabledProviders, checkDesktopAppRestriction: () => false, selectedWorkspaceDisplay: () => workspace, providerBaseUrl: () => "https://engine.example", selectedWorkspaceRoot: () => "/tmp/workspace_test", runtimeWorkspaceId: () => "ws_1", // The exact snapshot builder the session route mounts. openworkServer: createSessionOpenworkServer({ endpoint: () => options.endpoint, hostToken: () => options.hostToken, }), setProviders: (value) => { providers = value; }, setProviderDefaults: (value) => { providerDefaults = value; }, setProviderConnectedIds: (value) => { providerConnectedIds = value; }, setDisabledProviders: (value) => { disabledProviders = value; }, markOpencodeConfigReloadRequired: () => undefined, }); } describe("session-route cloud provider sync wiring", () => { beforeEach(() => { process.env.VITE_OPENWORK_DEPLOYMENT = "web"; console.info = () => undefined; }); afterEach(() => { Object.defineProperty(globalThis, "window", { configurable: true, value: originalWindow }); Object.defineProperty(globalThis, "fetch", { configurable: true, value: originalFetch }); console.info = originalConsoleInfo; if (originalDeployment === undefined) delete process.env.VITE_OPENWORK_DEPLOYMENT; else process.env.VITE_OPENWORK_DEPLOYMENT = originalDeployment; }); test("startup hydrates assigned organization models without a workspace endpoint", async () => { const storage = installWindow(); installCloudSession(storage); const requests: RecordedRequest[] = []; installFetchMock(requests); const store = createSessionRouteStore({ endpoint: null, hostToken: "", }); const assignedModelsLoaded = new Promise((resolve, reject) => { const timeout = setTimeout(() => reject(new Error("assigned models did not load")), 1_000); const unsubscribe = store.subscribe(() => { if (store.getSnapshot().cloudOrgProviders.length === 0) return; clearTimeout(timeout); unsubscribe(); resolve(); }); }); store.start(); await assignedModelsLoaded; expect(store.getSnapshot().cloudOrgProviders).toMatchObject([ { id: "lpr_test", models: [{ id: "gpt-test", name: "GPT Test" }], }, ]); expect( requests.filter((request) => request.url === "https://den.example/api/den/v1/llm-providers"), ).toHaveLength(1); expect(requests.filter((request) => new URL(request.url).pathname === "/cloud-provider-sync/run")).toHaveLength(0); store.dispose(); }); test("clearing the Den session clears assigned organization models", async () => { const storage = installWindow(); installCloudSession(storage); const requests: RecordedRequest[] = []; installFetchMock(requests); const store = createSessionRouteStore({ endpoint: null, hostToken: "", }); const assignedModelsLoaded = new Promise((resolve, reject) => { const timeout = setTimeout(() => reject(new Error("assigned models did not load")), 1_000); const unsubscribe = store.subscribe(() => { if (store.getSnapshot().cloudOrgProviders.length === 0) return; clearTimeout(timeout); unsubscribe(); resolve(); }); }); store.start(); await assignedModelsLoaded; clearDenSession(); expect(store.getSnapshot().cloudOrgProviders).toEqual([]); expect(store.getSnapshot().importedCloudProviders).toEqual({}); store.dispose(); }); test("logout removes connected provider credentials and resets their saved default", async () => { const storage = installWindow(); installCloudSession(storage); storage.setItem("openwork.defaultModel", "anthropic/claude-fable-5"); const requests: RecordedRequest[] = []; installFetchMock(requests); const store = createSessionRouteStore({ endpoint: null, hostToken: "", connectedProviderIds: ["opencode", "anthropic"], }); store.start(); clearDenSession(); for (let attempt = 0; attempt < 20; attempt += 1) { if (requests.some((request) => request.method === "DELETE" && new URL(request.url).pathname === "/auth/anthropic" )) break; await new Promise((resolve) => setTimeout(resolve, 0)); } expect( requests.filter((request) => request.method === "DELETE" && new URL(request.url).pathname === "/auth/anthropic" ), ).toHaveLength(1); expect(storage.getItem("openwork.defaultModel")).not.toBe("anthropic/claude-fable-5"); store.dispose(); }); test("an organization provider request started before logout cannot restore stale models", async () => { const storage = installWindow(); installCloudSession(storage); const requests: RecordedRequest[] = []; let resolveProviderResponse: (response: Response) => void = () => undefined; const providerResponse = new Promise((resolve) => { resolveProviderResponse = resolve; }); installFetchMock(requests, { providerResponse }); const store = createSessionRouteStore({ endpoint: null, hostToken: "", }); store.start(); for (let attempt = 0; attempt < 20; attempt += 1) { if (requests.some((request) => request.url === "https://den.example/api/den/v1/llm-providers")) break; await new Promise((resolve) => setTimeout(resolve, 0)); } expect( requests.filter((request) => request.url === "https://den.example/api/den/v1/llm-providers"), ).toHaveLength(1); clearDenSession(); resolveProviderResponse(jsonResponse({ llmProviders: [cloudProviderPayload()] })); await providerResponse; await new Promise((resolve) => setTimeout(resolve, 0)); expect(store.getSnapshot().cloudOrgProviders).toEqual([]); expect(store.getSnapshot().importedCloudProviders).toEqual({}); store.dispose(); }); test("a local endpoint with a host token pushes the Den session and syncs server-side after sign-in", async () => { const storage = installWindow(); installCloudSession(storage); const requests: RecordedRequest[] = []; installFetchMock(requests, { runStatuses: [{ status: "no_session" }, { status: "applied" }] }); const store = createSessionRouteStore({ endpoint: makeEndpoint({ origin: LOCAL_SERVER_ORIGIN, isRemote: false }), hostToken: "host-token-live", }); expect(await store.runCloudProviderSync("sign_in")).toEqual({ outcome: "handled_server_side" }); const sessionPuts = requests.filter( (request) => request.method === "PUT" && new URL(request.url).pathname === "/den-session", ); expect(sessionPuts).toHaveLength(1); expect(new URL(sessionPuts[0]?.url ?? "").origin).toBe(LOCAL_SERVER_ORIGIN); expect(sessionPuts[0]?.headers["x-openwork-host-token"]).toBe("host-token-live"); expect(sessionPuts[0]?.body).toBe(JSON.stringify({ baseUrl: "https://den.example/api/den", token: "den-token", orgId: "org_test", })); const runPosts = requests.filter( (request) => request.method === "POST" && new URL(request.url).pathname === "/cloud-provider-sync/run", ); expect(runPosts).toHaveLength(2); expect(runPosts.every((request) => request.headers["x-openwork-host-token"] === "host-token-live")).toBe(true); // Server-side sync means the renderer never fetches Den providers itself. expect(requests.filter((request) => request.url.includes("/v1/llm-providers"))).toHaveLength(0); }); test("falls back to the persisted host token for loopback servers when live host info is absent", async () => { const storage = installWindow(); installCloudSession(storage); storage.setItem("openwork.server.hostToken", "host-token-stored"); const requests: RecordedRequest[] = []; installFetchMock(requests, { runStatuses: [{ status: "no_session" }, { status: "noop" }] }); const store = createSessionRouteStore({ endpoint: makeEndpoint({ origin: LOCAL_SERVER_ORIGIN, isRemote: false }), hostToken: "", }); expect(await store.runCloudProviderSync("sign_in")).toEqual({ outcome: "handled_server_side" }); const sessionPuts = requests.filter( (request) => request.method === "PUT" && new URL(request.url).pathname === "/den-session", ); expect(sessionPuts).toHaveLength(1); expect(sessionPuts[0]?.headers["x-openwork-host-token"]).toBe("host-token-stored"); }); test("remote workspaces never receive the desktop's Den session and keep the legacy client path", async () => { const storage = installWindow(); installCloudSession(storage); // Even a (stale) persisted local host token must not leak to a remote worker. storage.setItem("openwork.server.hostToken", "host-token-stored"); const requests: RecordedRequest[] = []; installFetchMock(requests); const store = createSessionRouteStore({ endpoint: makeEndpoint({ origin: REMOTE_SERVER_ORIGIN, isRemote: true }), hostToken: "", }); await store.runCloudProviderSync("sign_in"); expect(requests.filter((request) => new URL(request.url).pathname === "/den-session")).toHaveLength(0); expect(requests.filter((request) => new URL(request.url).pathname === "/cloud-provider-sync/run")).toHaveLength(0); // The legacy renderer-side reconciliation still runs for remote workspaces. expect(requests.some((request) => request.url === "https://den.example/api/den/v1/llm-providers")).toBe(true); }); });