diff --git a/e2e/local/cli-telemetry-optout.test.ts b/e2e/local/cli-telemetry-optout.test.ts new file mode 100644 index 000000000..441d735f5 --- /dev/null +++ b/e2e/local/cli-telemetry-optout.test.ts @@ -0,0 +1,27 @@ +import { expect, it } from "@effect/vitest"; +import { Effect } from "effect"; + +import { makeCliSurface } from "../src/surfaces/cli"; + +it.live("terminal E2E sessions force product telemetry off", () => + makeCliSurface() + .session( + [ + process.execPath, + "-e", + "console.log([process.env.DO_NOT_TRACK, process.env.EXECUTOR_DISABLE_ANALYTICS, process.env.EXECUTOR_DISABLE_INTEGRATIONS_FETCH].join('|'))", + ], + (terminal) => + terminal.screen + .waitUntil((screen) => screen.text.includes("1|1|1"), { timeoutMs: 5_000 }) + .then((screen) => expect(screen.text).toContain("1|1|1")), + { + env: { + DO_NOT_TRACK: "0", + EXECUTOR_DISABLE_ANALYTICS: "0", + EXECUTOR_DISABLE_INTEGRATIONS_FETCH: "0", + }, + }, + ) + .pipe(Effect.timeout("10 seconds")), +); diff --git a/e2e/src/surfaces/cli.ts b/e2e/src/surfaces/cli.ts index ac7161883..85c0a9325 100644 --- a/e2e/src/surfaces/cli.ts +++ b/e2e/src/surfaces/cli.ts @@ -32,6 +32,15 @@ interface AsciicastEvent { bytes?: number[]; } +// E2E subprocesses must never report product usage or fetch the production +// integrations catalog. Keep these after caller-provided values below so a +// scenario cannot accidentally turn outbound telemetry back on. +const E2E_OUTBOUND_OPT_OUT = { + DO_NOT_TRACK: "1", + EXECUTOR_DISABLE_ANALYTICS: "1", + EXECUTOR_DISABLE_INTEGRATIONS_FETCH: "1", +} as const; + /** terminal-control's JSONL recording → asciicast v2 (what asciinema plays). */ const toAsciicast = (recording: Uint8Array): string => { const events = new TextDecoder() @@ -74,7 +83,7 @@ export const makeCliSurface = (): CliSurface => ({ const session: Session = await tc.launch({ command, cwd: options?.cwd, - env: options?.env, + env: { ...options?.env, ...E2E_OUTBOUND_OPT_OUT }, record: options?.record ? true : undefined, viewport: options?.viewport, });