From a4a1abbe3097a77d0bcbed48b2896609196e6be9 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 23 May 2026 11:13:06 +0100 Subject: [PATCH] fix: honor disabled synthetic auth lookup --- src/agents/model-auth.test.ts | 13 ++++++++++ src/agents/model-auth.ts | 8 +++++-- src/agents/model-provider-auth.test.ts | 33 ++++++++++++++++++++++++-- src/agents/model-provider-auth.ts | 1 + 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/agents/model-auth.test.ts b/src/agents/model-auth.test.ts index b5d55b2067c0..d67cc88fbf9d 100644 --- a/src/agents/model-auth.test.ts +++ b/src/agents/model-auth.test.ts @@ -126,6 +126,7 @@ vi.mock("../plugins/provider-runtime.js", async () => { let applyAuthHeaderOverride: typeof import("./model-auth.js").applyAuthHeaderOverride; let applyLocalNoAuthHeaderOverride: typeof import("./model-auth.js").applyLocalNoAuthHeaderOverride; +let createRuntimeProviderAuthLookup: typeof import("./model-auth.js").createRuntimeProviderAuthLookup; let formatMissingAuthError: typeof import("./model-auth.js").formatMissingAuthError; let hasUsableCustomProviderApiKey: typeof import("./model-auth.js").hasUsableCustomProviderApiKey; let hasSyntheticLocalProviderAuthConfig: typeof import("./model-auth.js").hasSyntheticLocalProviderAuthConfig; @@ -146,6 +147,7 @@ beforeAll(async () => { ({ applyAuthHeaderOverride, applyLocalNoAuthHeaderOverride, + createRuntimeProviderAuthLookup, formatMissingAuthError, hasSyntheticLocalProviderAuthConfig, getApiKeyForModel, @@ -166,6 +168,17 @@ afterEach(() => { clearRuntimeConfigSnapshot(); }); +describe("createRuntimeProviderAuthLookup", () => { + it("omits synthetic auth refs when plugin synthetic auth is disabled", () => { + expect( + createRuntimeProviderAuthLookup({ + includePluginSyntheticAuth: false, + env: {}, + }).syntheticAuthProviderRefs, + ).toBeUndefined(); + }); +}); + async function withoutEnv(key: string, fn: () => Promise): Promise { const previous = process.env[key]; delete process.env[key]; diff --git a/src/agents/model-auth.ts b/src/agents/model-auth.ts index 1206aff46b1e..b4b8a59963b1 100644 --- a/src/agents/model-auth.ts +++ b/src/agents/model-auth.ts @@ -106,6 +106,7 @@ export function createRuntimeProviderAuthLookup(params: { cfg?: OpenClawConfig; workspaceDir?: string; env?: NodeJS.ProcessEnv; + includePluginSyntheticAuth?: boolean; }): RuntimeProviderAuthLookup { const env = params.env ?? process.env; const lookupParams = { @@ -113,14 +114,17 @@ export function createRuntimeProviderAuthLookup(params: { workspaceDir: params.workspaceDir, env, }; - const syntheticAuthProviderRefs = resolveRuntimeSyntheticAuthProviderRefState(lookupParams); + const syntheticAuthProviderRefs = + params.includePluginSyntheticAuth === false + ? undefined + : resolveRuntimeSyntheticAuthProviderRefState(lookupParams); return { envApiKey: { aliasMap: resolveProviderAuthAliasMap(lookupParams), candidateMap: resolveProviderEnvApiKeyCandidates(lookupParams), authEvidenceMap: resolveProviderEnvAuthEvidence(lookupParams), }, - syntheticAuthProviderRefs: syntheticAuthProviderRefs.complete + syntheticAuthProviderRefs: syntheticAuthProviderRefs?.complete ? syntheticAuthProviderRefs.refs : undefined, }; diff --git a/src/agents/model-provider-auth.test.ts b/src/agents/model-provider-auth.test.ts index 8efd85c98afb..69a64e3af9c8 100644 --- a/src/agents/model-provider-auth.test.ts +++ b/src/agents/model-provider-auth.test.ts @@ -63,8 +63,12 @@ vi.mock("./agent-scope-config.js", () => ({ resolveDefaultAgentId: () => "default", })); -const { clearCurrentProviderAuthState, hasAuthForModelProvider, warmCurrentProviderAuthState } = - await import("./model-provider-auth.js"); +const { + clearCurrentProviderAuthState, + createProviderAuthChecker, + hasAuthForModelProvider, + warmCurrentProviderAuthState, +} = await import("./model-provider-auth.js"); describe("prepared provider auth state", () => { afterEach(() => { @@ -147,6 +151,31 @@ describe("prepared provider auth state", () => { expect(modelAuthMocks.hasRuntimeAvailableProviderAuth).toHaveBeenCalledTimes(2); }); + it("does not prepare synthetic auth refs when plugin synthetic auth is disabled", async () => { + const cfg = {} as OpenClawConfig; + modelAuthMocks.hasRuntimeAvailableProviderAuth.mockReturnValue(false); + + const hasAuth = createProviderAuthChecker({ + cfg, + allowPluginSyntheticAuth: false, + discoverExternalCliAuth: false, + }); + + await expect(hasAuth("openai")).resolves.toBe(false); + + expect(modelAuthMocks.createRuntimeProviderAuthLookup).toHaveBeenCalledWith({ + cfg, + workspaceDir: undefined, + env: undefined, + includePluginSyntheticAuth: false, + }); + const runtimeLookup = + modelAuthMocks.hasRuntimeAvailableProviderAuth.mock.calls[0]?.[0].runtimeLookup; + expect(runtimeLookup).toBe( + modelAuthMocks.createRuntimeProviderAuthLookup.mock.results[0]?.value, + ); + }); + it("hasAuthForModelProvider uses the prepared answer for equivalent runtime config clones", async () => { const cfg = { gateway: { port: 18789 } } as OpenClawConfig; const clonedCfg = structuredClone(cfg); diff --git a/src/agents/model-provider-auth.ts b/src/agents/model-provider-auth.ts index 0c5cde8b540e..7138cdf1f4f8 100644 --- a/src/agents/model-provider-auth.ts +++ b/src/agents/model-provider-auth.ts @@ -188,6 +188,7 @@ export function createProviderAuthChecker(params: { cfg: params.cfg, workspaceDir: params.workspaceDir, env: params.env, + includePluginSyntheticAuth: params.allowPluginSyntheticAuth !== false, })), }); authCache.set(key, value);