From e00f9c7a9dcc06b4b1f27af15d43ca2f5ec99b63 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 17 Apr 2026 07:42:00 +0100 Subject: [PATCH] test: trim custom provider onboarding duplicates --- ...oard-non-interactive.provider-auth.test.ts | 42 ------------- .../onboard-non-interactive/api-keys.test.ts | 63 +++++++++++++++++++ .../local/auth-choice.test.ts | 38 +++++++++++ 3 files changed, 101 insertions(+), 42 deletions(-) diff --git a/src/commands/onboard-non-interactive.provider-auth.test.ts b/src/commands/onboard-non-interactive.provider-auth.test.ts index 5c1d3ce7b3e..d6c5a14c6ed 100644 --- a/src/commands/onboard-non-interactive.provider-auth.test.ts +++ b/src/commands/onboard-non-interactive.provider-auth.test.ts @@ -1132,7 +1132,6 @@ async function runOnboardingAndReadConfig( const CUSTOM_LOCAL_BASE_URL = "https://models.custom.local/v1"; const CUSTOM_LOCAL_MODEL_ID = "local-large"; -const CUSTOM_LOCAL_PROVIDER_ID = "custom-models-custom-local"; async function runCustomLocalNonInteractive( runtime: NonInteractiveRuntime, @@ -1147,19 +1146,6 @@ async function runCustomLocalNonInteractive( }); } -async function readCustomLocalProviderApiKey(configPath: string): Promise { - const cfg = await readJsonFile(configPath); - const apiKey = cfg.models?.providers?.[CUSTOM_LOCAL_PROVIDER_ID]?.apiKey; - return typeof apiKey === "string" ? apiKey : undefined; -} - -async function readCustomLocalProviderApiKeyInput( - configPath: string, -): Promise { - const cfg = await readJsonFile(configPath); - return cfg.models?.providers?.[CUSTOM_LOCAL_PROVIDER_ID]?.apiKey; -} - async function expectApiKeyProfile(params: { profileId: string; provider: string; @@ -1580,34 +1566,6 @@ describe("onboard (non-interactive): provider auth", () => { ); }); - it("uses CUSTOM_API_KEY env fallback for non-interactive custom provider auth", async () => { - await withOnboardEnv( - "openclaw-onboard-custom-provider-env-fallback-", - async ({ configPath, runtime }) => { - process.env.CUSTOM_API_KEY = "custom-env-key"; // pragma: allowlist secret - await runCustomLocalNonInteractive(runtime); - expect(await readCustomLocalProviderApiKey(configPath)).toBe("custom-env-key"); - }, - ); - }); - - it("stores CUSTOM_API_KEY env ref for non-interactive custom provider auth in ref mode", async () => { - await withOnboardEnv( - "openclaw-onboard-custom-provider-env-ref-", - async ({ configPath, runtime }) => { - process.env.CUSTOM_API_KEY = "custom-env-key"; // pragma: allowlist secret - await runCustomLocalNonInteractive(runtime, { - secretInputMode: "ref", // pragma: allowlist secret - }); - expect(await readCustomLocalProviderApiKeyInput(configPath)).toEqual({ - source: "env", - provider: "default", - id: "CUSTOM_API_KEY", - }); - }, - ); - }); - it("fails fast for custom provider ref mode when --custom-api-key is set but CUSTOM_API_KEY env is missing", async () => { await withOnboardEnv("openclaw-onboard-custom-provider-ref-flag-", async ({ runtime }) => { const providedSecret = "custom-inline-key-should-not-leak"; // pragma: allowlist secret diff --git a/src/commands/onboard-non-interactive/api-keys.test.ts b/src/commands/onboard-non-interactive/api-keys.test.ts index d55667229be..8e0da116281 100644 --- a/src/commands/onboard-non-interactive/api-keys.test.ts +++ b/src/commands/onboard-non-interactive/api-keys.test.ts @@ -92,6 +92,69 @@ describe("resolveNonInteractiveApiKey", () => { } }); + it("returns explicit env fallback keys when provider env discovery misses", async () => { + const runtime = createRuntime(); + resolveEnvApiKey.mockReturnValue(null); + const previousCustomApiKey = process.env.CUSTOM_API_KEY; + process.env.CUSTOM_API_KEY = "custom-env-key"; // pragma: allowlist secret + + try { + const result = await resolveNonInteractiveApiKey({ + provider: "custom-models-custom-local", + cfg: {}, + flagName: "--custom-api-key", + envVar: "CUSTOM_API_KEY", + envVarName: "CUSTOM_API_KEY", + runtime: runtime as never, + }); + + expect(result).toEqual({ + key: "custom-env-key", + source: "env", + envVarName: "CUSTOM_API_KEY", + }); + expect(runtime.exit).not.toHaveBeenCalled(); + } finally { + if (previousCustomApiKey === undefined) { + delete process.env.CUSTOM_API_KEY; + } else { + process.env.CUSTOM_API_KEY = previousCustomApiKey; + } + } + }); + + it("returns explicit env fallback refs in secret-ref mode", async () => { + const runtime = createRuntime(); + resolveEnvApiKey.mockReturnValue(null); + const previousCustomApiKey = process.env.CUSTOM_API_KEY; + process.env.CUSTOM_API_KEY = "custom-env-key"; // pragma: allowlist secret + + try { + const result = await resolveNonInteractiveApiKey({ + provider: "custom-models-custom-local", + cfg: {}, + flagName: "--custom-api-key", + envVar: "CUSTOM_API_KEY", + envVarName: "CUSTOM_API_KEY", + runtime: runtime as never, + secretInputMode: "ref", + }); + + expect(result).toEqual({ + key: "custom-env-key", + source: "env", + envVarName: "CUSTOM_API_KEY", + }); + expect(runtime.exit).not.toHaveBeenCalled(); + } finally { + if (previousCustomApiKey === undefined) { + delete process.env.CUSTOM_API_KEY; + } else { + process.env.CUSTOM_API_KEY = previousCustomApiKey; + } + } + }); + it("falls back to a matching API-key profile after flag and env are absent", async () => { const runtime = createRuntime(); authStore.profiles["custom-models-custom-local:default"] = { diff --git a/src/commands/onboard-non-interactive/local/auth-choice.test.ts b/src/commands/onboard-non-interactive/local/auth-choice.test.ts index f611295805a..659cfae36ec 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.test.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.test.ts @@ -72,4 +72,42 @@ describe("applyNonInteractiveAuthChoice", () => { expect(runtime.exit).toHaveBeenCalledWith(1); expect(applyNonInteractivePluginProviderChoice).toHaveBeenCalledOnce(); }); + + it("stores custom provider env refs through the local auth-choice seam", async () => { + const runtime = createRuntime(); + const nextConfig = { agents: { defaults: {} } } as OpenClawConfig; + resolveNonInteractiveApiKey.mockResolvedValueOnce({ + key: "custom-env-key", + source: "env", + envVarName: "CUSTOM_API_KEY", + }); + + const result = await applyNonInteractiveAuthChoice({ + nextConfig, + authChoice: "custom-api-key", + opts: { + customBaseUrl: "https://models.custom.local/v1", + customModelId: "local-large", + secretInputMode: "ref", + } as never, + runtime: runtime as never, + baseConfig: nextConfig, + }); + + expect(result?.models?.providers?.["custom-models-custom-local"]?.apiKey).toEqual({ + source: "env", + provider: "default", + id: "CUSTOM_API_KEY", + }); + expect(result?.agents?.defaults?.model?.primary).toBe("custom-models-custom-local/local-large"); + expect(resolveNonInteractiveApiKey).toHaveBeenCalledWith( + expect.objectContaining({ + provider: "custom-models-custom-local", + flagName: "--custom-api-key", + envVar: "CUSTOM_API_KEY", + envVarName: "CUSTOM_API_KEY", + secretInputMode: "ref", + }), + ); + }); });