From eb53c827c611c3e9a55bf027ed90b4b59be4beaf Mon Sep 17 00:00:00 2001 From: mesalogo Date: Sun, 27 Sep 2026 13:57:26 +0800 Subject: [PATCH] fix: apply runtime telemetry settings to web and remote clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DS Web and remote Agent launch paths omitted shared telemetry opt-out settings. Reuse one environment definition for local launches, remote runtime profiles, and the remote model bridge helper while preserving existing update controls and user-requested networking. Validation: 16 focused tests passed at commit time. Prior local real-model validation passed; modified Agent real-Host validation and background network monitoring remain outstanding. Release note: 补齐 DS Web 与远程 Runtime 启动时的遥测关闭配置,保留现有自动更新关闭设置,不影响模型、MCP 和用户主动联网请求。 --- .../deepseek-harness/technical-design.md | 2 +- src/agent-daemon/model-bridge-helper.ts | 3 +++ .../opencode-runtime-profile.test.ts | 5 +++++ src/agent-daemon/opencode-runtime-profile.ts | 2 ++ src/main/agent/native-dsh-web-client.ts | 4 ++-- src/main/agent/process-environment.ts | 17 +++-------------- src/shared/runtime-privacy-environment.ts | 14 ++++++++++++++ 7 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 src/shared/runtime-privacy-environment.ts diff --git a/docs/features/deepseek-harness/technical-design.md b/docs/features/deepseek-harness/technical-design.md index 231462b1..1645c8cd 100644 --- a/docs/features/deepseek-harness/technical-design.md +++ b/docs/features/deepseek-harness/technical-design.md @@ -418,7 +418,7 @@ Main 的 Web/MCP ToolProvider 按工作区保存,最后一个对应 Session - 使用环境变量白名单构造 utilityProcess 环境。 - 不继承 `NODE_OPTIONS`、调试端口、任意 npm 配置、用户 `DSH_*` 覆盖或白名单之外的凭据。 -- `DSH_TELEMETRY_DISABLED=1` 必须固定设置。 +- `DSH_TELEMETRY_DISABLED=1` 必须固定设置。后台 Host 与独立 Web 启动器均叠加 `src/shared/runtime-privacy-environment.ts` 的通用遥测关闭配置,设置 `DO_NOT_TRACK=1`、`OTEL_SDK_DISABLED=true`,并关闭日志、指标和追踪 exporter。模型、MCP 和用户主动联网请求不受此配置限制。 - Harness Home 指向 GoodBuddy 管理的隔离目录。 - 不调用官方 `loadEnv` 或 `loadLayeredEnv`。 - API Key 由 Main 从加密设置中解析。 diff --git a/src/agent-daemon/model-bridge-helper.ts b/src/agent-daemon/model-bridge-helper.ts index 2fc8f43e..adfed84b 100644 --- a/src/agent-daemon/model-bridge-helper.ts +++ b/src/agent-daemon/model-bridge-helper.ts @@ -1,3 +1,4 @@ +import { runtimePrivacyEnvironment } from '../shared/runtime-privacy-environment' import { randomBytes, randomUUID } from 'node:crypto' import { spawn as nodeSpawn } from 'node:child_process' import { mkdtemp, writeFile, rm } from 'node:fs/promises' @@ -931,7 +932,9 @@ function credentialFreeHelperEnvironment( 'XDG_STATE_HOME' ] as const const environment: NodeJS.ProcessEnv = { + ...runtimePrivacyEnvironment, OPENCODE_CONFIG_CONTENT: config, + OPENCODE_ENABLE_QUESTION_TOOL: 'true' } for (const name of allowed) { diff --git a/src/agent-daemon/opencode-runtime-profile.test.ts b/src/agent-daemon/opencode-runtime-profile.test.ts index 971006dc..524f5900 100644 --- a/src/agent-daemon/opencode-runtime-profile.test.ts +++ b/src/agent-daemon/opencode-runtime-profile.test.ts @@ -60,6 +60,11 @@ describe('OpenCode direct launch profile', () => { workMode }) const config = JSON.parse(profile.env.OPENCODE_CONFIG_CONTENT!) + expect(profile.env).toMatchObject({ + DO_NOT_TRACK: '1', OTEL_SDK_DISABLED: 'true', + OTEL_LOGS_EXPORTER: 'none', OTEL_METRICS_EXPORTER: 'none', OTEL_TRACES_EXPORTER: 'none', + OPENCODE_DISABLE_AUTOUPDATE: '1', OPENCODE_DISABLE_MODELS_FETCH: '1' + }) expect(config.snapshot).toBe(false) expect(config.permission).toBe(workMode === 'ask' ? 'ask' : 'allow') } diff --git a/src/agent-daemon/opencode-runtime-profile.ts b/src/agent-daemon/opencode-runtime-profile.ts index 0f89ac00..b843b3b5 100644 --- a/src/agent-daemon/opencode-runtime-profile.ts +++ b/src/agent-daemon/opencode-runtime-profile.ts @@ -1,3 +1,4 @@ +import { runtimePrivacyEnvironment } from "../shared/runtime-privacy-environment"; import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path"; import { OPENCODE_REMOTE_RUNTIME_ENVIRONMENT_NAMES, @@ -148,6 +149,7 @@ export function createOpenCodeLaunchProfile(input: { const environmentBase = { ...executeEnvironment(process.env, workspaceDirectory), + ...runtimePrivacyEnvironment, ...(isContinue ? {} : { ...OPEN_CODE_RUNTIME_ENVIRONMENT, OPENCODE_CONFIG_DIR: join(bundleDirectory, "config", "opencode") }), }; diff --git a/src/main/agent/native-dsh-web-client.ts b/src/main/agent/native-dsh-web-client.ts index f1727364..13176ca6 100644 --- a/src/main/agent/native-dsh-web-client.ts +++ b/src/main/agent/native-dsh-web-client.ts @@ -10,7 +10,7 @@ import { canonicalJson } from '../../shared/agent-protocol/canonical' import type { ResolvedModelProfile } from '../runtime-settings-store' import { createManagedModelBridge } from '../remote-agent/managed-model-bridge' import { terminateProcessTreeAndWait } from './child-process-termination' -import { buildCredentialFilteredUserEnvironment } from './process-environment' +import { buildCredentialFilteredUserEnvironment, runtimePrivacyEnvironment } from './process-environment' import { nativeDshMcpToolName, nativeDshWebPatch, nativeDshWebPolicySource, type NativeDshMcpServer } from './native-dsh-web-policy' export type { NativeDshMcpServer } from './native-dsh-web-policy' @@ -177,7 +177,7 @@ export class NativeDshWebClientService { instance.child = spawn(launch.nodeExecutablePath, [cli, 'web', '--no-open', '--host', '127.0.0.1', '--port', '0'], { cwd: request.workspace, shell: false, windowsHide: true, detached: process.platform !== 'win32', stdio: ['ignore', 'pipe', 'pipe'], - env: { ...environment, DSH_HOME: instance.home, DSH_TELEMETRY_DISABLED: '1', + env: { ...environment, ...runtimePrivacyEnvironment, DSH_HOME: instance.home, DSH_TELEMETRY_DISABLED: '1', DSH_PERMISSION_MODE: 'danger-full-access', GOODBUDDY_DSH_MODEL_KEY: MODEL_BRIDGE_SDK_AUTH_SENTINEL } }) const child = instance.child diff --git a/src/main/agent/process-environment.ts b/src/main/agent/process-environment.ts index be41b550..3ef98b31 100644 --- a/src/main/agent/process-environment.ts +++ b/src/main/agent/process-environment.ts @@ -1,3 +1,6 @@ +import { runtimePrivacyEnvironment } from '../../shared/runtime-privacy-environment' +export { runtimePrivacyEnvironment } from '../../shared/runtime-privacy-environment' + import type { LaunchEnvironmentProvider } from '../local-tool-environment/launch-environment-provider' export const runtimeProviderEnvironmentNames = [ @@ -112,20 +115,6 @@ export type RuntimeProfileCredential = { value: string } -export const runtimePrivacyEnvironment: NodeJS.ProcessEnv = { - DO_NOT_TRACK: '1', - OTEL_EXPORTER_OTLP_ENDPOINT: '', - OTEL_EXPORTER_OTLP_HEADERS: '', - OTEL_EXPORTER_OTLP_LOGS_ENDPOINT: '', - OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: '', - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '', - OTEL_LOGS_EXPORTER: 'none', - OTEL_LOG_USER_PROMPTS: '0', - OTEL_METRICS_EXPORTER: 'none', - OTEL_SDK_DISABLED: 'true', - OTEL_TRACES_EXPORTER: 'none' -} - export function buildRuntimeEnvironment( overrides: NodeJS.ProcessEnv, source: NodeJS.ProcessEnv = process.env diff --git a/src/shared/runtime-privacy-environment.ts b/src/shared/runtime-privacy-environment.ts new file mode 100644 index 00000000..a24dc25e --- /dev/null +++ b/src/shared/runtime-privacy-environment.ts @@ -0,0 +1,14 @@ +/** Disable optional Runtime telemetry without restricting user-requested networking. */ +export const runtimePrivacyEnvironment: Readonly = Object.freeze({ + DO_NOT_TRACK: '1', + OTEL_EXPORTER_OTLP_ENDPOINT: '', + OTEL_EXPORTER_OTLP_HEADERS: '', + OTEL_EXPORTER_OTLP_LOGS_ENDPOINT: '', + OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: '', + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '', + OTEL_LOGS_EXPORTER: 'none', + OTEL_LOG_USER_PROMPTS: '0', + OTEL_METRICS_EXPORTER: 'none', + OTEL_SDK_DISABLED: 'true', + OTEL_TRACES_EXPORTER: 'none' +})