From 834450a0c022d0c0d8843b41544a64ee88b44c0e Mon Sep 17 00:00:00 2001 From: OpeOginni Date: Fri, 31 Jul 2026 18:40:56 +0200 Subject: [PATCH 1/2] fix(opencode): report stored provider credentials --- .../instance/httpapi/handlers/provider.ts | 5 +++- .../test/server/httpapi-provider.test.ts | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts index e1377b6f75c5..6f0e5f608cde 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/provider.ts @@ -2,6 +2,7 @@ import { ProviderAuth } from "@/provider/auth" import { Config } from "@/config/config" import { ModelsDev } from "@opencode-ai/core/models-dev" import { Provider } from "@/provider/provider" +import { Auth } from "@/auth" import { mapValues } from "remeda" import { Effect, Schema } from "effect" @@ -36,6 +37,7 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider" const cfg = yield* Config.Service const provider = yield* Provider.Service const svc = yield* ProviderAuth.Service + const authStore = yield* Auth.Service const list = Effect.fn("ProviderHttpApi.list")(function* () { const config = yield* cfg.get() @@ -47,6 +49,7 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider" if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) filtered[key] = value } const connected = yield* provider.list() + const credentials = yield* authStore.all().pipe(Effect.orDie) const providers = Object.assign( mapValues(filtered, (item) => Provider.fromModelsDevProvider(item)), connected, @@ -54,7 +57,7 @@ export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider" return { all: Object.values(providers).map(Provider.toPublicInfo), default: Provider.defaultModelIDs(providers), - connected: Object.keys(connected), + connected: Object.keys(providers).filter((id) => id in connected || credentials[id]), } }) diff --git a/packages/opencode/test/server/httpapi-provider.test.ts b/packages/opencode/test/server/httpapi-provider.test.ts index 625ca1896b46..0787b9af1b18 100644 --- a/packages/opencode/test/server/httpapi-provider.test.ts +++ b/packages/opencode/test/server/httpapi-provider.test.ts @@ -52,6 +52,11 @@ function providerByID(input: unknown, key: "all" | "providers", id: string) { return providerList(input, key).find((provider) => isRecord(provider) && provider.id === id) } +function connectedProviders(input: unknown) { + if (!isRecord(input) || !Array.isArray(input.connected)) return [] + return input.connected.filter((provider): provider is string => typeof provider === "string") +} + function hasNonZeroModelCost(input: unknown, key: "all" | "providers", id: string) { const provider = providerByID(input, key, id) if (!isRecord(provider) || !isRecord(provider.models)) return false @@ -378,6 +383,29 @@ describe("provider HttpApi", () => { { ...projectOptions, init: writeFunctionOptionsPlugin }, ) + it.instance( + "reports credentials added after provider state initializes as connected", + Effect.gen(function* () { + const directory = (yield* TestInstance).directory + const headers = { "x-opencode-directory": directory } + const initial = yield* request("/provider", { headers }) + expect(initial.status).toBe(200) + expect(connectedProviders(yield* initial.json)).not.toContain("github-copilot") + + yield* setEnvScoped( + "OPENCODE_AUTH_CONTENT", + JSON.stringify({ + "github-copilot": { type: "oauth", refresh: "dummy", access: "dummy", expires: 0 }, + }), + ) + const updated = yield* request("/provider", { headers }) + + expect(updated.status).toBe(200) + expect(connectedProviders(yield* updated.json)).toContain("github-copilot") + }), + projectOptions, + ) + it.instance( "keeps provider.models hook input mutations out of provider state", Effect.gen(function* () { From c93f2d56a0be1a6b46c3d85344a2a3b6876a7507 Mon Sep 17 00:00:00 2001 From: OpeOginni Date: Fri, 31 Jul 2026 18:47:48 +0200 Subject: [PATCH 2/2] test(opencode): remove provider auth regression test --- .../test/server/httpapi-provider.test.ts | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/packages/opencode/test/server/httpapi-provider.test.ts b/packages/opencode/test/server/httpapi-provider.test.ts index 0787b9af1b18..625ca1896b46 100644 --- a/packages/opencode/test/server/httpapi-provider.test.ts +++ b/packages/opencode/test/server/httpapi-provider.test.ts @@ -52,11 +52,6 @@ function providerByID(input: unknown, key: "all" | "providers", id: string) { return providerList(input, key).find((provider) => isRecord(provider) && provider.id === id) } -function connectedProviders(input: unknown) { - if (!isRecord(input) || !Array.isArray(input.connected)) return [] - return input.connected.filter((provider): provider is string => typeof provider === "string") -} - function hasNonZeroModelCost(input: unknown, key: "all" | "providers", id: string) { const provider = providerByID(input, key, id) if (!isRecord(provider) || !isRecord(provider.models)) return false @@ -383,29 +378,6 @@ describe("provider HttpApi", () => { { ...projectOptions, init: writeFunctionOptionsPlugin }, ) - it.instance( - "reports credentials added after provider state initializes as connected", - Effect.gen(function* () { - const directory = (yield* TestInstance).directory - const headers = { "x-opencode-directory": directory } - const initial = yield* request("/provider", { headers }) - expect(initial.status).toBe(200) - expect(connectedProviders(yield* initial.json)).not.toContain("github-copilot") - - yield* setEnvScoped( - "OPENCODE_AUTH_CONTENT", - JSON.stringify({ - "github-copilot": { type: "oauth", refresh: "dummy", access: "dummy", expires: 0 }, - }), - ) - const updated = yield* request("/provider", { headers }) - - expect(updated.status).toBe(200) - expect(connectedProviders(yield* updated.json)).toContain("github-copilot") - }), - projectOptions, - ) - it.instance( "keeps provider.models hook input mutations out of provider state", Effect.gen(function* () {