Harden GA telemetry disclosure

This commit is contained in:
rcourtman
2026-07-02 11:50:03 +01:00
parent c63533790c
commit 6c9b4f8e8d
37 changed files with 217 additions and 87 deletions
+1 -1
View File
@@ -461,7 +461,7 @@ Use this only in trusted environments.
## Privacy
Patrol runs on your server and only sends the minimal context needed for analysis to the configured provider (when AI is enabled). Anonymous outbound telemetry (counts, feature flags, and coarse Patrol mode and governed Pulse Intelligence operations adoption flags and counters only; no hostnames, credentials, prompts, chat messages, command text, action output, token values, or resource identifiers) is enabled by default and can be disabled any time. See [Privacy](PRIVACY.md) for details.
Patrol runs on your server and only sends the minimal context needed for analysis to the configured provider (when AI is enabled). Outbound usage telemetry (a rotating pseudonymous install ID, counts, feature flags, and coarse Patrol mode and governed Pulse Intelligence operations adoption flags and counters only; no hostnames, credentials, prompts, chat messages, command text, action output, token values, IP addresses, or resource identifiers in the payload) is enabled by default and can be disabled any time. See [Privacy](PRIVACY.md) for details.
---
+1 -1
View File
@@ -306,7 +306,7 @@ When `allowEmbedding` is `false`, Pulse sends `X-Frame-Options: DENY` and `frame
| `PULSE_ENABLE_PROXMOX_GUEST_DOCKER_DETECTION` | Allow Proxmox-side LXC Docker socket hinting with `pct exec` | `false` |
| `PULSE_ENABLE_PROXMOX_GUEST_DOCKER_INVENTORY` | Allow Proxmox-side minimal LXC Docker inventory collection with `pct exec`; collects Docker host/container summary, not inspect/env/mount/process data | `false` |
| `PULSE_PROXMOX_GUEST_DOCKER_INVENTORY_VMIDS` | Optional comma-separated VMID allowlist for Proxmox-side LXC Docker inventory; empty means all running Docker-enabled LXCs are eligible when inventory is enabled | *(unset)* |
| `PULSE_TELEMETRY` | Anonymous outbound usage telemetry ([details](PRIVACY.md)); set `false` to disable | `true` |
| `PULSE_TELEMETRY` | Outbound usage telemetry ([details](PRIVACY.md)); set `false` to disable | `true` |
### Logging Overrides
+10 -10
View File
@@ -4,7 +4,7 @@ Pulse is designed to run locally. By default, your monitoring data stays on your
## Usage Data
Pulse has one outbound usage-data scope: **anonymous outbound telemetry** to
Pulse has one outbound usage-data scope: **outbound usage telemetry** to
help me understand active installations, release uptake, and feature use in
aggregate.
@@ -12,15 +12,15 @@ Commercial activation and license-recovery runtime records stay on the Pulse
instance where they were created. They are not exported to Pulse infrastructure,
third-party analytics, support diagnostics, or ordinary Settings surfaces.
### Anonymous outbound telemetry
### Outbound usage telemetry
Pulse includes anonymous outbound telemetry that is **enabled by default**. It sends a lightweight ping on startup and once every 24 hours to help me understand how many active installations exist, which releases are actually deployed, which features are in use, and whether Patrol control and governed Pulse Intelligence operations are being adopted.
Pulse includes outbound usage telemetry that is **enabled by default**. It sends a lightweight ping on startup and once every 24 hours with a rotating pseudonymous install ID to help me understand how many active installations exist, which releases are actually deployed, which features are in use, and whether Patrol control and governed Pulse Intelligence operations are being adopted.
No hostnames, credentials, infrastructure identifiers, IP addresses, prompts, chat messages, command text, action output, token values, or personally identifiable information is ever sent. See the full field list below.
The telemetry payload does not include hostnames, credentials, infrastructure identifiers, IP addresses, prompts, chat messages, command text, action output, token values, names, email addresses, or account identifiers. See the full field list below.
#### How to disable
- **Settings → System → General → Anonymous outbound telemetry** (toggle off), or
- **Settings → System → General → Outbound usage telemetry** (toggle off), or
- Set the environment variable `PULSE_TELEMETRY=false`
#### How to inspect or rotate it
@@ -31,7 +31,7 @@ No hostnames, credentials, infrastructure identifiers, IP addresses, prompts, ch
#### Exactly what is sent
Every field is listed below with the reason it exists — nothing else leaves your server:
Every field is listed below with the reason it exists. Nothing else is included in the telemetry payload:
| Field | Example | Purpose |
|-------|---------|---------|
@@ -148,19 +148,19 @@ Every field is listed below with the reason it exists — nothing else leaves yo
- Pulse may derive aggregate Pulse Intelligence adoption reports from those same rows, including whether an install reached Patrol issue activity, Patrol resolution, Assistant, direct external-agent, or MCP collaboration, Patrol mode starter use, paid Patrol mode cohorts, governed-action activity, approved or rejected action decisions, approved action success, completed Patrol control work, recent retention, and observed free-to-paid movement within the source window. Those reports do not add prompts, findings, resource identifiers, tool names, tool inputs, tool outputs, command payloads, action outputs, account links, or exact commercial tiers.
- External-agent/MCP activity is stored only as a coarse adapter-origin flag plus capability-class counters: context, event stream, provisioning, operator state, findings, and action requests.
- Telemetry rows older than **90 days** are purged automatically.
- The license server uses client IP addresses transiently for abuse/rate limiting, but it does **not** store IP addresses in telemetry rows.
- The license server uses request IP addresses transiently for abuse/rate limiting, but it does **not** store IP addresses in telemetry rows.
#### What is NOT sent
- No IP addresses are stored in telemetry rows
- No IP addresses are included in the telemetry payload or stored in telemetry rows
- No hostnames, node names, VM names, or any infrastructure identifiers
- No Proxmox credentials, API tokens, or passwords
- No alert content, AI prompts, chat messages, tool names, tool inputs, tool outputs, command text, action output, or token values
- No personally identifiable information of any kind
- No names, email addresses, account identifiers, or other intentionally identifying personal content
#### Install ID rotation
The telemetry install ID is pseudonymous and rotates automatically every 30 days.
The telemetry install ID is pseudonymous, is not tied to a Pulse account, and rotates automatically every 30 days.
Pulse keeps it only to avoid treating every startup ping as a brand-new install
while still limiting long-term linkage from one heartbeat window to the next.
Operators can also rotate it immediately from **Settings → System → General → Reset ID**.
@@ -138,12 +138,12 @@ command completed. External-agent/MCP readiness is optional collaboration
setup for agents outside the app, not a first-party Patrol control completion
gate and not a lifecycle setup stage.
Server update funnel telemetry is lifecycle-adjacent only. The updater's local
history may feed anonymous 30-day attempt, success, failure, and coarse failure
history may feed outbound usage 30-day attempt, success, failure, and coarse failure
category counters, but those counters are adoption analytics, not proof that a
particular agent update, profile rollout, host command, registration, or fleet
operation succeeded. Lifecycle surfaces must keep reading update readiness and
continuity from the updater, installer, connection ledger, and agent runtime
state instead of inferring it from anonymous telemetry.
state instead of inferring it from outbound usage telemetry.
1. `frontend-modern/src/api/agentProfiles.ts` shared with `api-contracts`: the agent profiles frontend client is both an agent lifecycle control surface and a canonical API payload contract boundary.
2. `frontend-modern/src/api/nodes.ts` shared with `api-contracts`: the shared Proxmox node client is both an agent lifecycle setup/install control surface and a canonical API payload contract boundary.
@@ -500,7 +500,7 @@ request payload.
must update the MCP README's Pulse Intelligence surface contract and the public
`docs/AI.md` overview from the manifest instead of leaving hand-written
Core/Patrol/Assistant/MCP relationship prose beside generated inventories.
Public AI docs may describe anonymous outbound telemetry only as counts,
Public AI docs may describe outbound usage telemetry only as counts,
feature flags, and coarse Patrol control and governed Pulse Intelligence
operations adoption flags and counters.
They must keep prompts, chat messages, command text, action output, token
@@ -3765,14 +3765,14 @@ for logs and response headers.
That same shared settings/licensing contract now also owns the split usage-data
payload model. `frontend-modern/src/api/settings.ts`,
`internal/api/router_routes_licensing.go`, and adjacent settings callers must
keep anonymous outbound telemetry as the only browser-visible usage-data scope;
keep outbound usage telemetry as the only browser-visible usage-data scope;
local commercial reporting controls stay internal/admin-owned and must not
surface as ordinary Settings controls. The telemetry preview payload must ship
normalized version identity fields (`version`, `version_raw`, `version_channel`,
`version_build`, `version_is_development`, and
`version_is_published_release`) instead of leaving browser callers to infer
published-release truth from raw build strings.
That same preview contract now includes the complete anonymous telemetry
That same preview contract now includes the complete outbound usage telemetry
payload shape, including aggregate self-hosted adoption counters for monitored
platforms, workloads, storage, and availability targets plus coarse feature
booleans, content-free update funnel counters, and content-free Patrol,
@@ -232,7 +232,7 @@ Stripe-free and avoids a cloud-control-plane report data path across clients.
`pkg/licensing/grant_refresh.go`, and cloud-paid transport must send those
values on activate, legacy exchange, and grant refresh instead of inferring
install version or paid-runtime status from browser state, dev build
metadata, public image tags, or anonymous telemetry.
metadata, public image tags, or outbound usage telemetry.
Active self-hosted paid entitlements must also treat runtime identity as a
first-class product state. A paid Pro, Pro Annual, Pro+, lifetime, or
enterprise entitlement on a non-Pro or missing runtime identity must render
@@ -395,7 +395,7 @@ files.
Pulse Intelligence paid-value evidence is a separate private admin aggregate,
not a revival of those retired funnel stores. The `pulse-pro` license server
may expose `/v1/admin/pulse-intelligence/value` and the matching admin-console
strip only as coarse install cohorts over anonymous telemetry pings: paid
strip only as coarse install cohorts over outbound usage telemetry pings: paid
install rate, free-to-paid conversion, returning-install retention, and whether
the full Patrol -> contextual collaboration -> governed action loop, the
stricter Patrol -> contextual collaboration -> approved execution loop, and
@@ -507,7 +507,7 @@ AGENT_SURFACE_ID_PULSE_MCP)` and `getAgentSurfaceToolPosturePresentation`,
4. `frontend-modern/src/components/Settings/DataHandlingPanel.tsx` shared with `security-privacy`: the data-handling settings surface is both a security/privacy trust surface and a canonical settings-shell presentation boundary.
5. `frontend-modern/src/components/Settings/dataHandlingPanelModel.ts` shared with `security-privacy`: the data-handling settings model is both a security/privacy posture projection and a canonical settings-shell presentation boundary.
6. `frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx` shared with `security-privacy`: the general settings privacy panel is both a security/privacy control surface and a canonical settings-shell presentation boundary.
The panel owns compact settings-shell framing for anonymous telemetry, but
The panel owns compact settings-shell framing for outbound usage telemetry, but
its vocabulary must stay aligned with `security-privacy`: aggregate
self-hosted adoption counts, coarse feature flags, and coarse Patrol,
Assistant, and external-agent usage counters may be named, while
@@ -2057,7 +2057,7 @@ default` instead of fusing provider and badge text such as
`AIRuntimeControlsSection.tsx` must not hardcode GitHub `main` doc URLs for
privacy, security, proxy-auth, scope-reference, or Terms-of-Service links.
29. Keep shared settings-shell telemetry transparency controls on the governed
general settings panel. Preview/reset affordances for anonymous telemetry
general settings panel. Preview/reset affordances for outbound usage telemetry
must stay rendered inside
`frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx`
instead of drifting into route-local modals, hidden dev tools, or shell
@@ -2069,7 +2069,7 @@ default` instead of fusing provider and badge text such as
`GeneralSettingsPanel.tsx` must state those facts plainly instead of
reverting to a stronger but inaccurate shorthand.
31. Keep maintainer commercial-event controls out of customer settings.
The shared general settings privacy panel may expose anonymous outbound
The shared general settings privacy panel may expose outbound usage
telemetry controls, preview, and reset affordances, but it must not render
local commercial handoff event toggles, `PULSE_DISABLE_LOCAL_UPGRADE_METRICS`,
or other commercial-debug controls as normal customer-facing preferences.
@@ -2446,8 +2446,8 @@ That same shared settings and modal boundary now also owns the public usage-data
vocabulary. `frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx`,
`frontend-modern/src/components/Settings/useSystemSettingsState.ts`, and
`frontend-modern/src/utils/systemSettingsPresentation.ts` must present one
explicit `Usage data and privacy` model centered on `Anonymous outbound
telemetry`; maintainer commercial-event controls, upgrade-metrics labels, and
explicit `Usage data and privacy` model centered on `Outbound usage telemetry`;
maintainer commercial-event controls, upgrade-metrics labels, and
sales/onboarding reporting language must not appear in customer-facing Settings
or support diagnostics, and public configuration docs must not list their
internal compatibility switches as ordinary operator settings. Customer
@@ -4627,7 +4627,7 @@ through `frontend-modern/src/utils/docsLinks.ts` rather than panel-local
external URLs.
That same shared-shell framing also covers the concise telemetry summary in
General settings. The shell may present the privacy contract in compact product
copy, but the vocabulary for anonymous outbound telemetry must stay aligned
copy, but the vocabulary for outbound usage telemetry must stay aligned
with `security-privacy`: aggregate self-hosted adoption counts, coarse feature
flags, and coarse Patrol, Assistant, and external-agent usage counters are
allowed, while hostnames, credentials, infrastructure identifiers, prompts,
@@ -950,7 +950,7 @@ reporting surface that claims installation totals must aggregate across the
provisioned tenant set through the reloadable multi-tenant monitor boundary,
not by reading `GetMonitor()`'s default-org compatibility shim.
Those install-wide counts are now the canonical aggregate adoption signal for
anonymous telemetry: monitoring owns the source counts for agent hosts, Docker
outbound usage telemetry: monitoring owns the source counts for agent hosts, Docker
and Kubernetes workloads, storage pools and physical disks, Ceph, network
shares, TrueNAS systems/VMs/apps, VMware hosts/VMs/datastores, availability
targets, and active alerts. Telemetry callers may consume those coarse totals,
@@ -398,7 +398,7 @@ the API boundary before it reaches persisted AI config: the settings handler
trim, drop blanks, de-duplicate) so untrusted request bodies cannot widen the
alert-driven investigation surface beyond the validated shape.
That same governed home now also owns the single customer-facing "usage data"
vocabulary for anonymous outbound telemetry. Local commercial activation and
vocabulary for outbound usage telemetry. Local commercial activation and
license-recovery runtime records must stay out of ordinary Settings, support
diagnostics, outbound telemetry disclosure copy, and public configuration
reference tables.
@@ -607,14 +607,14 @@ That same disclosure boundary now also fixes the telemetry payload floor:
commercial and auth-adjacent telemetry may report only coarse posture signals
such as whether a paid license is active or whether any API tokens exist.
Exact license tiers and exact API-token counts are not part of the canonical
anonymous telemetry contract and may not be reintroduced without updating this
outbound usage telemetry contract and may not be reintroduced without updating this
trust boundary and the governed privacy disclosure together.
That same rule also applies at the license-server ingest and storage boundary:
server-side telemetry rows may preserve the canonical normalized version
identity plus those same coarse booleans, but they must not retain legacy
exact commercial tier or exact API-token count fields as first-class analytics
dimensions just because older clients once sent them.
That same anonymous telemetry floor now also permits only privacy-safe
That same outbound usage telemetry floor now also permits only privacy-safe
aggregate self-hosted adoption counters: counts of monitored platforms,
workloads, storage resources, physical disks, Ceph clusters, network shares,
TrueNAS and VMware resource categories, availability targets, and active
@@ -622,7 +622,7 @@ alerts. Those counts may describe scale and feature adoption, but they must not
include hostnames, resource IDs, infrastructure identifiers, credentials,
prompts, chat messages, command text, action output, token values, or personal
information.
That same anonymous telemetry floor now also permits content-free update
That same outbound usage telemetry floor now also permits content-free update
funnel counters derived from local update history inside the same rotating
30-day telemetry window: update attempts, successful updates, failed or
rolled-back updates, and the latest coarse failure category. The category may
@@ -631,7 +631,7 @@ identify only the governed class (`download`, `signature`, `checksum`,
`cancelled`, or `unknown`). It must not export raw updater error text,
download URLs, command output, log lines, paths, hostnames, release asset URLs,
checksums, signatures, or operator-entered values.
That same anonymous telemetry floor now also permits only content-free Pulse
That same outbound usage telemetry floor now also permits only content-free Pulse
Patrol control and governed Pulse Intelligence operations adoption flags and
counters inside the same rotating 30-day telemetry window:
configured/active/completed/resolved governed-operation and approved-execution
@@ -713,7 +713,7 @@ content-free Pulse Intelligence fields only alongside the canonical coarse
entry-to-retention cohorts, paid Patrol-control completed/resolved
cohorts, and observed free-to-paid conversion counts without linking telemetry
to customer accounts or storing exact commercial tiers. The report may also
derive or persist a completed governed-operation signal from those same anonymous
derive or persist a completed governed-operation signal from those same content-free
fields, but completion may only mean observed Patrol
issue evidence plus Assistant governed-context or MCP collaboration activity
plus approved/rejected governed-action decision evidence inside the source window;
@@ -733,7 +733,7 @@ collaboration, and at least one approved governed action completed
successfully. It may not encode finding IDs, resource IDs, fix details,
verification detail, command text, action output, approver identity, or a
causal claim that the approved action directly resolved the finding.
The Patrol control completed-loop status count follows that same anonymous
The Patrol control completed-loop status count follows that same content-free telemetry
evidence contract: it may only mean the same content-free window also had
Patrol issue evidence, contextual collaboration, and either a rejected governed
decision or an approved governed decision with verified outcome proof. Legacy
@@ -741,7 +741,7 @@ Patrol autonomy and Pro activation completed-loop fields may mirror that value
for compatibility, but must not add checkout/account identity, prompt content,
action identity, resource identity, finding identity, token identity, or a
causality claim.
The Patrol control resolved-loop status count follows that same anonymous
The Patrol control resolved-loop status count follows that same content-free telemetry
evidence contract: it may only mean the same content-free window also had
Patrol issue evidence, contextual collaboration, an approved governed decision,
and verified outcome proof. It must not require MCP readiness, treat rejected
@@ -751,7 +751,7 @@ the status projection and outbound telemetry must derive these Patrol control
completed/resolved values through the shared `internal/telemetry` proof
classifier so privacy-sensitive reporting cannot drift into a richer runtime
event join in one caller.
That same anonymous telemetry contract also treats `install_id` as a rotating
That same outbound usage telemetry contract also treats `install_id` as a rotating
pseudonymous identifier, not a lifetime install handle. The runtime may keep a
local rotating UUID so startup and heartbeat pings can still represent an
active installation window, but it may not preserve one stable install
@@ -109,6 +109,12 @@ handlers, including Pro activation entry-point telemetry for the same
operations-loop prompt, is likewise API/privacy/commercial activation evidence
only; storage and recovery surfaces must not treat it as backup readiness,
restore capability, recovered-state proof, or storage-health verification.
Outbound usage telemetry projection in `internal/api/telemetry_pulse_intelligence.go`
is likewise API/privacy evidence only. Update funnel and governed-action
adoption counters may summarize content-free activity for product analytics,
but storage and recovery surfaces must not treat those counters as backup
coverage, restore capability, recovery-job proof, storage-health verification,
or evidence that a specific resource was protected or recovered.
Proxmox page stale-agent notices are adjacent frontend and agent-lifecycle
plumbing even though `ProxmoxPageSurface` is a storage/recovery canonical file.
Those notices may link an operator to scoped agent update commands for