diff --git a/src/telemetry.ts b/src/telemetry.ts index dd4993c..bdf99cf 100644 --- a/src/telemetry.ts +++ b/src/telemetry.ts @@ -213,6 +213,7 @@ export function createTelemetry({ if ( config.enabled === false || isTelemetryDisabledByEnv(env) + || isRunningInCI(env) || !INSTALL_ID_PATTERN.test(config.installId) || !resolvedSink ) { @@ -332,6 +333,17 @@ function isTelemetryDisabledByEnv(env: Record): bool return value !== undefined && DISABLED_ENV_VALUES.has(value); } +function isRunningInCI(env: Record): boolean { + // Most CI providers set `CI=true` (GitHub Actions, CircleCI, GitLab, + // Travis, Buildkite, Jenkins via plugins, etc.). We also check the + // GitHub Actions-specific marker as belt-and-braces, in case some + // future provider drops the conventional `CI` variable. + return ( + env.CI?.trim().toLowerCase() === "true" + || env.GITHUB_ACTIONS?.trim().toLowerCase() === "true" + ); +} + function resolveConfiguredHost( env: Record, config: TelemetryConfig, diff --git a/test/telemetry.test.ts b/test/telemetry.test.ts index 2f4ce07..4977981 100644 --- a/test/telemetry.test.ts +++ b/test/telemetry.test.ts @@ -196,6 +196,73 @@ test("AGENTRAIL_TELEMETRY_DISABLED=1 wins over enabled config", async () => { assert.deepEqual(delivered, []); }); +test("CI=true suppresses telemetry even with enabled config", async () => { + const delivered: TelemetrySinkEvent[] = []; + const telemetry = createTelemetry({ + source: "cli", + version: "0.1.6", + config: { + enabled: true, + installId, + provider: "posthog", + host: DEFAULT_POSTHOG_HOST, + }, + env: { CI: "true" }, + sink: async (event) => { + delivered.push(event); + }, + }); + + await telemetry.capture("init_started", { provider: "github" }); + + assert.deepEqual(delivered, []); +}); + +test("GITHUB_ACTIONS=true suppresses telemetry even without CI variable", async () => { + const delivered: TelemetrySinkEvent[] = []; + const telemetry = createTelemetry({ + source: "cli", + version: "0.1.6", + config: { + enabled: true, + installId, + provider: "posthog", + host: DEFAULT_POSTHOG_HOST, + }, + env: { GITHUB_ACTIONS: "true" }, + sink: async (event) => { + delivered.push(event); + }, + }); + + await telemetry.capture("init_started", { provider: "github" }); + + assert.deepEqual(delivered, []); +}); + +test("CI=false does not suppress telemetry", async () => { + const delivered: TelemetrySinkEvent[] = []; + const telemetry = createTelemetry({ + source: "cli", + version: "0.1.6", + config: { + enabled: true, + installId, + provider: "posthog", + host: DEFAULT_POSTHOG_HOST, + }, + env: { CI: "false" }, + sink: async (event) => { + delivered.push(event); + }, + }); + + await telemetry.capture("init_started", { provider: "github" }); + + assert.equal(delivered.length, 1); + assert.equal(delivered[0].event, "init_started"); +}); + test("invalid install id telemetry sends nothing", async () => { const delivered: TelemetrySinkEvent[] = []; const telemetry = createTelemetry({