track github repository names in telemetry events (#13670)

Co-authored-by: riddhi <duttariddhi@google.com>
This commit is contained in:
Riddhi Dutta
2025-12-03 10:56:12 +05:30
committed by GitHub
parent 035bea3699
commit 92e95ed806
3 changed files with 105 additions and 1 deletions

View File

@@ -427,6 +427,84 @@ describe('ClearcutLogger', () => {
});
});
describe('GITHUB_REPOSITORY metadata', () => {
it('includes hashed repository when GITHUB_REPOSITORY is set', () => {
vi.stubEnv('GITHUB_REPOSITORY', 'google/gemini-cli');
const { logger } = setup({});
const event = logger?.createLogEvent(EventNames.API_ERROR, []);
const repositoryMetadata = event?.event_metadata[0].find(
(item) =>
item.gemini_cli_key ===
EventMetadataKey.GEMINI_CLI_GH_REPOSITORY_NAME_HASH,
);
expect(repositoryMetadata).toBeDefined();
expect(repositoryMetadata?.value).toMatch(/^[a-f0-9]{64}$/);
expect(repositoryMetadata?.value).not.toBe('google/gemini-cli');
});
it('hashes repository name consistently', () => {
vi.stubEnv('GITHUB_REPOSITORY', 'google/gemini-cli');
const { logger } = setup({});
const event1 = logger?.createLogEvent(EventNames.API_ERROR, []);
const event2 = logger?.createLogEvent(EventNames.API_ERROR, []);
const hash1 = event1?.event_metadata[0].find(
(item) =>
item.gemini_cli_key ===
EventMetadataKey.GEMINI_CLI_GH_REPOSITORY_NAME_HASH,
)?.value;
const hash2 = event2?.event_metadata[0].find(
(item) =>
item.gemini_cli_key ===
EventMetadataKey.GEMINI_CLI_GH_REPOSITORY_NAME_HASH,
)?.value;
expect(hash1).toBeDefined();
expect(hash2).toBeDefined();
expect(hash1).toBe(hash2);
});
it('produces different hashes for different repositories', () => {
vi.stubEnv('GITHUB_REPOSITORY', 'google/gemini-cli');
const { logger: logger1 } = setup({});
const event1 = logger1?.createLogEvent(EventNames.API_ERROR, []);
const hash1 = event1?.event_metadata[0].find(
(item) =>
item.gemini_cli_key ===
EventMetadataKey.GEMINI_CLI_GH_REPOSITORY_NAME_HASH,
)?.value;
vi.stubEnv('GITHUB_REPOSITORY', 'google/other-repo');
ClearcutLogger.clearInstance();
const { logger: logger2 } = setup({});
const event2 = logger2?.createLogEvent(EventNames.API_ERROR, []);
const hash2 = event2?.event_metadata[0].find(
(item) =>
item.gemini_cli_key ===
EventMetadataKey.GEMINI_CLI_GH_REPOSITORY_NAME_HASH,
)?.value;
expect(hash1).toBeDefined();
expect(hash2).toBeDefined();
expect(hash1).not.toBe(hash2);
});
it('does not include repository when GITHUB_REPOSITORY is not set', () => {
vi.stubEnv('GITHUB_REPOSITORY', undefined);
const { logger } = setup({});
const event = logger?.createLogEvent(EventNames.API_ERROR, []);
const hasRepository = event?.event_metadata[0].some(
(item) =>
item.gemini_cli_key ===
EventMetadataKey.GEMINI_CLI_GH_REPOSITORY_NAME_HASH,
);
expect(hasRepository).toBe(false);
});
});
describe('logChatCompressionEvent', () => {
it('logs an event with proper fields', () => {
const { logger } = setup();

View File

@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { createHash } from 'node:crypto';
import { HttpsProxyAgent } from 'https-proxy-agent';
import type {
StartSessionEvent,
@@ -155,6 +156,13 @@ function determineGHWorkflowName(): string | undefined {
return process.env['GH_WORKFLOW_NAME'];
}
/**
* Determines the GitHub repository name if the CLI is running in a GitHub Actions environment.
*/
function determineGHRepositoryName(): string | undefined {
return process.env['GITHUB_REPOSITORY'];
}
/**
* Clearcut URL to send logging events to.
*/
@@ -186,6 +194,7 @@ export class ClearcutLogger {
private promptId: string = '';
private readonly installationManager: InstallationManager;
private readonly userAccountManager: UserAccountManager;
private readonly hashedGHRepositoryName?: string;
/**
* Queue of pending events that need to be flushed to the server. New events
@@ -215,6 +224,13 @@ export class ClearcutLogger {
this.promptId = config?.getSessionId() ?? '';
this.installationManager = new InstallationManager();
this.userAccountManager = new UserAccountManager();
const ghRepositoryName = determineGHRepositoryName();
if (ghRepositoryName) {
this.hashedGHRepositoryName = createHash('sha256')
.update(ghRepositoryName)
.digest('hex');
}
}
static getInstance(config?: Config): ClearcutLogger | undefined {
@@ -323,6 +339,13 @@ export class ClearcutLogger {
});
}
if (this.hashedGHRepositoryName) {
baseMetadata.push({
gemini_cli_key: EventMetadataKey.GEMINI_CLI_GH_REPOSITORY_NAME_HASH,
value: this.hashedGHRepositoryName,
});
}
const logEvent: LogEvent = {
console_type: 'GEMINI_CLI',
application: 102, // GEMINI_CLI

View File

@@ -7,7 +7,7 @@
// Defines valid event metadata keys for Clearcut logging.
export enum EventMetadataKey {
// Deleted enums: 24
// Next ID: 131
// Next ID: 133
GEMINI_CLI_KEY_UNKNOWN = 0,
@@ -197,6 +197,9 @@ export enum EventMetadataKey {
// Logs the active experiment IDs for the session.
GEMINI_CLI_EXPERIMENT_IDS = 131,
// Logs the repository name of the GitHub Action that triggered the session.
GEMINI_CLI_GH_REPOSITORY_NAME_HASH = 132,
// ==========================================================================
// Loop Detected Event Keys
// ===========================================================================