From d42f974d4eb73045eb74d5699e26c420d0432bcb Mon Sep 17 00:00:00 2001 From: Ryder Sun Date: Sat, 7 Nov 2026 20:16:54 +0800 Subject: [PATCH] Avoid Gemini readiness without a selected auth mode Treat stale OAuth files and unrelated API keys as unverified when the native noninteractive CLI has no selected authentication. Checks: 108 Gemini readiness tests; desktop packaging; git diff --check. --- desktop/src/agents/local-agent-readiness.cjs | 2 +- desktop/test/agents/cli/gemini-native-config.test.cjs | 4 ++++ desktop/test/agents/local-agent-readiness.test.cjs | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/desktop/src/agents/local-agent-readiness.cjs b/desktop/src/agents/local-agent-readiness.cjs index dd1c513..4f38b33 100644 --- a/desktop/src/agents/local-agent-readiness.cjs +++ b/desktop/src/agents/local-agent-readiness.cjs @@ -817,7 +817,7 @@ function nativeCredentialState(kind, options = {}) { return found ? { state: 'ready', source: options.credentialSource === 'native-shell' ? 'native-shell' : 'native-credential' } : { state: 'unknown', source: 'unverified' } } - if (selection.authType) return { state: 'unknown', source: 'unverified' } + return { state: 'unknown', source: 'unverified' } } const expandHome = value => String(value).replace(/^~(?=$|[\\/])/, home) const piHome = env.PI_CODING_AGENT_DIR ? expandHome(env.PI_CODING_AGENT_DIR) : path.join(home, '.pi', 'agent') diff --git a/desktop/test/agents/cli/gemini-native-config.test.cjs b/desktop/test/agents/cli/gemini-native-config.test.cjs index 2a3163b..2625d6f 100644 --- a/desktop/test/agents/cli/gemini-native-config.test.cjs +++ b/desktop/test/agents/cli/gemini-native-config.test.cjs @@ -34,7 +34,11 @@ test('Gemini readiness checks credentials for its selected auth mode', t => { t.after(() => fs.rmSync(home, { recursive: true, force: true })) const root = path.join(home, '.gemini') fs.mkdirSync(root) + fs.writeFileSync(path.join(root, 'oauth_creds.json'), JSON.stringify({ refresh_token: 'oauth-token' })) + const noSelection = { GEMINI_CLI_SYSTEM_SETTINGS_PATH: path.join(home, 'system.json'), GOOGLE_API_KEY: 'unrelated' } + assert.deepEqual(nativeCredentialState('gemini', { home, env: noSelection }), { state: 'unknown', source: 'unverified' }) const env = { GEMINI_CLI_SYSTEM_SETTINGS_PATH: path.join(home, 'system.json'), GEMINI_CLI_AUTH_OVERRIDE: 'oauth-personal', GEMINI_API_KEY: 'unrelated' } + fs.unlinkSync(path.join(root, 'oauth_creds.json')) assert.deepEqual(nativeCredentialState('gemini', { home, env }), { state: 'unknown', source: 'unverified' }) fs.writeFileSync(path.join(root, 'oauth_creds.json'), JSON.stringify({ refresh_token: 'oauth-token' })) assert.deepEqual(nativeCredentialState('gemini', { home, env }), { state: 'ready', source: 'native-credential' }) diff --git a/desktop/test/agents/local-agent-readiness.test.cjs b/desktop/test/agents/local-agent-readiness.test.cjs index a1ca07e..01bd7e0 100644 --- a/desktop/test/agents/local-agent-readiness.test.cjs +++ b/desktop/test/agents/local-agent-readiness.test.cjs @@ -220,6 +220,7 @@ test('Gemini uses its shell-selected native home for readiness and execution', a assert.deepEqual(native, { GEMINI_CLI_HOME: selected }) assert.equal(nativeCredentialState('gemini', { home, env: native }).state, 'unknown') fs.writeFileSync(path.join(selectedConfig, 'oauth_creds.json'), JSON.stringify({ refresh_token: 'selected-secret' })) + fs.writeFileSync(path.join(selectedConfig, 'settings.json'), JSON.stringify({ security: { auth: { selectedType: 'oauth-personal' } } })) assert.equal(nativeCredentialState('gemini', { home, env: native }).state, 'ready') assert.equal(childEnvironment({ kind: 'gemini' }, home, { env: native }, 'darwin').GEMINI_CLI_HOME, selected) assert.deepEqual(nativeCredentialEnvironment('codex', captured.env), {}) @@ -1319,6 +1320,9 @@ test('native readiness recognizes credential files for every supported CLI', () fs.mkdirSync(path.dirname(filename), { recursive: true }) fs.writeFileSync(filename, JSON.stringify(value)) } + fs.writeFileSync(path.join(home, '.gemini', 'settings.json'), JSON.stringify({ + security: { auth: { selectedType: 'oauth-personal' } }, + })) for (const [kind] of fixtures) { assert.deepEqual(nativeCredentialState(kind, { home, env: {} }), { state: 'ready', source: 'native-credential',