build(deps): bump google-auth-library to 11.3.1 (#2387)

This commit is contained in:
JATMN
2026-10-24 06:22:19 -07:00
committed by GitHub
parent df184fbafc
commit 94e22e19d3
3 changed files with 176 additions and 8 deletions
+6 -6
View File
@@ -51,7 +51,7 @@
"figures": "6.1.0",
"fuse.js": "7.5.0",
"get-east-asian-width": "1.7.0",
"google-auth-library": "10.6.2",
"google-auth-library": "11.3.1",
"graphology": "0.26.0",
"graphology-metrics": "2.4.2",
"https-proxy-agent": "9.1.0",
@@ -105,7 +105,7 @@
},
},
"overrides": {
"google-auth-library": "10.6.2",
"google-auth-library": "11.3.1",
"ip-address": "10.2.0",
"lodash-es": "4.18.1",
"node-domexception": "file:vendor/node-domexception-shim",
@@ -819,9 +819,9 @@
"fuse.js": ["fuse.js@7.5.0", "", {}, "sha512-sQtrEfA+ez/3G0cCZecF70oqpCRttCexYUG4mUrtWL49ULUzUyxokt5kyqwtKzj1270RaKih+hcP3qLcumccow=="],
"gaxios": ["gaxios@7.1.5", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg=="],
"gaxios": ["gaxios@8.3.2", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-7VsaTExxjbDv2ZK1YuC4jbgfN33NI/6/7zdYWUHB6mcg51v4tCBZe+xzjqPzOpVzI+C5k1Kk9OQ80WVrXAHOqw=="],
"gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
"gcp-metadata": ["gcp-metadata@9.2.2", "", { "dependencies": { "gaxios": "^8.3.0", "google-logging-utils": "^2.0.0", "json-bigint": "^1.0.0" } }, "sha512-hlaHpCBoNCzoUjMnBZq0LbUiYqPAhXFaAgyNwQqwWU44TZIYJK3RD3o2wkNdvPs8nnUXqJjTudnodLJkLMBjow=="],
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
@@ -839,9 +839,9 @@
"globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"google-auth-library": ["google-auth-library@10.6.2", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw=="],
"google-auth-library": ["google-auth-library@11.3.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^8.3.0", "gcp-metadata": "^9.0.0", "google-logging-utils": "^2.0.0", "jws": "^4.0.0" } }, "sha512-mQS0R2Ev/DKkzuWSYtDeq15uhDeaWuT2qzLYqJ41LmooxVKHmn5ut3pc6dlHY6wfHW/D7FBmOYjAtkjaD1A7qA=="],
"google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="],
"google-logging-utils": ["google-logging-utils@2.1.0", "", {}, "sha512-1R6uiq6XhXW2ZrcGtZpGgVDsYGzSmveVOn8Pp37qe1fbThHZ34e3t3eXj5mVu6PFSVx9fvB1KNVnYgVtq/BRcA=="],
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
+2 -2
View File
@@ -131,7 +131,7 @@
"figures": "6.1.0",
"fuse.js": "7.5.0",
"get-east-asian-width": "1.7.0",
"google-auth-library": "10.6.2",
"google-auth-library": "11.3.1",
"graphology": "0.26.0",
"graphology-metrics": "2.4.2",
"https-proxy-agent": "9.1.0",
@@ -213,7 +213,7 @@
},
"overrides": {
"ip-address": "10.2.0",
"google-auth-library": "10.6.2",
"google-auth-library": "11.3.1",
"lodash-es": "4.18.1",
"node-domexception": "file:vendor/node-domexception-shim"
},
@@ -0,0 +1,168 @@
import { afterEach, beforeEach, expect, mock, spyOn, test } from 'bun:test'
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { GoogleAuth, UserRefreshClient } from 'google-auth-library'
import { snapshotEnv } from '../../test/envSnapshot.js'
import {
acquireSharedMutationLock,
releaseSharedMutationLock,
} from '../../test/sharedMutationLock.js'
import { checkGcpCredentialsValid } from '../../utils/auth.js'
import { resolveGeminiCredential } from '../../utils/geminiAuth.js'
import { getAnthropicClient } from './client.js'
const originalGetClient = GoogleAuth.prototype.getClient
const envKeys = [
'GOOGLE_APPLICATION_CREDENTIALS', 'GOOGLE_CLOUD_PROJECT', 'GCLOUD_PROJECT',
'GOOGLE_CLOUD_QUOTA_PROJECT', 'GOOGLE_PROJECT_ID',
'CLAUDE_CODE_USE_VERTEX', 'CLAUDE_CODE_SKIP_VERTEX_AUTH',
'ANTHROPIC_VERTEX_PROJECT_ID', 'ANTHROPIC_VERTEX_BASE_URL', 'CLOUD_ML_REGION',
'CLAUDE_CODE_USE_GEMINI', 'GEMINI_AUTH_MODE', 'GEMINI_API_KEY', 'GOOGLE_API_KEY',
'GEMINI_ACCESS_TOKEN', 'GEMINI_BASE_URL', 'GEMINI_MODEL',
'CLAUDE_CODE_USE_OPENAI', 'CLAUDE_CODE_USE_BEDROCK', 'CLAUDE_CODE_USE_FOUNDRY',
'CLAUDE_CODE_USE_GITHUB', 'CLAUDE_CODE_USE_MISTRAL', 'ANTHROPIC_CUSTOM_HEADERS',
] as const
let restoreEnv: () => void
let fixtureDir: string
let originalMacro: PropertyDescriptor | undefined
let authInstances: GoogleAuth[]
let tokenRequests: URLSearchParams[]
let apiHeaders: Headers | undefined
let apiUrl: string | undefined
const apiFetch = (async (input, init) => {
apiUrl = String(input)
apiHeaders = new Headers(init?.headers)
const vertex = process.env.CLAUDE_CODE_USE_VERTEX === '1'
return new Response(JSON.stringify(vertex ? {
id: 'msg_auth', type: 'message', role: 'assistant',
model: 'claude-sonnet-4-6', content: [{ type: 'text', text: 'ok' }],
stop_reason: 'end_turn', stop_sequence: null,
usage: { input_tokens: 1, output_tokens: 1 },
} : {
id: 'chatcmpl_auth', model: 'gemini-2.5-flash',
choices: [{ message: { role: 'assistant', content: 'ok' }, finish_reason: 'stop' }],
usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 },
}), { headers: { 'Content-Type': 'application/json' } })
}) as typeof fetch
beforeEach(async () => {
await acquireSharedMutationLock('services/api/googleAuth.integration.test.ts')
restoreEnv = snapshotEnv(envKeys, { clear: true })
originalMacro = Object.getOwnPropertyDescriptor(globalThis, 'MACRO')
;(globalThis as Record<string, unknown>).MACRO = { VERSION: 'test-version' }
fixtureDir = mkdtempSync(join(tmpdir(), 'openclaude-google-auth-'))
const credentialsPath = join(fixtureDir, 'adc.json')
writeFileSync(credentialsPath, JSON.stringify({
type: 'authorized_user',
client_id: 'fixture-client',
client_secret: 'fixture-secret',
refresh_token: 'fixture-refresh',
quota_project_id: 'fixture-quota',
}))
process.env.GOOGLE_APPLICATION_CREDENTIALS = credentialsPath
process.env.GOOGLE_CLOUD_PROJECT = 'fixture-project'
authInstances = []
tokenRequests = []
apiHeaders = undefined
apiUrl = undefined
// Keep the production constructor, ADC file loading, getClient, and token/header
// methods real. Replace only the HTTP transport of the resulting auth client.
spyOn(GoogleAuth.prototype, 'getClient').mockImplementation(async function (this: GoogleAuth) {
const client = await originalGetClient.call(this)
expect(client).toBeInstanceOf(UserRefreshClient)
authInstances.push(this)
client.transporter.defaults.fetchImplementation = async (url, init) => {
expect(String(url)).toBe('https://oauth2.googleapis.com/token')
expect(init?.method).toBe('POST')
tokenRequests.push(new URLSearchParams(String(init?.body)))
return new Response(JSON.stringify({
access_token: 'fixture-access-token', token_type: 'Bearer', expires_in: 3600,
}), { headers: { 'Content-Type': 'application/json' } })
}
return client
})
})
afterEach(() => {
try {
mock.restore()
restoreEnv()
if (originalMacro) {
Object.defineProperty(globalThis, 'MACRO', originalMacro)
} else {
delete (globalThis as Record<string, unknown>).MACRO
}
rmSync(fixtureDir, { recursive: true, force: true })
} finally {
releaseSharedMutationLock()
}
})
function expectRealAuthFlow(): void {
expect(authInstances).toHaveLength(1)
expect(tokenRequests).toHaveLength(1)
expect(Object.fromEntries(tokenRequests[0]!)).toEqual({
client_id: 'fixture-client',
client_secret: 'fixture-secret',
refresh_token: 'fixture-refresh',
grant_type: 'refresh_token',
})
}
test('Vertex loads ADC and forwards real Google auth Headers to rawPredict', async () => {
process.env.CLAUDE_CODE_USE_VERTEX = '1'
process.env.CLOUD_ML_REGION = 'us-east5'
process.env.ANTHROPIC_VERTEX_PROJECT_ID = 'fixture-target'
const client = await getAnthropicClient({
maxRetries: 0, model: 'claude-sonnet-4-6', fetchOverride: apiFetch,
})
await client.messages.create({
model: 'claude-sonnet-4-6', max_tokens: 16,
messages: [{ role: 'user', content: 'hello' }],
})
expectRealAuthFlow()
expect(apiUrl).toContain('/projects/fixture-target/locations/us-east5/')
expect(apiUrl).toEndWith(':rawPredict')
expect(apiHeaders?.get('authorization')).toBe('Bearer fixture-access-token')
expect(apiHeaders?.get('x-goog-user-project')).toBe('fixture-quota')
})
test('Gemini loads ADC and normalizes the real getAccessToken result for requests', async () => {
// The OpenAI shim uses the shared fetch transport rather than fetchOverride.
spyOn(globalThis, 'fetch').mockImplementation(apiFetch)
process.env.CLAUDE_CODE_USE_GEMINI = '1'
process.env.GEMINI_AUTH_MODE = 'adc'
process.env.GEMINI_MODEL = 'gemini-2.5-flash'
process.env.GEMINI_BASE_URL = 'https://generativelanguage.googleapis.com/v1beta/openai'
const client = await getAnthropicClient({
maxRetries: 0, model: 'gemini-2.5-flash', fetchOverride: apiFetch,
})
await client.messages.create({
model: 'gemini-2.5-flash', max_tokens: 16,
messages: [{ role: 'user', content: 'hello' }],
})
expectRealAuthFlow()
expect(apiUrl).toBe('https://generativelanguage.googleapis.com/v1beta/openai/chat/completions')
expect(apiHeaders?.get('authorization')).toBe('Bearer fixture-access-token')
expect(apiHeaders?.get('x-goog-user-project')).toBe('fixture-project')
})
test('Vertex credential validation loads ADC and retrieves a real access token', async () => {
await expect(checkGcpCredentialsValid()).resolves.toBe(true)
expectRealAuthFlow()
})
test('Vertex validation and Gemini ADC reject malformed credential files', async () => {
writeFileSync(process.env.GOOGLE_APPLICATION_CREDENTIALS!, '{invalid json')
process.env.GEMINI_AUTH_MODE = 'adc'
await expect(checkGcpCredentialsValid()).resolves.toBe(false)
await expect(resolveGeminiCredential()).resolves.toEqual({ kind: 'none' })
expect(tokenRequests).toHaveLength(0)
})