diff --git a/extensions/cli/src/telemetry/posthogService.test.ts b/extensions/cli/src/telemetry/posthogService.test.ts index 7fd95204da..6e60de95e3 100644 --- a/extensions/cli/src/telemetry/posthogService.test.ts +++ b/extensions/cli/src/telemetry/posthogService.test.ts @@ -152,5 +152,38 @@ describe("PosthogService", () => { expect(client).toBeUndefined(); expect(dns.lookup).toHaveBeenCalledTimes(1); }); + + it("returns false when DNS resolves to 0.0.0.0 (blocked)", async () => { + const dns: any = (await import("dns/promises")).default; + dns.lookup.mockResolvedValueOnce({ + address: "0.0.0.0", + family: 4, + } as any); + const result = await (service as any).hasInternetConnection(); + expect(result).toBe(false); + expect(dns.lookup).toHaveBeenCalledTimes(1); + }); + + it("returns false when DNS resolves to localhost", async () => { + const dns: any = (await import("dns/promises")).default; + dns.lookup.mockResolvedValueOnce({ + address: "127.0.0.1", + family: 4, + } as any); + const result = await (service as any).hasInternetConnection(); + expect(result).toBe(false); + expect(dns.lookup).toHaveBeenCalledTimes(1); + }); + + it("returns true when DNS resolves to valid address", async () => { + const dns: any = (await import("dns/promises")).default; + dns.lookup.mockResolvedValueOnce({ + address: "1.1.1.1", + family: 4, + } as any); + const result = await (service as any).hasInternetConnection(); + expect(result).toBe(true); + expect(dns.lookup).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/extensions/cli/src/telemetry/posthogService.ts b/extensions/cli/src/telemetry/posthogService.ts index acbec0855f..04c76aff32 100644 --- a/extensions/cli/src/telemetry/posthogService.ts +++ b/extensions/cli/src/telemetry/posthogService.ts @@ -5,6 +5,7 @@ import node_machine_id from "node-machine-id"; import type { PostHog as PostHogType } from "posthog-node"; import { isAuthenticatedConfig, loadAuthConfig } from "../auth/workos.js"; +import { loggers } from "../logging.js"; import { isHeadlessMode, isServe } from "../util/cli.js"; import { isGitHubActions } from "../util/git.js"; import { logger } from "../util/logger.js"; @@ -13,6 +14,7 @@ import { getVersion } from "../version.js"; export class PosthogService { private os: string | undefined; private uniqueId: string; + private _telemetryBlocked: boolean = false; constructor() { this.os = os.platform(); @@ -23,10 +25,20 @@ export class PosthogService { private async hasInternetConnection() { const refetchConnection = async () => { try { - await dns.lookup("app.posthog.com"); - this._hasInternetConnection = true; + const result = await dns.lookup("app.posthog.com"); + // Check that the resolved address is not 0.0.0.0 or other invalid addresses + const isValidAddress = + result.address !== "0.0.0.0" && !result.address.startsWith("127."); + this._hasInternetConnection = isValidAddress; + this._telemetryBlocked = !isValidAddress; + if (!isValidAddress) { + logger.debug( + "DNS lookup returned invalid address for PostHog, skipping telemetry", + ); + } } catch { this._hasInternetConnection = false; + this._telemetryBlocked = false; } }; @@ -40,6 +52,14 @@ export class PosthogService { } get isEnabled() { + // Check for the unified telemetry control first + if (process.env.CONTINUE_TELEMETRY_ENABLED === "0") { + return false; + } + if (process.env.CONTINUE_TELEMETRY_ENABLED === "1") { + return true; + } + // Fall back to the legacy variable for backward compatibility return process.env.CONTINUE_ALLOW_ANONYMOUS_TELEMETRY !== "0"; } @@ -47,7 +67,13 @@ export class PosthogService { private async getClient() { if (!(await this.hasInternetConnection())) { this._client = undefined; - logger.warn("No internet connection, skipping telemetry"); + if (this._telemetryBlocked && this.isEnabled) { + loggers.warning( + "Telemetry appears to be blocked by your network. To disable telemetry entirely, set CONTINUE_TELEMETRY_ENABLED=0", + ); + } else if (this.isEnabled) { + logger.warn("No internet connection, skipping telemetry"); + } } else if (this.isEnabled) { if (!this._client) { const { PostHog } = await import("posthog-node"); diff --git a/extensions/cli/src/telemetry/telemetryService.ts b/extensions/cli/src/telemetry/telemetryService.ts index 910c82f59e..561ba4bd4b 100644 --- a/extensions/cli/src/telemetry/telemetryService.ts +++ b/extensions/cli/src/telemetry/telemetryService.ts @@ -71,8 +71,19 @@ class TelemetryService { process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT || process.env.OTEL_METRICS_EXPORTER ); - const enabled = - process.env.CONTINUE_CLI_ENABLE_TELEMETRY !== "0" && hasOtelConfig; + + // Check for unified telemetry control first + let telemetryEnabled = true; // default to enabled if OTEL config exists + if (process.env.CONTINUE_TELEMETRY_ENABLED === "0") { + telemetryEnabled = false; + } else if (process.env.CONTINUE_TELEMETRY_ENABLED === "1") { + telemetryEnabled = true; + } else { + // Fall back to legacy variable for backward compatibility + telemetryEnabled = process.env.CONTINUE_CLI_ENABLE_TELEMETRY !== "0"; + } + + const enabled = telemetryEnabled && hasOtelConfig; const sessionId = uuidv4(); return {