From c3a0fb9325c95f6ae7a8b5bca792f64adb08c71e Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 5 May 2026 02:14:27 -0700 Subject: [PATCH] test(live): bound provider discovery hooks --- src/agents/models.profiles.live.test.ts | 9 +++- .../pi-auth-discovery.external-cli.test.ts | 43 +++++++++++++++++-- src/agents/pi-auth-discovery.ts | 24 ++++++++--- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/agents/models.profiles.live.test.ts b/src/agents/models.profiles.live.test.ts index 1e1e2fcfb26..1f61235ed28 100644 --- a/src/agents/models.profiles.live.test.ts +++ b/src/agents/models.profiles.live.test.ts @@ -732,11 +732,18 @@ describeLive("live models (profile keys)", () => { } const providers = parseProviderFilter(process.env.OPENCLAW_LIVE_PROVIDERS); + const providerList = providers ? [...providers] : null; const agentDir = resolveOpenClawAgentDir(); const authStorage = discoverAuthStorage(agentDir, { config: cfg, env: process.env, - ...(providers ? { externalCli: externalCliDiscoveryForProviders({ cfg, providers }) } : {}), + ...(providerList + ? { + externalCli: externalCliDiscoveryForProviders({ cfg, providers: providerList }), + skipExternalAuthProfiles: true, + syntheticAuthProviderRefs: providerList, + } + : {}), }); logProgress("[live-models] loading model registry"); const models = await withLiveStageTimeout( diff --git a/src/agents/pi-auth-discovery.external-cli.test.ts b/src/agents/pi-auth-discovery.external-cli.test.ts index 06cdea27c8c..17ce8b1b2a4 100644 --- a/src/agents/pi-auth-discovery.external-cli.test.ts +++ b/src/agents/pi-auth-discovery.external-cli.test.ts @@ -1,8 +1,10 @@ -import { describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/types.openclaw.js"; const storeMocks = vi.hoisted(() => ({ ensureAuthProfileStore: vi.fn(() => ({ version: 1, profiles: {} })), + ensureAuthProfileStoreWithoutExternalProfiles: vi.fn(() => ({ version: 1, profiles: {} })), + loadAuthProfileStoreWithoutExternalProfiles: vi.fn(() => ({ version: 1, profiles: {} })), loadAuthProfileStoreForRuntime: vi.fn(() => ({ version: 1, profiles: {} })), loadAuthProfileStoreForSecretsRuntime: vi.fn(() => ({ version: 1, profiles: {} })), })); @@ -16,6 +18,11 @@ const discoveryCoreMocks = vi.hoisted(() => ({ scrubLegacyStaticAuthJsonEntriesForDiscovery: vi.fn(), })); +const syntheticAuthMocks = vi.hoisted(() => ({ + resolveRuntimeSyntheticAuthProviderRefs: vi.fn(() => []), + resolveProviderSyntheticAuthWithPlugin: vi.fn(), +})); + vi.mock("./auth-profiles/store.js", () => storeMocks); vi.mock("./pi-auth-credentials.js", () => credentialMocks); @@ -23,17 +30,22 @@ vi.mock("./pi-auth-credentials.js", () => credentialMocks); vi.mock("./pi-auth-discovery-core.js", () => discoveryCoreMocks); vi.mock("./synthetic-auth.runtime.js", () => ({ - resolveRuntimeSyntheticAuthProviderRefs: () => [], + resolveRuntimeSyntheticAuthProviderRefs: + syntheticAuthMocks.resolveRuntimeSyntheticAuthProviderRefs, })); vi.mock("../plugins/provider-runtime.js", () => ({ - resolveProviderSyntheticAuthWithPlugin: vi.fn(), + resolveProviderSyntheticAuthWithPlugin: syntheticAuthMocks.resolveProviderSyntheticAuthWithPlugin, })); import { externalCliDiscoveryForProviders } from "./auth-profiles/external-cli-discovery.js"; import { resolvePiCredentialsForDiscovery } from "./pi-auth-discovery.js"; describe("resolvePiCredentialsForDiscovery external CLI scoping", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + it("threads scoped external CLI discovery into writable auth store loading", () => { const cfg = {} as OpenClawConfig; const externalCli = externalCliDiscoveryForProviders({ @@ -76,4 +88,29 @@ describe("resolvePiCredentialsForDiscovery external CLI scoping", () => { readOnly: true, }); }); + + it("can skip runtime external auth overlays and scope synthetic auth discovery", () => { + resolvePiCredentialsForDiscovery("/tmp/openclaw-agent", { + env: {}, + skipExternalAuthProfiles: true, + syntheticAuthProviderRefs: ["fireworks"], + }); + + expect(storeMocks.ensureAuthProfileStoreWithoutExternalProfiles).toHaveBeenCalledWith( + "/tmp/openclaw-agent", + { + allowKeychainPrompt: false, + }, + ); + expect(storeMocks.ensureAuthProfileStore).not.toHaveBeenCalled(); + expect(syntheticAuthMocks.resolveRuntimeSyntheticAuthProviderRefs).not.toHaveBeenCalled(); + expect(syntheticAuthMocks.resolveProviderSyntheticAuthWithPlugin).toHaveBeenCalledWith({ + provider: "fireworks", + context: { + config: undefined, + provider: "fireworks", + providerConfig: undefined, + }, + }); + }); }); diff --git a/src/agents/pi-auth-discovery.ts b/src/agents/pi-auth-discovery.ts index 1b09d6b28d0..84490d50afd 100644 --- a/src/agents/pi-auth-discovery.ts +++ b/src/agents/pi-auth-discovery.ts @@ -3,6 +3,8 @@ import { resolveRuntimeSyntheticAuthProviderRefs } from "../plugins/synthetic-au import type { ExternalCliAuthDiscovery } from "./auth-profiles/external-cli-discovery.js"; import { ensureAuthProfileStore, + ensureAuthProfileStoreWithoutExternalProfiles, + loadAuthProfileStoreWithoutExternalProfiles, loadAuthProfileStoreForRuntime, loadAuthProfileStoreForSecretsRuntime, } from "./auth-profiles/store.js"; @@ -15,7 +17,9 @@ import { export type DiscoverAuthStorageOptions = { externalCli?: ExternalCliAuthDiscovery; readOnly?: boolean; + skipExternalAuthProfiles?: boolean; skipCredentials?: boolean; + syntheticAuthProviderRefs?: Iterable; } & PiDiscoveryAuthLookupOptions; export function resolvePiCredentialsForDiscovery( @@ -28,17 +32,25 @@ export function resolvePiCredentialsForDiscovery( ...(options?.externalCli ? { externalCli: options.externalCli } : {}), }; const store = - options?.readOnly === true - ? options.externalCli || options.config - ? loadAuthProfileStoreForRuntime(agentDir, { readOnly: true, ...storeOptions }) - : loadAuthProfileStoreForSecretsRuntime(agentDir) - : ensureAuthProfileStore(agentDir, storeOptions); + options?.skipExternalAuthProfiles === true + ? options.readOnly === true + ? loadAuthProfileStoreWithoutExternalProfiles(agentDir) + : ensureAuthProfileStoreWithoutExternalProfiles(agentDir, { + allowKeychainPrompt: false, + }) + : options?.readOnly === true + ? options.externalCli || options.config + ? loadAuthProfileStoreForRuntime(agentDir, { readOnly: true, ...storeOptions }) + : loadAuthProfileStoreForSecretsRuntime(agentDir) + : ensureAuthProfileStore(agentDir, storeOptions); const credentials = addEnvBackedPiCredentials(resolvePiCredentialMapFromStore(store), { config: options?.config, workspaceDir: options?.workspaceDir, env: options?.env, }); - for (const provider of resolveRuntimeSyntheticAuthProviderRefs()) { + const syntheticAuthProviderRefs = + options?.syntheticAuthProviderRefs ?? resolveRuntimeSyntheticAuthProviderRefs(); + for (const provider of syntheticAuthProviderRefs) { if (credentials[provider]) { continue; }