From 3657661c6306d1ca7dceb5c3ee75630e3cd7b007 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 18 Jul 2026 14:51:31 +0200 Subject: [PATCH] fix: normalize workbench cloud authorization --- internal/workbench/cloud-application.ts | 6 ++++-- internal/workbench/workbench.test.ts | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/internal/workbench/cloud-application.ts b/internal/workbench/cloud-application.ts index fb725e64..61f9e142 100644 --- a/internal/workbench/cloud-application.ts +++ b/internal/workbench/cloud-application.ts @@ -6,13 +6,15 @@ export function createCloudWorkbenchApplication(options: { fetchImpl?: typeof fetch; }): WorkbenchApplication { if (!options.baseUrl) throw codedError("workbench_cloud_api_url_required", "WORKBENCH_CLOUD_API_URL is required"); - if (!options.authorization) throw codedError("workbench_cloud_api_auth_required", "WORKBENCH_CLOUD_API_AUTHORIZATION is required"); + const authorization = options.authorization.trim(); + if (!authorization) throw codedError("workbench_cloud_api_auth_required", "WORKBENCH_CLOUD_API_AUTHORIZATION is required"); + const authorizationHeader = /^Bearer\s+/iu.test(authorization) ? authorization : `Bearer ${authorization}`; const fetchImpl = options.fetchImpl ?? fetch; const request = async (method: string, route: string, body: Record | undefined, actor: { id: string; role?: string | null }) => { const response = await fetchImpl(`${options.baseUrl.replace(/\/$/u, "")}${route}`, { method, headers: { - authorization: options.authorization, + authorization: authorizationHeader, "content-type": "application/json", "x-workbench-activity-dispatch": "1", "x-hwlab-actor-id": actor.id, diff --git a/internal/workbench/workbench.test.ts b/internal/workbench/workbench.test.ts index 6dec557e..7d800c98 100644 --- a/internal/workbench/workbench.test.ts +++ b/internal/workbench/workbench.test.ts @@ -54,10 +54,24 @@ describe("Workbench Cloud application adapter", () => { await application.admitTurn(input); await application.dispatchTurn(input); expect(calls).toEqual([ - { path: "/v1/internal/workbench/admit", authorization: "unified-internal-key" }, - { path: "/v1/agent/chat", authorization: "unified-internal-key" } + { path: "/v1/internal/workbench/admit", authorization: "Bearer unified-internal-key" }, + { path: "/v1/agent/chat", authorization: "Bearer unified-internal-key" } ]); }); + + test("preserves an existing Bearer authorization scheme", async () => { + let authorization: string | null = null; + const application = createCloudWorkbenchApplication({ + baseUrl: "http://cloud.internal", + authorization: "Bearer unified-internal-key", + fetchImpl: (async (_url: string | URL | Request, init?: RequestInit) => { + authorization = new Headers(init?.headers).get("authorization"); + return Response.json({ ok: true, session: { sessionId: "ses_test" } }); + }) as typeof fetch + }); + await application.createSession({ actor: { id: "usr_test" }, params: {} }); + expect(authorization).toBe("Bearer unified-internal-key"); + }); }); describe("Workbench native HTTP adapter", () => {