mirror of
https://github.com/google-gemini/gemini-cli
synced 2026-04-21 13:37:17 +00:00
Merge 52948495f5 into a38e2f0048
This commit is contained in:
commit
6b3617e665
2 changed files with 89 additions and 5 deletions
|
|
@ -347,7 +347,7 @@ describe('CodeAssistServer', () => {
|
|||
});
|
||||
|
||||
it('should construct the default URL correctly', () => {
|
||||
const server = new CodeAssistServer({} as never);
|
||||
const server = new CodeAssistServer({} as never, 'test-project');
|
||||
const url = server.getMethodUrl('testMethod');
|
||||
expect(url).toBe(
|
||||
'https://cloudcode-pa.googleapis.com/v1internal:testMethod',
|
||||
|
|
@ -356,26 +356,79 @@ describe('CodeAssistServer', () => {
|
|||
|
||||
it('should use the CODE_ASSIST_ENDPOINT environment variable if set', () => {
|
||||
process.env['CODE_ASSIST_ENDPOINT'] = 'https://custom-endpoint.com';
|
||||
const server = new CodeAssistServer({} as never);
|
||||
const server = new CodeAssistServer({} as never, 'test-project');
|
||||
const url = server.getMethodUrl('testMethod');
|
||||
expect(url).toBe('https://custom-endpoint.com/v1internal:testMethod');
|
||||
});
|
||||
|
||||
it('should use the CODE_ASSIST_API_VERSION environment variable if set', () => {
|
||||
process.env['CODE_ASSIST_API_VERSION'] = 'v2beta';
|
||||
const server = new CodeAssistServer({} as never);
|
||||
const server = new CodeAssistServer({} as never, 'test-project');
|
||||
const url = server.getMethodUrl('testMethod');
|
||||
expect(url).toBe('https://cloudcode-pa.googleapis.com/v2beta:testMethod');
|
||||
});
|
||||
|
||||
it('should use default value if CODE_ASSIST_API_VERSION env var is empty', () => {
|
||||
process.env['CODE_ASSIST_API_VERSION'] = '';
|
||||
const server = new CodeAssistServer({} as never);
|
||||
const server = new CodeAssistServer({} as never, 'test-project');
|
||||
const url = server.getMethodUrl('testMethod');
|
||||
expect(url).toBe(
|
||||
'https://cloudcode-pa.googleapis.com/v1internal:testMethod',
|
||||
);
|
||||
});
|
||||
|
||||
it('should use standard API endpoint when no projectId is provided', () => {
|
||||
const server = new CodeAssistServer({} as never);
|
||||
const url = server.getMethodUrl('testMethod');
|
||||
expect(url).toBe(
|
||||
'https://generativelanguage.googleapis.com/v1beta:testMethod',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadCodeAssist project hijacking prevention', () => {
|
||||
it('should strip cloudaicompanionProject from response when no projectId is set', async () => {
|
||||
const mockRequest = vi.fn();
|
||||
const client = { request: mockRequest } as unknown as OAuth2Client;
|
||||
const server = new CodeAssistServer(client, undefined, {}, undefined);
|
||||
|
||||
mockRequest.mockResolvedValue({
|
||||
data: {
|
||||
cloudaicompanionProject: 'ghost-project-id',
|
||||
currentTier: { id: 'standard-tier' },
|
||||
},
|
||||
});
|
||||
|
||||
const result = await server.loadCodeAssist({
|
||||
metadata: { ideType: 'IDE_UNSPECIFIED' },
|
||||
});
|
||||
|
||||
expect(result.cloudaicompanionProject).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should preserve cloudaicompanionProject when projectId is explicitly set', async () => {
|
||||
const mockRequest = vi.fn();
|
||||
const client = { request: mockRequest } as unknown as OAuth2Client;
|
||||
const server = new CodeAssistServer(
|
||||
client,
|
||||
'explicit-project',
|
||||
{},
|
||||
undefined,
|
||||
);
|
||||
|
||||
mockRequest.mockResolvedValue({
|
||||
data: {
|
||||
cloudaicompanionProject: 'server-project-id',
|
||||
currentTier: { id: 'standard-tier' },
|
||||
},
|
||||
});
|
||||
|
||||
const result = await server.loadCodeAssist({
|
||||
metadata: { ideType: 'IDE_UNSPECIFIED' },
|
||||
});
|
||||
|
||||
expect(result.cloudaicompanionProject).toBe('server-project-id');
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the generateContentStream endpoint and parse SSE', async () => {
|
||||
|
|
|
|||
|
|
@ -264,10 +264,29 @@ export class CodeAssistServer implements ContentGenerator {
|
|||
req: LoadCodeAssistRequest,
|
||||
): Promise<LoadCodeAssistResponse> {
|
||||
try {
|
||||
return await this.requestPost<LoadCodeAssistResponse>(
|
||||
const res = await this.requestPost<LoadCodeAssistResponse>(
|
||||
'loadCodeAssist',
|
||||
req,
|
||||
);
|
||||
|
||||
/**
|
||||
* FIX: Prevent automatic project hijacking for personal users.
|
||||
* For Google One AI Premium subscribers, the backend may return a
|
||||
* "shadow" project ID (e.g., master-impulse-jrkws) in
|
||||
* cloudaicompanionProject. If adopted, this forces the CLI to route
|
||||
* through the Enterprise endpoint (cloudcode-pa.googleapis.com),
|
||||
* which rejects personal OAuth tokens with 403 PERMISSION_DENIED.
|
||||
*
|
||||
* By stripping this field when no explicit projectId was provided,
|
||||
* we preserve the Personal/Standard flow routing.
|
||||
* See: https://github.com/google-gemini/gemini-cli/issues/25189
|
||||
* See: https://github.com/google-gemini/gemini-cli/issues/24517
|
||||
*/
|
||||
if (res.cloudaicompanionProject && !this.projectId) {
|
||||
delete res.cloudaicompanionProject;
|
||||
}
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
if (isVpcScAffectedUser(e)) {
|
||||
return {
|
||||
|
|
@ -508,6 +527,18 @@ export class CodeAssistServer implements ContentGenerator {
|
|||
}
|
||||
|
||||
private getBaseUrl(): string {
|
||||
/**
|
||||
* FIX: Endpoint fallback logic.
|
||||
* If no explicit projectId is provided via CLI flags or config, default
|
||||
* to the standard Generative Language API. This prevents accidental
|
||||
* routing to the Enterprise Cloud Code PA endpoint for personal users.
|
||||
* See: https://github.com/google-gemini/gemini-cli/issues/25189
|
||||
* See: https://github.com/google-gemini/gemini-cli/issues/24517
|
||||
*/
|
||||
if (!this.projectId) {
|
||||
return 'https://generativelanguage.googleapis.com/v1beta';
|
||||
}
|
||||
|
||||
const endpoint =
|
||||
process.env['CODE_ASSIST_ENDPOINT'] ?? CODE_ASSIST_ENDPOINT;
|
||||
const version =
|
||||
|
|
|
|||
Loading…
Reference in a new issue