agent-joule/PRIVACY_HARDENING.md
David Charlot cf65c49ea4 Step 4 follow-up: purge auto_update_helper from Windows packaging
Completes the auto-update removal (Wave 2) on the packaging side. The crates were
already deleted; this removes the now-dangling references that would have broken a
Windows installer build.

- script/bundle-windows.ps1: no longer builds (--package auto_update_helper),
  copies (.exe/.pdb), signs, or moves auto_update_helper; dropped the now-unused
  $innoDir\tools directory creation.
- crates/zed/resources/windows/zed.iss: removed 'Source: ...\tools\*' (would have
  failed Inno compile with an empty source dir) and the {app}\tools + {app}\updates
  [UninstallDelete] entries (auto-update installer artifacts).
- .github/CODEOWNERS.hold: removed ownership lines for the deleted auto_update*
  crates (parked file; cosmetic).

Not buildable on this macOS dev box (no Inno Setup/Windows); changes are mechanical
removals of references to the deleted binary, verified no dangling refs remain.
PRIVACY_HARDENING.md updated to reflect the packaging cleanup.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-02 11:03:26 -04:00

5.7 KiB

agent-zed — Privacy Hardening

agent-zed is a private, no-phone-home fork of Zed. It drives vendors' own logged-in agent CLIs (Claude Code, Gemini) over ACP plus a local vLLM backend. It must never establish a Zed identity, send telemetry, upload crashes, check for updates, or make any unprompted network call to Zed-operated (or Zed-adjacent) infrastructure.

This document records what was removed/neutralized and how it was verified.

Threat model / goal

  • No automatic sign-in; no Zed account is ever established.
  • No telemetry, analytics, or usage events leave the machine.
  • No crash/minidump upload.
  • No auto-update or contact with release servers.
  • No unprompted startup fetches to Zed-operated endpoints.
  • Expected, allowed traffic: the federated agent processes the user explicitly drives (e.g. npx ACP agents) and the local vLLM backend on localhost. These are the vendor's processes, not agent-zed phoning home.

Changes

A — Sign-in removed

  • crates/zed/src/main.rs: authenticate() is a no-op — no automatic sign-in/connect at startup, so no Zed identity is established (this was the real phone-home).
  • crates/title_bar: removed the Sign In button + now-unused bindings.
  • crates/onboarding: removed the Zed-cloud "Zed Agent" promo + SignIn action. The dangling onboarding::SignIn keybindings were also removed from the three default keymaps (a removed action left bound = startup keymap-validation panic).
  • The client crate stays compiled but signed-out; collab/CRDT is retained for later self-hosting against a non-Zed server.

B — Auto-update removed entirely

Updates are a wholesale uninstall + reinstall; there is no in-app updater.

  • Deleted the auto_update, auto_update_ui, and auto_update_helper crates and all usages (menus, title-bar affordance, activity indicator, init).
  • This closed a residual egress that the earlier poll-neuter missed: auto_update still contained live calls to Zed release servers (download_remote_server_release / get_release_asset), reachable via "Check for Updates" and the SSH remote-server download path.
  • remote_connection: remote-server auto-download is stubbed to a clear "disabled in agent-zed" error instead of silently fetching from Zed.
  • Windows packaging was updated to match: script/bundle-windows.ps1 no longer builds/copies/signs auto_update_helper, and zed.iss drops the {app}\tools and {app}\updates directories (auto-update installer artifacts).

C — Telemetry neutralized

  • crates/client/src/telemetry.rs: send_event() is a no-op, so every telemetry::event! call site across the tree is inert with a single edit. Nothing is queued, recorded, or sent.

D — Crash upload disabled

  • MINIDUMP_ENDPOINT is forced to None (ignores build/runtime env), so the upload paths in reliability.rs are unreachable. Local minidump capture is unaffected. (Runtime log confirms: "Minidump endpoint not set".)
  • RefreshLlmTokenListener is inert (no sign-in event to trigger a Zed cloud token refresh).

E — ACP agent-registry auto-fetch disabled

The federation feature auto-fetched the ACP agent registry from cdn.agentclientprotocol.com at startup (registry index + icons). This is not Zed telemetry, but it is an unprompted launch-time request to Zed-adjacent infrastructure — exactly the egress this build avoids.

  • crates/project/src/agent_registry_store.rs: removed the startup auto-refresh in init_global, and made refresh_if_stale() a no-op (this was the path that actually fired, via agent-settings load and registry-agent connect).
  • The registry still loads from the on-disk cache, and the explicit, user-initiated refresh() (e.g. opening the Agent Registry page) still works. Only the automatic, staleness-driven fetch is gone.

F — Egress backstop

Belt-and-suspenders: even if some code path survived the removals above, it cannot reach a Zed host.

  • crates/http_client/src/http_client.rs: the four Zed-host URL builders (build_zed_api_url, build_zed_cloud_url, build_zed_cloud_url_with_query, build_zed_llm_url) now bail! instead of returning a URL. Any surviving caller fails loudly rather than contacting api.zed.dev / cloud.zed.dev / llm.zed.dev.

Extensions

  • assets/settings/default.json: auto_install_extensions is empty by default (was {"html": true}), so the extension registry/CDN is not contacted at startup. Users opt in to extensions explicitly.

Verification

Method: launch the built agent-zed against a fresh --user-data-dir, then observe outbound connections with lsof -nP -i -p <pid> and capture TLS SNI hostnames with tshark -i en0 -Y 'tls.handshake.type == 1' (Wireshark's ChmodBPF grants capture access without sudo). IP-based inference is unreliable here because Zed and the ACP CDN both sit behind Cloudflare anycast; SNI is authoritative.

Findings across the hardening passes:

  • Zero connections to *.zed.dev (Zed's own infra) at any point.
  • The one persistent startup egress observed (~36 connections) was conclusively identified by SNI as cdn.agentclientprotocol.com — the ACP registry fetch, fixed in E above.
  • After E: agent-zed makes zero outbound connections at idle startup (0 established across repeated samples; no cdn.agentclientprotocol.com, no *.zed.dev in the SNI capture). Startup is network-silent.

Re-run the check after any change touching networking:

cargo build --bin agent-zed
tshark -i en0 -f 'tcp port 443' -Y 'tls.handshake.type == 1' \
  -T fields -e tls.handshake.extensions_server_name -a duration:26 | sort | uniq -c &
./target/debug/agent-zed --user-data-dir /tmp/azed-check .
# expect: no agent-zed connections to *.zed.dev or *.agentclientprotocol.com