mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
refactor(auth): drop provider auth storage switchboard
This commit is contained in:
@@ -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<string, { key?: string; keyRef?: unknown }>;
|
||||
@@ -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<string, { key?: string; keyRef?: unknown }>;
|
||||
|
||||
@@ -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<string, { type?: string; provider?: string; key?: string }>;
|
||||
|
||||
@@ -103,6 +103,28 @@ export function buildApiKeyCredential(
|
||||
};
|
||||
}
|
||||
|
||||
export function upsertApiKeyProfile(params: {
|
||||
provider: string;
|
||||
input: SecretInput;
|
||||
agentDir?: string;
|
||||
options?: ApiKeyStorageOptions;
|
||||
profileId?: string;
|
||||
metadata?: Record<string, string>;
|
||||
}): 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: {
|
||||
|
||||
@@ -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> | void;
|
||||
|
||||
function upsertProviderApiKeyProfile(params: {
|
||||
provider: string;
|
||||
key: SecretInput;
|
||||
agentDir?: string;
|
||||
options?: ApiKeyStorageOptions;
|
||||
profileId?: string;
|
||||
metadata?: Record<string, string>;
|
||||
}) {
|
||||
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<const T extends Record<string, ProviderApiKeySetterSpec>>(
|
||||
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 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user