fix(openai): scope external codex auth to realtime

This commit is contained in:
Ayaan Zaidi
2026-05-25 08:42:30 +05:30
parent ffb02a5919
commit 9db04a27eb
4 changed files with 46 additions and 15 deletions

View File

@@ -302,6 +302,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
expect(resolveProviderAuthProfileApiKeyMock).toHaveBeenCalledWith({
provider: "openai-codex",
cfg: {},
includeExternalCliAuth: true,
});
const request = requireFetchRequest();
expectRecordFields(request, "fetch request", {
@@ -589,6 +590,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
expect(isProviderAuthProfileConfiguredMock).toHaveBeenCalledWith({
provider: "openai-codex",
cfg,
includeExternalCliAuth: true,
});
});
@@ -632,6 +634,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
expect(resolveProviderAuthProfileApiKeyMock).toHaveBeenCalledWith({
provider: "openai-codex",
cfg,
includeExternalCliAuth: true,
});
expectRecordFields(requireFetchHeaders(), "fetch headers", {
Authorization: "Bearer oauth-realtime-token", // pragma: allowlist secret
@@ -663,6 +666,7 @@ describe("buildOpenAIRealtimeVoiceProvider", () => {
expect(resolveProviderAuthProfileApiKeyMock).toHaveBeenCalledWith({
provider: "openai-codex",
cfg,
includeExternalCliAuth: true,
});
expectRecordFields(requireFetchHeaders(), "fetch headers", {
Authorization: "Bearer oauth-realtime-token", // pragma: allowlist secret

View File

@@ -349,6 +349,7 @@ async function resolveOpenAIRealtimeDefaultAuth(params: {
const codexToken = await resolveProviderAuthProfileApiKey({
provider: "openai-codex",
cfg: params.cfg,
includeExternalCliAuth: true,
});
if (codexToken) {
return { status: "available", kind: "codex-oauth", value: codexToken };
@@ -387,6 +388,7 @@ function hasOpenAIRealtimeBrowserAuthInput(params: {
isProviderAuthProfileConfigured({
provider: "openai-codex",
cfg: params.cfg,
includeExternalCliAuth: true,
}) || hasOpenAIRealtimeApiKeyInput(undefined)
);
}
@@ -725,6 +727,7 @@ class OpenAIRealtimeVoiceBridge implements RealtimeVoiceBridge {
!isProviderAuthProfileConfigured({
provider: "openai-codex",
cfg: cfg.cfg,
includeExternalCliAuth: true,
})
) {
const directApiKey = resolveOpenAIRealtimeEnvApiKey();

View File

@@ -86,10 +86,14 @@ describe("provider auth profile helpers", () => {
);
});
it("scopes external CLI auth discovery to provider profile resolution", async () => {
it("only discovers external CLI auth when provider resolution opts in", async () => {
vi.resetModules();
const store: AuthProfileStore = {
const primaryStore: AuthProfileStore = {
version: 1,
profiles: {},
};
const externalStore: AuthProfileStore = {
version: 1,
profiles: {
"openai-codex:default": {
@@ -102,7 +106,10 @@ describe("provider auth profile helpers", () => {
},
};
const externalCli = { mode: "scoped", providerIds: ["openai-codex"] };
const loadAuthProfileStoreForSecretsRuntime = vi.fn(() => store);
const loadAuthProfileStoreForSecretsRuntime = vi.fn(
(_agentDir?: string, options?: { externalCli?: unknown }) =>
options?.externalCli ? externalStore : primaryStore,
);
vi.doMock("../agents/agent-scope-config.js", () => ({
resolveDefaultAgentDir: () => "/tmp/openclaw-agent",
@@ -126,8 +133,8 @@ describe("provider auth profile helpers", () => {
.map(([profileId]) => profileId),
}));
vi.doMock("../agents/auth-profiles/store.js", () => ({
ensureAuthProfileStore: vi.fn(() => store),
ensureAuthProfileStoreForLocalUpdate: vi.fn(() => store),
ensureAuthProfileStore: vi.fn(() => primaryStore),
ensureAuthProfileStoreForLocalUpdate: vi.fn(() => primaryStore),
loadAuthProfileStoreForSecretsRuntime,
loadAuthProfileStoreWithoutExternalProfiles: vi.fn(() => ({ version: 1, profiles: {} })),
updateAuthProfileStoreWithLock: vi.fn(),
@@ -135,9 +142,18 @@ describe("provider auth profile helpers", () => {
const { isProviderAuthProfileConfigured } = await import("./provider-auth.js");
expect(isProviderAuthProfileConfigured({ provider: "openai-codex" })).toBe(true);
expect(loadAuthProfileStoreForSecretsRuntime).toHaveBeenCalledWith("/tmp/openclaw-agent", {
externalCli,
});
expect(isProviderAuthProfileConfigured({ provider: "openai-codex" })).toBe(false);
expect(
isProviderAuthProfileConfigured({
provider: "openai-codex",
includeExternalCliAuth: true,
}),
).toBe(true);
expect(loadAuthProfileStoreForSecretsRuntime).toHaveBeenNthCalledWith(1, "/tmp/openclaw-agent");
expect(loadAuthProfileStoreForSecretsRuntime).toHaveBeenNthCalledWith(
2,
"/tmp/openclaw-agent",
{ externalCli },
);
});
});

View File

@@ -289,6 +289,7 @@ export function listUsableProviderAuthProfileIds(params: {
cfg?: OpenClawConfig;
agentDir?: string;
allowKeychainPrompt?: boolean;
includeExternalCliAuth?: boolean;
}): { agentDir: string; profileIds: string[] } {
try {
const { agentDir, profileIds } = resolveUsableProviderAuthProfiles(params);
@@ -303,6 +304,7 @@ export function isProviderAuthProfileConfigured(params: {
cfg?: OpenClawConfig;
agentDir?: string;
allowKeychainPrompt?: boolean;
includeExternalCliAuth?: boolean;
}): boolean {
return listUsableProviderAuthProfileIds(params).profileIds.length > 0;
}
@@ -312,6 +314,7 @@ export async function resolveProviderAuthProfileApiKey(params: {
cfg?: OpenClawConfig;
agentDir?: string;
allowKeychainPrompt?: boolean;
includeExternalCliAuth?: boolean;
}): Promise<string | undefined> {
const { agentDir, profileIds, store } = resolveUsableProviderAuthProfiles(params);
if (!agentDir || profileIds.length === 0) {
@@ -336,14 +339,19 @@ function resolveUsableProviderAuthProfiles(params: {
cfg?: OpenClawConfig;
agentDir?: string;
allowKeychainPrompt?: boolean;
includeExternalCliAuth?: boolean;
}): { agentDir: string; profileIds: string[]; store: AuthProfileStore } {
const agentDir = params.agentDir?.trim() || resolveDefaultAgentDir(params.cfg ?? {});
const externalCli = externalCliDiscoveryForProviderAuth({
cfg: params.cfg,
provider: params.provider,
allowKeychainPrompt: params.allowKeychainPrompt,
});
const store = loadAuthProfileStoreForSecretsRuntime(agentDir, { externalCli });
const externalCli = params.includeExternalCliAuth
? externalCliDiscoveryForProviderAuth({
cfg: params.cfg,
provider: params.provider,
allowKeychainPrompt: params.allowKeychainPrompt,
})
: undefined;
const store = externalCli
? loadAuthProfileStoreForSecretsRuntime(agentDir, { externalCli })
: loadAuthProfileStoreForSecretsRuntime(agentDir);
const profileIds = resolveAuthProfileOrder({
cfg: params.cfg,
store,