diff --git a/extensions/cli/src/telemetry/posthogService.test.ts b/extensions/cli/src/telemetry/posthogService.test.ts index 7fd95204da9..6e60de95e31 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 1c2c663045f..48363fbd748 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 | undefined; + private _telemetryBlocked: boolean = false; constructor() { // Initialization is now lazy to avoid issues with mocking in tests @@ -36,15 +38,24 @@ 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"); + 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; } }; if (typeof this._hasInternetConnection !== "undefined") { - void refetchConnection(); // check in background if connection became available + void refetchConnection(); return this._hasInternetConnection; } @@ -53,6 +64,12 @@ export class PosthogService { } get isEnabled() { + if (process.env.CONTINUE_TELEMETRY_ENABLED === "0") { + return false; + } + if (process.env.CONTINUE_TELEMETRY_ENABLED === "1") { + return true; + } return process.env.CONTINUE_ALLOW_ANONYMOUS_TELEMETRY !== "0"; } @@ -60,7 +77,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 910c82f59ed..5804a24bc4a 100644 --- a/extensions/cli/src/telemetry/telemetryService.ts +++ b/extensions/cli/src/telemetry/telemetryService.ts @@ -71,8 +71,17 @@ class TelemetryService { process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT || process.env.OTEL_METRICS_EXPORTER ); - const enabled = - process.env.CONTINUE_CLI_ENABLE_TELEMETRY !== "0" && hasOtelConfig; + + let telemetryEnabled = true; + if (process.env.CONTINUE_METRICS_ENABLED === "0") { + telemetryEnabled = false; + } else if (process.env.CONTINUE_METRICS_ENABLED === "1") { + telemetryEnabled = true; + } else { + telemetryEnabled = process.env.CONTINUE_CLI_ENABLE_TELEMETRY !== "0"; + } + + const enabled = telemetryEnabled && hasOtelConfig; const sessionId = uuidv4(); return {