From a5d2e89d3d1e277be09848d09fa82060ccc0df8f Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 6 Apr 2026 13:01:21 +0100 Subject: [PATCH] refactor(auth): drop provider auth storage switchboard --- src/commands/onboard-auth.credentials.test.ts | 67 ++++-- src/commands/onboard-auth.test.ts | 11 +- src/plugins/provider-auth-helpers.ts | 22 ++ src/plugins/provider-auth-storage.ts | 201 ------------------ 4 files changed, 75 insertions(+), 226 deletions(-) delete mode 100644 src/plugins/provider-auth-storage.ts diff --git a/src/commands/onboard-auth.credentials.test.ts b/src/commands/onboard-auth.credentials.test.ts index 8c80f51ec2a..78d75383012 100644 --- a/src/commands/onboard-auth.credentials.test.ts +++ b/src/commands/onboard-auth.credentials.test.ts @@ -1,12 +1,5 @@ import { afterEach, describe, expect, it } from "vitest"; -import { - setByteplusApiKey, - setCloudflareAiGatewayConfig, - setMoonshotApiKey, - setOpencodeZenApiKey, - setOpenaiApiKey, - setVolcengineApiKey, -} from "../plugins/provider-auth-storage.js"; +import { upsertApiKeyProfile } from "../plugins/provider-auth-helpers.js"; import { createAuthTestLifecycle, readAuthProfilesForAgent, @@ -80,7 +73,7 @@ describe("onboard auth credentials secret refs", () => { envValue: "sk-moonshot-env", profileId: "moonshot:default", apply: async () => { - await setMoonshotApiKey("sk-moonshot-env"); + upsertApiKeyProfile({ provider: "moonshot", input: "sk-moonshot-env" }); }, expected: { key: "sk-moonshot-env", @@ -96,7 +89,12 @@ describe("onboard auth credentials secret refs", () => { envValue: "sk-moonshot-env", profileId: "moonshot:default", apply: async (agentDir) => { - await setMoonshotApiKey("sk-moonshot-env", agentDir, { secretInputMode: "ref" }); // pragma: allowlist secret + upsertApiKeyProfile({ + provider: "moonshot", + input: "sk-moonshot-env", + agentDir, + options: { secretInputMode: "ref" }, // pragma: allowlist secret + }); }, expected: { keyRef: { source: "env", provider: "default", id: "MOONSHOT_API_KEY" }, @@ -110,7 +108,7 @@ describe("onboard auth credentials secret refs", () => { prefix: "openclaw-onboard-auth-credentials-inline-ref-", profileId: "moonshot:default", apply: async () => { - await setMoonshotApiKey("${MOONSHOT_API_KEY}"); + upsertApiKeyProfile({ provider: "moonshot", input: "${MOONSHOT_API_KEY}" }); }, expected: { keyRef: { source: "env", provider: "default", id: "MOONSHOT_API_KEY" }, @@ -126,7 +124,7 @@ describe("onboard auth credentials secret refs", () => { envValue: "sk-moonshot-other", profileId: "moonshot:default", apply: async () => { - await setMoonshotApiKey("sk-moonshot-plaintext"); + upsertApiKeyProfile({ provider: "moonshot", input: "sk-moonshot-plaintext" }); }, expected: { key: "sk-moonshot-plaintext", @@ -140,8 +138,15 @@ describe("onboard auth credentials secret refs", () => { lifecycle.setStateDir(env.stateDir); process.env.CLOUDFLARE_AI_GATEWAY_API_KEY = "cf-secret"; // pragma: allowlist secret - await setCloudflareAiGatewayConfig("account-1", "gateway-1", "cf-secret", env.agentDir, { - secretInputMode: "ref", // pragma: allowlist secret + upsertApiKeyProfile({ + provider: "cloudflare-ai-gateway", + input: "cf-secret", + agentDir: env.agentDir, + options: { secretInputMode: "ref" }, // pragma: allowlist secret + metadata: { + accountId: "account-1", + gatewayId: "gateway-1", + }, }); const parsed = await readAuthProfilesForAgent<{ @@ -161,7 +166,7 @@ describe("onboard auth credentials secret refs", () => { envValue: "sk-openai-env", profileId: "openai:default", apply: async () => { - await setOpenaiApiKey("sk-openai-env"); + upsertApiKeyProfile({ provider: "openai", input: "sk-openai-env" }); }, expected: { key: "sk-openai-env", @@ -177,7 +182,12 @@ describe("onboard auth credentials secret refs", () => { envValue: "sk-openai-env", profileId: "openai:default", apply: async (agentDir) => { - await setOpenaiApiKey("sk-openai-env", agentDir, { secretInputMode: "ref" }); // pragma: allowlist secret + upsertApiKeyProfile({ + provider: "openai", + input: "sk-openai-env", + agentDir, + options: { secretInputMode: "ref" }, // pragma: allowlist secret + }); }, expected: { keyRef: { source: "env", provider: "default", id: "OPENAI_API_KEY" }, @@ -192,8 +202,18 @@ describe("onboard auth credentials secret refs", () => { process.env.VOLCANO_ENGINE_API_KEY = "volcengine-secret"; // pragma: allowlist secret process.env.BYTEPLUS_API_KEY = "byteplus-secret"; // pragma: allowlist secret - await setVolcengineApiKey("volcengine-secret", env.agentDir, { secretInputMode: "ref" }); // pragma: allowlist secret - await setByteplusApiKey("byteplus-secret", env.agentDir, { secretInputMode: "ref" }); // pragma: allowlist secret + upsertApiKeyProfile({ + provider: "volcengine", + input: "volcengine-secret", + agentDir: env.agentDir, + options: { secretInputMode: "ref" }, // pragma: allowlist secret + }); + upsertApiKeyProfile({ + provider: "byteplus", + input: "byteplus-secret", + agentDir: env.agentDir, + options: { secretInputMode: "ref" }, // pragma: allowlist secret + }); const parsed = await readAuthProfilesForAgent<{ profiles?: Record; @@ -215,9 +235,14 @@ describe("onboard auth credentials secret refs", () => { lifecycle.setStateDir(env.stateDir); process.env.OPENCODE_API_KEY = "sk-opencode-env"; // pragma: allowlist secret - await setOpencodeZenApiKey("sk-opencode-env", env.agentDir, { - secretInputMode: "ref", // pragma: allowlist secret - }); + for (const provider of ["opencode", "opencode-go"] as const) { + upsertApiKeyProfile({ + provider, + input: "sk-opencode-env", + agentDir: env.agentDir, + options: { secretInputMode: "ref" }, // pragma: allowlist secret + }); + } const parsed = await readAuthProfilesForAgent<{ profiles?: Record; diff --git a/src/commands/onboard-auth.test.ts b/src/commands/onboard-auth.test.ts index 6635b377dba..c48dd620ccb 100644 --- a/src/commands/onboard-auth.test.ts +++ b/src/commands/onboard-auth.test.ts @@ -3,8 +3,11 @@ import os from "node:os"; import path from "node:path"; import type { OAuthCredentials } from "@mariozechner/pi-ai"; import { afterEach, describe, expect, it } from "vitest"; -import { applyAuthProfileConfig } from "../plugins/provider-auth-helpers.js"; -import { setMinimaxApiKey, writeOAuthCredentials } from "../plugins/provider-auth-storage.js"; +import { + applyAuthProfileConfig, + upsertApiKeyProfile, + writeOAuthCredentials, +} from "../plugins/provider-auth-helpers.js"; import { createAuthTestLifecycle, readAuthProfilesForAgent, @@ -163,7 +166,7 @@ describe("writeOAuthCredentials", () => { }); }); -describe("setMinimaxApiKey", () => { +describe("upsertApiKeyProfile", () => { const lifecycle = createAuthTestLifecycle([ "OPENCLAW_STATE_DIR", "OPENCLAW_AGENT_DIR", @@ -178,7 +181,7 @@ describe("setMinimaxApiKey", () => { const env = await setupAuthTestEnv("openclaw-minimax-", { agentSubdir: "custom-agent" }); lifecycle.setStateDir(env.stateDir); - await setMinimaxApiKey("sk-minimax-test"); + upsertApiKeyProfile({ provider: "minimax", input: "sk-minimax-test" }); const parsed = await readAuthProfilesForAgent<{ profiles?: Record; diff --git a/src/plugins/provider-auth-helpers.ts b/src/plugins/provider-auth-helpers.ts index ff32ce03277..c24ea79de76 100644 --- a/src/plugins/provider-auth-helpers.ts +++ b/src/plugins/provider-auth-helpers.ts @@ -103,6 +103,28 @@ export function buildApiKeyCredential( }; } +export function upsertApiKeyProfile(params: { + provider: string; + input: SecretInput; + agentDir?: string; + options?: ApiKeyStorageOptions; + profileId?: string; + metadata?: Record; +}): string { + const profileId = params.profileId ?? buildAuthProfileId({ providerId: params.provider }); + upsertAuthProfile({ + profileId, + credential: buildApiKeyCredential( + params.provider, + params.input, + params.metadata, + params.options, + ), + agentDir: resolveAuthAgentDir(params.agentDir), + }); + return profileId; +} + export function applyAuthProfileConfig( cfg: OpenClawConfig, params: { diff --git a/src/plugins/provider-auth-storage.ts b/src/plugins/provider-auth-storage.ts deleted file mode 100644 index 15cd909fddf..00000000000 --- a/src/plugins/provider-auth-storage.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { resolveOpenClawAgentDir } from "../agents/agent-paths.js"; -import { upsertAuthProfile } from "../agents/auth-profiles.js"; -import type { SecretInput } from "../config/types.secrets.js"; -import { - buildApiKeyCredential, - type ApiKeyStorageOptions, - writeOAuthCredentials, - type WriteOAuthCredentialsOptions, -} from "./provider-auth-helpers.js"; - -const resolveAuthAgentDir = (agentDir?: string) => agentDir ?? resolveOpenClawAgentDir(); - -type ProviderApiKeySetter = ( - key: SecretInput, - agentDir?: string, - options?: ApiKeyStorageOptions, -) => Promise | void; - -function upsertProviderApiKeyProfile(params: { - provider: string; - key: SecretInput; - agentDir?: string; - options?: ApiKeyStorageOptions; - profileId?: string; - metadata?: Record; -}) { - upsertAuthProfile({ - profileId: params.profileId ?? `${params.provider}:default`, - credential: buildApiKeyCredential(params.provider, params.key, params.metadata, params.options), - agentDir: resolveAuthAgentDir(params.agentDir), - }); -} - -function createProviderApiKeySetter( - provider: string, - resolveKey: (key: SecretInput) => SecretInput = (key) => key, -): ProviderApiKeySetter { - return async (key, agentDir, options) => { - upsertProviderApiKeyProfile({ - provider, - key: resolveKey(key), - agentDir, - options, - }); - }; -} - -type ProviderApiKeySetterSpec = { - provider: string; - resolveKey?: (key: SecretInput) => SecretInput; -}; - -function createProviderApiKeySetters>( - specs: T, -): { [K in keyof T]: ProviderApiKeySetter } { - const entries = Object.entries(specs).map(([name, spec]) => [ - name, - createProviderApiKeySetter(spec.provider, spec.resolveKey), - ]); - return Object.fromEntries(entries) as { [K in keyof T]: ProviderApiKeySetter }; -} - -export { - buildApiKeyCredential, - type ApiKeyStorageOptions, - writeOAuthCredentials, - type WriteOAuthCredentialsOptions, -}; - -const { - setAnthropicApiKey, - setOpenaiApiKey, - setGeminiApiKey, - setMoonshotApiKey, - setKimiCodingApiKey, - setVolcengineApiKey, - setByteplusApiKey, - setSyntheticApiKey, - setVeniceApiKey, - setZaiApiKey, - setXiaomiApiKey, - setOpenrouterApiKey, - setLitellmApiKey, - setVercelAiGatewayApiKey, - setTogetherApiKey, - setHuggingfaceApiKey, - setQianfanApiKey, - setQwenApiKey, - setModelStudioApiKey, - setXaiApiKey, - setMistralApiKey, - setKilocodeApiKey, -} = createProviderApiKeySetters({ - setAnthropicApiKey: { provider: "anthropic" }, - setOpenaiApiKey: { provider: "openai" }, - setGeminiApiKey: { provider: "google" }, - setMoonshotApiKey: { provider: "moonshot" }, - setKimiCodingApiKey: { provider: "kimi" }, - setVolcengineApiKey: { provider: "volcengine" }, - setByteplusApiKey: { provider: "byteplus" }, - setSyntheticApiKey: { provider: "synthetic" }, - setVeniceApiKey: { provider: "venice" }, - setZaiApiKey: { provider: "zai" }, - setXiaomiApiKey: { provider: "xiaomi" }, - setOpenrouterApiKey: { - provider: "openrouter", - resolveKey: (key) => (typeof key === "string" && key === "undefined" ? "" : key), - }, - setLitellmApiKey: { provider: "litellm" }, - setVercelAiGatewayApiKey: { provider: "vercel-ai-gateway" }, - setTogetherApiKey: { provider: "together" }, - setHuggingfaceApiKey: { provider: "huggingface" }, - setQianfanApiKey: { provider: "qianfan" }, - setQwenApiKey: { provider: "qwen" }, - setModelStudioApiKey: { provider: "qwen" }, - setXaiApiKey: { provider: "xai" }, - setMistralApiKey: { provider: "mistral" }, - setKilocodeApiKey: { provider: "kilocode" }, -}); - -export { - setAnthropicApiKey, - setOpenaiApiKey, - setGeminiApiKey, - setMoonshotApiKey, - setKimiCodingApiKey, - setVolcengineApiKey, - setByteplusApiKey, - setSyntheticApiKey, - setVeniceApiKey, - setZaiApiKey, - setXiaomiApiKey, - setOpenrouterApiKey, - setLitellmApiKey, - setVercelAiGatewayApiKey, - setTogetherApiKey, - setHuggingfaceApiKey, - setQianfanApiKey, - setQwenApiKey, - setModelStudioApiKey, - setXaiApiKey, - setMistralApiKey, - setKilocodeApiKey, -}; - -export async function setMinimaxApiKey( - key: SecretInput, - agentDir?: string, - profileId: string = "minimax:default", - options?: ApiKeyStorageOptions, -) { - const provider = profileId.split(":")[0] ?? "minimax"; - upsertProviderApiKeyProfile({ provider, key, agentDir, options, profileId }); -} - -export async function setCloudflareAiGatewayConfig( - accountId: string, - gatewayId: string, - apiKey: SecretInput, - agentDir?: string, - options?: ApiKeyStorageOptions, -) { - const normalizedAccountId = accountId.trim(); - const normalizedGatewayId = gatewayId.trim(); - upsertProviderApiKeyProfile({ - provider: "cloudflare-ai-gateway", - key: apiKey, - agentDir, - options, - metadata: { - accountId: normalizedAccountId, - gatewayId: normalizedGatewayId, - }, - }); -} - -export async function setOpencodeZenApiKey( - key: SecretInput, - agentDir?: string, - options?: ApiKeyStorageOptions, -) { - await setSharedOpencodeApiKey(key, agentDir, options); -} - -export async function setOpencodeGoApiKey( - key: SecretInput, - agentDir?: string, - options?: ApiKeyStorageOptions, -) { - await setSharedOpencodeApiKey(key, agentDir, options); -} - -async function setSharedOpencodeApiKey( - key: SecretInput, - agentDir?: string, - options?: ApiKeyStorageOptions, -) { - for (const provider of ["opencode", "opencode-go"] as const) { - upsertProviderApiKeyProfile({ provider, key, agentDir, options }); - } -}