Onboarding: disallow GigaChat profile fallback

This commit is contained in:
Alexander Davydov 2026-03-18 13:48:05 +03:00
parent 19eb8be825
commit 6e1e4b23da
2 changed files with 82 additions and 0 deletions

View File

@ -0,0 +1,77 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../../config/config.js";
import { applySimpleNonInteractiveApiKeyChoice } from "./auth-choice.api-key-providers.js";
const applyAuthProfileConfig = vi.hoisted(() => vi.fn((cfg: OpenClawConfig) => cfg));
vi.mock("../../../plugins/provider-auth-helpers.js", () => ({
applyAuthProfileConfig,
}));
const setGigachatApiKey = vi.hoisted(() => vi.fn(async () => {}));
const setLitellmApiKey = vi.hoisted(() => vi.fn(async () => {}));
vi.mock("../../../plugins/provider-auth-storage.js", () => ({
setGigachatApiKey,
setLitellmApiKey,
}));
const applyGigachatConfig = vi.hoisted(() => vi.fn((cfg: OpenClawConfig) => cfg));
vi.mock("../../onboard-auth.config-core.js", () => ({
applyGigachatConfig,
}));
const applyLitellmConfig = vi.hoisted(() => vi.fn((cfg: OpenClawConfig) => cfg));
vi.mock("../../onboard-auth.config-litellm.js", () => ({
applyLitellmConfig,
}));
describe("applySimpleNonInteractiveApiKeyChoice", () => {
beforeEach(() => {
vi.clearAllMocks();
applyAuthProfileConfig.mockImplementation((cfg: OpenClawConfig) => cfg);
applyGigachatConfig.mockImplementation((cfg: OpenClawConfig) => cfg);
applyLitellmConfig.mockImplementation((cfg: OpenClawConfig) => cfg);
});
it("disables profile fallback for GigaChat personal OAuth onboarding", async () => {
const nextConfig = { agents: { defaults: {} } } as OpenClawConfig;
const resolveApiKey = vi.fn(async () => ({
key: "gigachat-oauth-credentials",
source: "env" as const,
}));
const maybeSetResolvedApiKey = vi.fn(async (resolved, setter) => {
await setter(resolved.key);
return true;
});
await applySimpleNonInteractiveApiKeyChoice({
authChoice: "gigachat-api-key",
nextConfig,
baseConfig: nextConfig,
opts: {} as never,
runtime: { error: vi.fn(), exit: vi.fn(), log: vi.fn() } as never,
apiKeyStorageOptions: undefined,
resolveApiKey,
maybeSetResolvedApiKey,
});
expect(resolveApiKey).toHaveBeenCalledWith(
expect.objectContaining({
provider: "gigachat",
flagName: "--gigachat-api-key",
envVar: "GIGACHAT_CREDENTIALS",
allowProfile: false,
}),
);
expect(maybeSetResolvedApiKey).toHaveBeenCalledOnce();
expect(setGigachatApiKey).toHaveBeenCalledWith(
"gigachat-oauth-credentials",
undefined,
undefined,
{
authMode: "oauth",
insecureTls: "false",
scope: "GIGACHAT_API_PERS",
},
);
});
});

View File

@ -29,6 +29,7 @@ async function applyGigachatNonInteractiveApiKeyChoice(params: {
flagName: `--${string}`;
envVar: string;
runtime: RuntimeEnv;
allowProfile?: boolean;
}) => Promise<ResolvedNonInteractiveApiKey | null>;
maybeSetResolvedApiKey: (
resolved: ResolvedNonInteractiveApiKey,
@ -42,6 +43,9 @@ async function applyGigachatNonInteractiveApiKeyChoice(params: {
flagName: "--gigachat-api-key",
envVar: "GIGACHAT_CREDENTIALS",
runtime: params.runtime,
// Personal OAuth onboarding must not silently reuse an existing Basic
// username:password profile and then rewrite the provider to OAuth config.
allowProfile: false,
});
if (!resolved) {
return null;
@ -80,6 +84,7 @@ export async function applySimpleNonInteractiveApiKeyChoice(params: {
flagName: `--${string}`;
envVar: string;
runtime: RuntimeEnv;
allowProfile?: boolean;
}) => Promise<ResolvedNonInteractiveApiKey | null>;
maybeSetResolvedApiKey: (
resolved: ResolvedNonInteractiveApiKey,