mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-24 03:54:43 -07:00
feat(telemetry): add keychain availability and token storage metrics (#18971)
This commit is contained in:
@@ -22,6 +22,20 @@ vi.mock('./keychain-token-storage.js', () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock('../../code_assist/oauth-credential-storage.js', () => ({
|
||||
OAuthCredentialStorage: {
|
||||
saveCredentials: vi.fn(),
|
||||
loadCredentials: vi.fn(),
|
||||
clearCredentials: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../../core/apiKeyCredentialStorage.js', () => ({
|
||||
loadApiKey: vi.fn(),
|
||||
saveApiKey: vi.fn(),
|
||||
clearApiKey: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('./file-token-storage.js', () => ({
|
||||
FileTokenStorage: vi.fn().mockImplementation(() => ({
|
||||
getCredentials: vi.fn(),
|
||||
|
||||
@@ -8,6 +8,8 @@ import { BaseTokenStorage } from './base-token-storage.js';
|
||||
import { FileTokenStorage } from './file-token-storage.js';
|
||||
import type { TokenStorage, OAuthCredentials } from './types.js';
|
||||
import { TokenStorageType } from './types.js';
|
||||
import { coreEvents } from '../../utils/events.js';
|
||||
import { TokenStorageInitializationEvent } from '../../telemetry/types.js';
|
||||
|
||||
const FORCE_FILE_STORAGE_ENV_VAR = 'GEMINI_FORCE_FILE_STORAGE';
|
||||
|
||||
@@ -34,6 +36,11 @@ export class HybridTokenStorage extends BaseTokenStorage {
|
||||
if (isAvailable) {
|
||||
this.storage = keychainStorage;
|
||||
this.storageType = TokenStorageType.KEYCHAIN;
|
||||
|
||||
coreEvents.emitTelemetryTokenStorageType(
|
||||
new TokenStorageInitializationEvent('keychain', forceFileStorage),
|
||||
);
|
||||
|
||||
return this.storage;
|
||||
}
|
||||
} catch (_e) {
|
||||
@@ -43,6 +50,11 @@ export class HybridTokenStorage extends BaseTokenStorage {
|
||||
|
||||
this.storage = new FileTokenStorage(this.serviceName);
|
||||
this.storageType = TokenStorageType.ENCRYPTED_FILE;
|
||||
|
||||
coreEvents.emitTelemetryTokenStorageType(
|
||||
new TokenStorageInitializationEvent('encrypted_file', forceFileStorage),
|
||||
);
|
||||
|
||||
return this.storage;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,15 +25,20 @@ vi.mock('keytar', () => ({
|
||||
default: mockKeytar,
|
||||
}));
|
||||
|
||||
vi.mock('node:crypto', () => ({
|
||||
randomBytes: vi.fn(() => ({
|
||||
toString: vi.fn(() => mockCryptoRandomBytesString),
|
||||
})),
|
||||
}));
|
||||
vi.mock('node:crypto', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('node:crypto')>();
|
||||
return {
|
||||
...actual,
|
||||
randomBytes: vi.fn(() => ({
|
||||
toString: vi.fn(() => mockCryptoRandomBytesString),
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../../utils/events.js', () => ({
|
||||
coreEvents: {
|
||||
emitFeedback: vi.fn(),
|
||||
emitTelemetryKeychainAvailability: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import * as crypto from 'node:crypto';
|
||||
import { BaseTokenStorage } from './base-token-storage.js';
|
||||
import type { OAuthCredentials, SecretStorage } from './types.js';
|
||||
import { coreEvents } from '../../utils/events.js';
|
||||
import { KeychainAvailabilityEvent } from '../../telemetry/types.js';
|
||||
|
||||
interface Keytar {
|
||||
getPassword(service: string, account: string): Promise<string | null>;
|
||||
@@ -263,9 +264,21 @@ export class KeychainTokenStorage
|
||||
|
||||
const success = deleted && retrieved === testPassword;
|
||||
this.keychainAvailable = success;
|
||||
|
||||
coreEvents.emitTelemetryKeychainAvailability(
|
||||
new KeychainAvailabilityEvent(success),
|
||||
);
|
||||
|
||||
return success;
|
||||
} catch (_error) {
|
||||
this.keychainAvailable = false;
|
||||
|
||||
// Do not log the raw error message to avoid potential PII leaks
|
||||
// (e.g. from OS-level error messages containing file paths)
|
||||
coreEvents.emitTelemetryKeychainAvailability(
|
||||
new KeychainAvailabilityEvent(false),
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user