fix(gemini-vertex): wire flag into env-file allowlist, test scrubs and truthiness

Addresses maintainer review on PR #1614:

- envFile.ts: add CLAUDE_CODE_USE_GEMINI_VERTEX plus GEMINI_VERTEX_* /
  GOOGLE_APPLICATION_CREDENTIALS / GCLOUD_PROJECT / GOOGLE_PROJECT_ID to
  ALLOWED_ENV_FILE_KEYS so --provider-env-file .env no longer silently
  rejects the documented Vertex setup. Adds a PROVIDER_SELECTION_FLAGS-derived
  parity test plus a full Vertex .env load test.
- Add CLAUDE_CODE_USE_GEMINI_VERTEX to the provider env scrub/restore lists in
  betas, conversationRecovery, model, withRetry and promptCacheBreakDetection
  tests to prevent cross-test flag leakage.
- providerFlag.applyModelFlagFromArgs and StartupScreen.detectProvider: use
  isEnvTruthy for all provider flags instead of literal '1'/'true' checks,
  removing the Vertex-only inconsistency.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gitdevine
2026-06-26 11:37:41 +02:00
co-authored by Claude Opus 4.8
parent 1ac5ab6171
commit 5e975fff48
9 changed files with 79 additions and 16 deletions
+5
View File
@@ -21,6 +21,7 @@ type SettingsModule = typeof import('../../utils/settings/settings.js')
const originalEnv = {
CLAUDE_CODE_USE_OPENAI: process.env.CLAUDE_CODE_USE_OPENAI,
CLAUDE_CODE_USE_GEMINI: process.env.CLAUDE_CODE_USE_GEMINI,
CLAUDE_CODE_USE_GEMINI_VERTEX: process.env.CLAUDE_CODE_USE_GEMINI_VERTEX,
CLAUDE_CODE_USE_GITHUB: process.env.CLAUDE_CODE_USE_GITHUB,
CLAUDE_CODE_USE_MISTRAL: process.env.CLAUDE_CODE_USE_MISTRAL,
CLAUDE_CODE_USE_BEDROCK: process.env.CLAUDE_CODE_USE_BEDROCK,
@@ -202,6 +203,10 @@ afterEach(() => {
settingsForTest = {}
restoreEnv('CLAUDE_CODE_USE_OPENAI', originalEnv.CLAUDE_CODE_USE_OPENAI)
restoreEnv('CLAUDE_CODE_USE_GEMINI', originalEnv.CLAUDE_CODE_USE_GEMINI)
restoreEnv(
'CLAUDE_CODE_USE_GEMINI_VERTEX',
originalEnv.CLAUDE_CODE_USE_GEMINI_VERTEX,
)
restoreEnv('CLAUDE_CODE_USE_GITHUB', originalEnv.CLAUDE_CODE_USE_GITHUB)
restoreEnv('CLAUDE_CODE_USE_MISTRAL', originalEnv.CLAUDE_CODE_USE_MISTRAL)
restoreEnv('CLAUDE_CODE_USE_BEDROCK', originalEnv.CLAUDE_CODE_USE_BEDROCK)
+4 -4
View File
@@ -85,10 +85,10 @@ const LOGO_CLAUDE = [
export function detectProvider(modelOverride?: string): { name: string; model: string; baseUrl: string; isLocal: boolean } {
const useGeminiVertex = isEnvTruthy(process.env.CLAUDE_CODE_USE_GEMINI_VERTEX)
const useGemini = process.env.CLAUDE_CODE_USE_GEMINI === '1' || process.env.CLAUDE_CODE_USE_GEMINI === 'true'
const useGithub = process.env.CLAUDE_CODE_USE_GITHUB === '1' || process.env.CLAUDE_CODE_USE_GITHUB === 'true'
const useOpenAI = process.env.CLAUDE_CODE_USE_OPENAI === '1' || process.env.CLAUDE_CODE_USE_OPENAI === 'true'
const useMistral = process.env.CLAUDE_CODE_USE_MISTRAL === '1' || process.env.CLAUDE_CODE_USE_MISTRAL === 'true'
const useGemini = isEnvTruthy(process.env.CLAUDE_CODE_USE_GEMINI)
const useGithub = isEnvTruthy(process.env.CLAUDE_CODE_USE_GITHUB)
const useOpenAI = isEnvTruthy(process.env.CLAUDE_CODE_USE_OPENAI)
const useMistral = isEnvTruthy(process.env.CLAUDE_CODE_USE_MISTRAL)
if (useGeminiVertex) {
// Use the shared resolvers so this display matches the runtime/provider
@@ -50,6 +50,7 @@ const PROVIDER_ENV_KEYS = [
'CLAUDE_CODE_USE_OPENAI',
'CLAUDE_CODE_USE_GITHUB',
'CLAUDE_CODE_USE_GEMINI',
'CLAUDE_CODE_USE_GEMINI_VERTEX',
'CLAUDE_CODE_USE_MISTRAL',
'CLAUDE_CODE_USE_BEDROCK',
'CLAUDE_CODE_USE_VERTEX',
+1
View File
@@ -22,6 +22,7 @@ let originalProvidersModule: ProvidersModule | undefined
const envKeys = [
'CLAUDE_CODE_USE_OPENAI',
'CLAUDE_CODE_USE_GEMINI',
'CLAUDE_CODE_USE_GEMINI_VERTEX',
'CLAUDE_CODE_USE_GITHUB',
'CLAUDE_CODE_USE_BEDROCK',
'CLAUDE_CODE_USE_VERTEX',
+1
View File
@@ -22,6 +22,7 @@ import { setSdkBetas } from '../bootstrap/state.js'
const PROVIDER_ENV_KEYS = [
'CLAUDE_CODE_USE_OPENAI',
'CLAUDE_CODE_USE_GEMINI',
'CLAUDE_CODE_USE_GEMINI_VERTEX',
'CLAUDE_CODE_USE_MISTRAL',
'CLAUDE_CODE_USE_GITHUB',
'CLAUDE_CODE_USE_BEDROCK',
+1
View File
@@ -17,6 +17,7 @@ const tempDirs: string[] = []
const originalSimple = process.env.CLAUDE_CODE_SIMPLE
const providerEnvKeys = [
'CLAUDE_CODE_USE_GEMINI',
'CLAUDE_CODE_USE_GEMINI_VERTEX',
'CLAUDE_CODE_USE_MISTRAL',
'CLAUDE_CODE_USE_GITHUB',
'CLAUDE_CODE_USE_BEDROCK',
+54
View File
@@ -11,6 +11,7 @@ import {
reapplyRememberedEnvFileValues,
rememberLoadedEnvFileValues,
} from './envFile.js'
import { PROVIDER_SELECTION_FLAGS } from './providerSelectionFlags.js'
const TEST_ENV_KEYS = [
'NODE_OPTIONS',
@@ -21,6 +22,16 @@ const TEST_ENV_KEYS = [
'OPENAI_API_KEY',
'OPENAI_BASE_URL',
'OPENAI_MODEL',
...PROVIDER_SELECTION_FLAGS,
'GEMINI_ACCESS_TOKEN',
'GEMINI_VERTEX_PROJECT',
'GEMINI_VERTEX_LOCATION',
'GEMINI_VERTEX_MODEL',
'GEMINI_VERTEX_AUTH_MODE',
'GOOGLE_APPLICATION_CREDENTIALS',
'GOOGLE_CLOUD_PROJECT',
'GCLOUD_PROJECT',
'GOOGLE_PROJECT_ID',
'WEB_AUTH_HEADER',
'WEB_AUTH_SCHEME',
'WEB_BODY_TEMPLATE',
@@ -335,6 +346,49 @@ describe('loadEnvFile', () => {
expect(process.env.CODEX_AUTH_JSON_PATH).toBe('/tmp/codex-auth.json')
})
it('accepts every registered provider-selection flag', () => {
// Guards against a new CLAUDE_CODE_USE_* flag (like Gemini Vertex) being
// added to PROVIDER_SELECTION_FLAGS but silently rejected by the env-file
// allowlist, which would break --provider-env-file end-to-end wiring.
const filePath = writeTempEnvFile(
PROVIDER_SELECTION_FLAGS.map(flag => `${flag}=1`).join('\n'),
)
const loaded = loadEnvFile(filePath)
for (const flag of PROVIDER_SELECTION_FLAGS) {
expect(loaded[flag]).toBe('1')
expect(process.env[flag]).toBe('1')
}
})
it('loads the documented Gemini Vertex provider setup', () => {
const filePath = writeTempEnvFile([
'CLAUDE_CODE_USE_GEMINI_VERTEX=1',
'GEMINI_VERTEX_PROJECT=my-project',
'GEMINI_VERTEX_LOCATION=us-central1',
'GEMINI_VERTEX_MODEL=gemini-2.0-flash',
'GEMINI_VERTEX_AUTH_MODE=adc',
'GOOGLE_APPLICATION_CREDENTIALS=/tmp/sa.json',
'GCLOUD_PROJECT=my-project',
'GOOGLE_PROJECT_ID=my-project',
].join('\n'))
const loaded = loadEnvFile(filePath)
expect(loaded).toEqual({
CLAUDE_CODE_USE_GEMINI_VERTEX: '1',
GEMINI_VERTEX_PROJECT: 'my-project',
GEMINI_VERTEX_LOCATION: 'us-central1',
GEMINI_VERTEX_MODEL: 'gemini-2.0-flash',
GEMINI_VERTEX_AUTH_MODE: 'adc',
GOOGLE_APPLICATION_CREDENTIALS: '/tmp/sa.json',
GCLOUD_PROJECT: 'my-project',
GOOGLE_PROJECT_ID: 'my-project',
})
expect(process.env.CLAUDE_CODE_USE_GEMINI_VERTEX).toBe('1')
})
it('rejects unsupported variables before mutating process environment', () => {
const filePath = writeTempEnvFile([
'OPENAI_MODEL=from-file',
+8
View File
@@ -37,6 +37,7 @@ const ALLOWED_ENV_FILE_KEYS = new Set([
'CLAUDE_CODE_USE_BEDROCK',
'CLAUDE_CODE_USE_FOUNDRY',
'CLAUDE_CODE_USE_GEMINI',
'CLAUDE_CODE_USE_GEMINI_VERTEX',
'CLAUDE_CODE_USE_GITHUB',
'CLAUDE_CODE_USE_MISTRAL',
'CLAUDE_CODE_USE_OPENAI',
@@ -53,11 +54,16 @@ const ALLOWED_ENV_FILE_KEYS = new Set([
'FIRECRAWL_API_KEY',
'FIRECRAWL_API_URL',
'FIREWORKS_API_KEY',
'GCLOUD_PROJECT',
'GEMINI_ACCESS_TOKEN',
'GEMINI_API_KEY',
'GEMINI_AUTH_MODE',
'GEMINI_BASE_URL',
'GEMINI_MODEL',
'GEMINI_VERTEX_AUTH_MODE',
'GEMINI_VERTEX_LOCATION',
'GEMINI_VERTEX_MODEL',
'GEMINI_VERTEX_PROJECT',
'GH_TOKEN',
'GITHUB_COPILOT_ALLOW_SUBAGENTS',
'GITHUB_COPILOT_FORCE_SYNC_SUBAGENTS',
@@ -65,8 +71,10 @@ const ALLOWED_ENV_FILE_KEYS = new Set([
'GITHUB_COPILOT_OPTIMIZATION_DISABLED',
'GITHUB_TOKEN',
'GOOGLE_API_KEY',
'GOOGLE_APPLICATION_CREDENTIALS',
'GOOGLE_CLOUD_PROJECT',
'GOOGLE_CSE_ID',
'GOOGLE_PROJECT_ID',
'GROQ_API_KEY',
'HICAP_API_KEY',
'JINA_API_KEY',
+4 -12
View File
@@ -225,18 +225,10 @@ export function applyModelFlagFromArgs(args: string[]): void {
if (!model) return
const useGeminiVertex = isEnvTruthy(process.env.CLAUDE_CODE_USE_GEMINI_VERTEX)
const useGemini =
process.env.CLAUDE_CODE_USE_GEMINI === '1' ||
process.env.CLAUDE_CODE_USE_GEMINI === 'true'
const useMistral =
process.env.CLAUDE_CODE_USE_MISTRAL === '1' ||
process.env.CLAUDE_CODE_USE_MISTRAL === 'true'
const useOpenAI =
process.env.CLAUDE_CODE_USE_OPENAI === '1' ||
process.env.CLAUDE_CODE_USE_OPENAI === 'true'
const useGithub =
process.env.CLAUDE_CODE_USE_GITHUB === '1' ||
process.env.CLAUDE_CODE_USE_GITHUB === 'true'
const useGemini = isEnvTruthy(process.env.CLAUDE_CODE_USE_GEMINI)
const useMistral = isEnvTruthy(process.env.CLAUDE_CODE_USE_MISTRAL)
const useOpenAI = isEnvTruthy(process.env.CLAUDE_CODE_USE_OPENAI)
const useGithub = isEnvTruthy(process.env.CLAUDE_CODE_USE_GITHUB)
if (useGeminiVertex) {
process.env.GEMINI_VERTEX_MODEL = model