From 3c530d8a9876943dd633152b71995d173264d216 Mon Sep 17 00:00:00 2001 From: kapelame Date: Wed, 5 Aug 2026 20:55:11 +0800 Subject: [PATCH] fix: isolate CLI provider credentials --- gitnexus/src/cli/wiki.ts | 17 ++++++++++- gitnexus/src/core/wiki/llm-client.ts | 10 ++++--- gitnexus/test/unit/wiki-llm-client.test.ts | 34 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/gitnexus/src/cli/wiki.ts b/gitnexus/src/cli/wiki.ts index 04f5fdde8..955ff11a0 100644 --- a/gitnexus/src/cli/wiki.ts +++ b/gitnexus/src/cli/wiki.ts @@ -224,6 +224,13 @@ const wikiCommandImpl = async (inputPath?: string, options?: WikiCommandOptions) if (options.apiVersion) updates.apiVersion = options.apiVersion; if (options.reasoningModel !== undefined) updates.isReasoningModel = options.reasoningModel; const providerChanged = !!options.provider && options.provider !== existing.provider; + if (providerChanged) { + updates.apiKey = undefined; + updates.baseUrl = undefined; + updates.model = undefined; + updates.apiVersion = undefined; + updates.isReasoningModel = undefined; + } if (options.provider === 'minimax') { if (providerChanged && options.reasoningModel === undefined) { updates.isReasoningModel = undefined; @@ -488,7 +495,15 @@ const wikiCommandImpl = async (inputPath?: string, options?: WikiCommandOptions) } // Save - await saveCLIConfig({ apiKey: key, baseUrl, model, provider }); + await saveCLIConfig({ + ...savedConfig, + apiKey: key, + baseUrl, + model, + provider, + apiVersion: undefined, + isReasoningModel: undefined, + }); console.log(' Config saved to ~/.gitnexus/config.json\n'); llmConfig = { ...llmConfig, apiKey: key, baseUrl, model, provider }; diff --git a/gitnexus/src/core/wiki/llm-client.ts b/gitnexus/src/core/wiki/llm-client.ts index acc16a13b..9e5988550 100644 --- a/gitnexus/src/core/wiki/llm-client.ts +++ b/gitnexus/src/core/wiki/llm-client.ts @@ -122,9 +122,9 @@ export async function resolveLLMConfig(overrides?: Partial): Promise< const apiKey = overrides?.apiKey || (savedProvider === 'minimax' ? process.env.MINIMAX_API_KEY : undefined) || - process.env.GITNEXUS_API_KEY || - process.env.OPENAI_API_KEY || - savedConfig.apiKey || + (savedProvider !== 'minimax' ? process.env.GITNEXUS_API_KEY : undefined) || + (savedProvider !== 'minimax' ? process.env.OPENAI_API_KEY : undefined) || + (reuseSavedHttpConfig ? savedConfig.apiKey : undefined) || ''; return { @@ -148,7 +148,9 @@ export async function resolveLLMConfig(overrides?: Partial): Promise< temperature: overrides?.temperature ?? 0, provider: savedProvider, apiVersion: - overrides?.apiVersion || process.env.GITNEXUS_AZURE_API_VERSION || savedConfig.apiVersion, + overrides?.apiVersion || + (savedProvider === 'azure' ? process.env.GITNEXUS_AZURE_API_VERSION : undefined) || + (reuseSavedHttpConfig ? savedConfig.apiVersion : undefined), isReasoningModel: overrides?.isReasoningModel ?? (reuseSavedHttpConfig ? savedConfig.isReasoningModel : undefined), diff --git a/gitnexus/test/unit/wiki-llm-client.test.ts b/gitnexus/test/unit/wiki-llm-client.test.ts index 63764e64b..2a20c7591 100644 --- a/gitnexus/test/unit/wiki-llm-client.test.ts +++ b/gitnexus/test/unit/wiki-llm-client.test.ts @@ -96,6 +96,40 @@ describe('buildRequestUrl', () => { }); }); +describe('resolveLLMConfig provider isolation', () => { + afterEach(() => { + vi.unstubAllEnvs(); + vi.restoreAllMocks(); + }); + + it('does not use OpenAI environment credentials for the default MiniMax provider', async () => { + vi.stubEnv('OPENAI_API_KEY', 'openai-key'); + vi.stubEnv('GITNEXUS_API_KEY', 'gitnexus-key'); + vi.stubEnv('MINIMAX_API_KEY', ''); + + const config = await resolveLLMConfig(); + + expect(config.provider).toBe('minimax'); + expect(config.apiKey).toBe(''); + }); + + it('does not reuse saved credentials or API versions after switching providers', async () => { + vi.spyOn(await import('../../src/storage/repo-manager.js'), 'loadCLIConfig').mockResolvedValue({ + provider: 'minimax', + apiKey: 'minimax-key', + baseUrl: MINIMAX_OPENAI_BASE_URLS.global_en, + model: MINIMAX_MODEL_IDS[0], + apiVersion: 'minimax-version', + }); + + const config = await resolveLLMConfig({ provider: 'openai' }); + + expect(config.apiKey).toBe(''); + expect(config.apiVersion).toBeUndefined(); + expect(config.baseUrl).toBe('https://openrouter.ai/api/v1'); + }); +}); + describe('callLLM — auth header', () => { afterEach(() => vi.unstubAllGlobals());