mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
fix(cli): prioritize configured auth over env vars in non-interactive mode (#10935)
This commit is contained in:
@@ -80,11 +80,9 @@ describe('JSON output', () => {
|
|||||||
expect(payload.error.type).toBe('Error');
|
expect(payload.error.type).toBe('Error');
|
||||||
expect(payload.error.code).toBe(1);
|
expect(payload.error.code).toBe(1);
|
||||||
expect(payload.error.message).toContain(
|
expect(payload.error.message).toContain(
|
||||||
'configured auth type is gemini-api-key',
|
"enforced authentication type is 'gemini-api-key'",
|
||||||
);
|
|
||||||
expect(payload.error.message).toContain(
|
|
||||||
'current auth type is oauth-personal',
|
|
||||||
);
|
);
|
||||||
|
expect(payload.error.message).toContain("current type is 'oauth-personal'");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not exit on tool errors and allow model to self-correct in JSON mode', async () => {
|
it('should not exit on tool errors and allow model to self-correct in JSON mode', async () => {
|
||||||
|
|||||||
@@ -209,19 +209,18 @@ describe('validateNonInterActiveAuth', () => {
|
|||||||
expect(refreshAuthMock).toHaveBeenCalledWith(AuthType.USE_GEMINI);
|
expect(refreshAuthMock).toHaveBeenCalledWith(AuthType.USE_GEMINI);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses configuredAuthType if provided', async () => {
|
it('uses configuredAuthType over environment variables', async () => {
|
||||||
// Set required env var for USE_GEMINI
|
|
||||||
process.env['GEMINI_API_KEY'] = 'fake-key';
|
process.env['GEMINI_API_KEY'] = 'fake-key';
|
||||||
const nonInteractiveConfig = {
|
const nonInteractiveConfig = {
|
||||||
refreshAuth: refreshAuthMock,
|
refreshAuth: refreshAuthMock,
|
||||||
};
|
};
|
||||||
await validateNonInteractiveAuth(
|
await validateNonInteractiveAuth(
|
||||||
AuthType.USE_GEMINI,
|
AuthType.LOGIN_WITH_GOOGLE,
|
||||||
undefined,
|
undefined,
|
||||||
nonInteractiveConfig,
|
nonInteractiveConfig,
|
||||||
mockSettings,
|
mockSettings,
|
||||||
);
|
);
|
||||||
expect(refreshAuthMock).toHaveBeenCalledWith(AuthType.USE_GEMINI);
|
expect(refreshAuthMock).toHaveBeenCalledWith(AuthType.LOGIN_WITH_GOOGLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exits if validateAuthMethod returns error', async () => {
|
it('exits if validateAuthMethod returns error', async () => {
|
||||||
@@ -274,16 +273,14 @@ describe('validateNonInterActiveAuth', () => {
|
|||||||
expect(refreshAuthMock).toHaveBeenCalledWith('invalid-auth-type');
|
expect(refreshAuthMock).toHaveBeenCalledWith('invalid-auth-type');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses enforcedAuthType if provided', async () => {
|
it('succeeds if effectiveAuthType matches enforcedAuthType', async () => {
|
||||||
mockSettings.merged.security.auth.enforcedType = AuthType.USE_GEMINI;
|
mockSettings.merged.security.auth.enforcedType = AuthType.USE_GEMINI;
|
||||||
mockSettings.merged.security.auth.selectedType = AuthType.USE_GEMINI;
|
|
||||||
// Set required env var for USE_GEMINI to ensure enforcedAuthType takes precedence
|
|
||||||
process.env['GEMINI_API_KEY'] = 'fake-key';
|
process.env['GEMINI_API_KEY'] = 'fake-key';
|
||||||
const nonInteractiveConfig = {
|
const nonInteractiveConfig = {
|
||||||
refreshAuth: refreshAuthMock,
|
refreshAuth: refreshAuthMock,
|
||||||
};
|
};
|
||||||
await validateNonInteractiveAuth(
|
await validateNonInteractiveAuth(
|
||||||
AuthType.USE_GEMINI,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
nonInteractiveConfig,
|
nonInteractiveConfig,
|
||||||
mockSettings,
|
mockSettings,
|
||||||
@@ -291,15 +288,11 @@ describe('validateNonInterActiveAuth', () => {
|
|||||||
expect(refreshAuthMock).toHaveBeenCalledWith(AuthType.USE_GEMINI);
|
expect(refreshAuthMock).toHaveBeenCalledWith(AuthType.USE_GEMINI);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exits if currentAuthType does not match enforcedAuthType', async () => {
|
it('exits if configuredAuthType does not match enforcedAuthType', async () => {
|
||||||
mockSettings.merged.security.auth.enforcedType = AuthType.LOGIN_WITH_GOOGLE;
|
mockSettings.merged.security.auth.enforcedType = AuthType.LOGIN_WITH_GOOGLE;
|
||||||
process.env['GOOGLE_GENAI_USE_VERTEXAI'] = 'true';
|
|
||||||
const nonInteractiveConfig = {
|
const nonInteractiveConfig = {
|
||||||
refreshAuth: refreshAuthMock,
|
refreshAuth: refreshAuthMock,
|
||||||
getOutputFormat: vi.fn().mockReturnValue(OutputFormat.TEXT),
|
getOutputFormat: vi.fn().mockReturnValue(OutputFormat.TEXT),
|
||||||
getContentGeneratorConfig: vi
|
|
||||||
.fn()
|
|
||||||
.mockReturnValue({ authType: undefined }),
|
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await validateNonInteractiveAuth(
|
await validateNonInteractiveAuth(
|
||||||
@@ -313,7 +306,31 @@ describe('validateNonInterActiveAuth', () => {
|
|||||||
expect((e as Error).message).toContain('process.exit(1) called');
|
expect((e as Error).message).toContain('process.exit(1) called');
|
||||||
}
|
}
|
||||||
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||||
'The configured auth type is oauth-personal, but the current auth type is vertex-ai. Please re-authenticate with the correct type.',
|
"The enforced authentication type is 'oauth-personal', but the current type is 'gemini-api-key'. Please re-authenticate with the correct type.",
|
||||||
|
);
|
||||||
|
expect(processExitSpy).toHaveBeenCalledWith(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('exits if auth from env var does not match enforcedAuthType', async () => {
|
||||||
|
mockSettings.merged.security.auth.enforcedType = AuthType.LOGIN_WITH_GOOGLE;
|
||||||
|
process.env['GEMINI_API_KEY'] = 'fake-key';
|
||||||
|
const nonInteractiveConfig = {
|
||||||
|
refreshAuth: refreshAuthMock,
|
||||||
|
getOutputFormat: vi.fn().mockReturnValue(OutputFormat.TEXT),
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
await validateNonInteractiveAuth(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
nonInteractiveConfig,
|
||||||
|
mockSettings,
|
||||||
|
);
|
||||||
|
expect.fail('Should have exited');
|
||||||
|
} catch (e) {
|
||||||
|
expect((e as Error).message).toContain('process.exit(1) called');
|
||||||
|
}
|
||||||
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||||
|
"The enforced authentication type is 'oauth-personal', but the current type is 'gemini-api-key'. Please re-authenticate with the correct type.",
|
||||||
);
|
);
|
||||||
expect(processExitSpy).toHaveBeenCalledWith(1);
|
expect(processExitSpy).toHaveBeenCalledWith(1);
|
||||||
});
|
});
|
||||||
@@ -352,8 +369,6 @@ describe('validateNonInterActiveAuth', () => {
|
|||||||
|
|
||||||
it('prints JSON error when enforced auth mismatches current auth and exits with code 1', async () => {
|
it('prints JSON error when enforced auth mismatches current auth and exits with code 1', async () => {
|
||||||
mockSettings.merged.security.auth.enforcedType = AuthType.USE_GEMINI;
|
mockSettings.merged.security.auth.enforcedType = AuthType.USE_GEMINI;
|
||||||
process.env['GOOGLE_GENAI_USE_GCA'] = 'true';
|
|
||||||
|
|
||||||
const nonInteractiveConfig = {
|
const nonInteractiveConfig = {
|
||||||
refreshAuth: refreshAuthMock,
|
refreshAuth: refreshAuthMock,
|
||||||
getOutputFormat: vi.fn().mockReturnValue(OutputFormat.JSON),
|
getOutputFormat: vi.fn().mockReturnValue(OutputFormat.JSON),
|
||||||
@@ -365,7 +380,7 @@ describe('validateNonInterActiveAuth', () => {
|
|||||||
let thrown: Error | undefined;
|
let thrown: Error | undefined;
|
||||||
try {
|
try {
|
||||||
await validateNonInteractiveAuth(
|
await validateNonInteractiveAuth(
|
||||||
undefined,
|
AuthType.LOGIN_WITH_GOOGLE,
|
||||||
undefined,
|
undefined,
|
||||||
nonInteractiveConfig as unknown as Config,
|
nonInteractiveConfig as unknown as Config,
|
||||||
mockSettings,
|
mockSettings,
|
||||||
@@ -381,7 +396,7 @@ describe('validateNonInterActiveAuth', () => {
|
|||||||
expect(payload.error.type).toBe('Error');
|
expect(payload.error.type).toBe('Error');
|
||||||
expect(payload.error.code).toBe(1);
|
expect(payload.error.code).toBe(1);
|
||||||
expect(payload.error.message).toContain(
|
expect(payload.error.message).toContain(
|
||||||
'The configured auth type is gemini-api-key, but the current auth type is oauth-personal.',
|
"The enforced authentication type is 'gemini-api-key', but the current type is 'oauth-personal'. Please re-authenticate with the correct type.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -31,17 +31,15 @@ export async function validateNonInteractiveAuth(
|
|||||||
settings: LoadedSettings,
|
settings: LoadedSettings,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const enforcedType = settings.merged.security?.auth?.enforcedType;
|
const effectiveAuthType = configuredAuthType || getAuthTypeFromEnv();
|
||||||
if (enforcedType) {
|
|
||||||
const currentAuthType = getAuthTypeFromEnv();
|
|
||||||
if (currentAuthType !== enforcedType) {
|
|
||||||
const message = `The configured auth type is ${enforcedType}, but the current auth type is ${currentAuthType}. Please re-authenticate with the correct type.`;
|
|
||||||
throw new Error(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const effectiveAuthType =
|
const enforcedType = settings.merged.security?.auth?.enforcedType;
|
||||||
enforcedType || getAuthTypeFromEnv() || configuredAuthType;
|
if (enforcedType && effectiveAuthType !== enforcedType) {
|
||||||
|
const message = effectiveAuthType
|
||||||
|
? `The enforced authentication type is '${enforcedType}', but the current type is '${effectiveAuthType}'. Please re-authenticate with the correct type.`
|
||||||
|
: `The auth type '${enforcedType}' is enforced, but no authentication is configured.`;
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
if (!effectiveAuthType) {
|
if (!effectiveAuthType) {
|
||||||
const message = `Please set an Auth method in your ${USER_SETTINGS_PATH} or specify one of the following environment variables before running: GEMINI_API_KEY, GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_GENAI_USE_GCA`;
|
const message = `Please set an Auth method in your ${USER_SETTINGS_PATH} or specify one of the following environment variables before running: GEMINI_API_KEY, GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_GENAI_USE_GCA`;
|
||||||
|
|||||||
Reference in New Issue
Block a user