nat.utils.telemetry.consent#
First-run consent prompt for NAT telemetry.
Order of precedence for whether telemetry is active:
NAT_TELEMETRY_ENABLEDenvironment variable, if set (any value).Persisted consent file at
~/.config/nat/telemetry.toml.Interactive prompt — only if all three of
stdin,stdout, andstderrare TTYs (seeis_interactive_session()). The prompt itself is rendered tostderr, so a captured stderr (2>/log, journald, Docker / CI log capture) would be invisible-but-effectful; gating on all three streams prevents that footgun.Default OFF, in non-interactive contexts (CI, cron, daemons).
The prompt is shown at most once per machine: the user’s answer is persisted, and subsequent invocations use the persisted value silently. The prompt explicitly tells the user what is collected, what is not collected, and how to change their decision later.
Attributes#
The single env var that, when set, overrides every other consent signal |
|
Bump if we materially change the prompt language. The persisted decision |
|
Classes#
Enum where members are also (and must be) strings |
Functions#
|
Return the env-var-driven consent override, or |
|
Resolve the consent file location. |
|
Read the user's persisted consent decision, if any. |
|
Persist the user's consent decision. |
|
Whether we should attempt to prompt the user. |
|
The user-facing consent prompt. |
|
Display the consent prompt and read the user's answer. |
|
Resolve telemetry state at module import time, without prompting. |
|
Run the first-run consent prompt if needed. |
Module Contents#
- logger#
- _CONSENT_FILE_ENV_VAR = 'NAT_TELEMETRY_CONSENT_FILE'#
- TELEMETRY_ENV_VAR = 'NAT_TELEMETRY_ENABLED'#
The single env var that, when set, overrides every other consent signal (persisted file, first-run prompt). Centralised here so producers and consumers share one canonical name.
- PROMPT_VERSION = '1.0'#
Bump if we materially change the prompt language. The persisted decision records which prompt version the user saw, so we can re-prompt on substantive changes (e.g. new categories of data collected).
- _TRUTHY = ('1', 'true', 'yes')#
- class ConsentState#
Bases:
enum.StrEnumEnum where members are also (and must be) strings
Initialize self. See help(type(self)) for accurate signature.
- ENABLED = 'enabled'#
- DISABLED = 'disabled'#
- NEVER_ASKED = 'never_asked'#
- resolve_env_consent() bool | None#
Return the env-var-driven consent override, or
Noneif unset.Single source of truth for “what does
NAT_TELEMETRY_ENABLEDsay”. Used by:resolve_initial_consent()— initial telemetry on/off decision.maybe_prompt_for_consent()— short-circuit when env wins.nat configure telemetry --status— report which signal source is effective.
- Returns:
Trueif the env var is set to a truthy value (case-insensitive1/true/yes);Falseif set to anything else;Noneif unset (caller should consult the persisted decision and/or prompt).
- _consent_file_path() pathlib.Path#
Resolve the consent file location.
Honors
NAT_TELEMETRY_CONSENT_FILEfor tests; falls back to~/.config/nat/telemetry.tomlfor production use.
- read_persisted_consent() ConsentState#
Read the user’s persisted consent decision, if any.
Asymmetric
prompt_versiongating, designed around user trust:Current ``prompt_version``: return the persisted state as-is.
Stale or missing ``prompt_version`` with ``consent = “disabled”``: return
DISABLED. A user who explicitly opted out under any version of the prompt must remain opted out — we never silently re-enable telemetry for someone who said no, even if we materially change the disclosure.Stale or missing ``prompt_version`` with ``consent = “enabled”``: return
NEVER_ASKEDto force a re-prompt under the new disclosure. A stale “yes” from a previous prompt version should not silently authorize collection under a new (potentially broader) disclosure.File missing, malformed, or unrecognized consent value: return
NEVER_ASKED.
The asymmetry is the key: re-prompting an already-disabled user combined with the default-yes prompt would be a silent opt-in flip — the worst possible privacy regression. Re-prompting an already-enabled user is conservative and respects the new disclosure.
- write_persisted_consent(state: ConsentState) None#
Persist the user’s consent decision.
Writes a small TOML file at the resolved consent path. Silently ignores write failures (filesystem permission errors, full disk, etc.) — the next interactive run will simply re-prompt.
- is_interactive_session() bool#
Whether we should attempt to prompt the user.
Requires all three standard streams to be TTYs:
stdin— soinput()can read the user’s reply.stdout— so any echoed feedback reaches the user.stderr— becauseprompt_user()writes the prompt itself to stderr; if stderr is captured (2>/some/log, journald, Docker log capture, CI log files), the user would be asked a question they cannot see and a keystroke / Enter would silently change their consent state.
Pipes, redirects, CI runners, daemons, and any other headless context return False — in those cases we never prompt, and telemetry defaults to OFF.
- render_prompt() str#
The user-facing consent prompt.
Kept inline (not in a separate file) so tests can assert on its contents and reviewers see any wording change in PR diffs.
- prompt_user() ConsentState#
Display the consent prompt and read the user’s answer.
Returns ENABLED on an explicit
y/yesor on an empty line (just pressing Enter, matching the[Y/n]default). Returns DISABLED onn/no, on any other input, or on EOF / KeyboardInterrupt. The decision is always persisted by the caller, so a hostile interrupt is treated as “no thanks” rather than re-prompting indefinitely.
- resolve_initial_consent() bool#
Resolve telemetry state at module import time, without prompting.
Used by
config.TELEMETRY_ENABLEDso a process that imports the telemetry package without going through the CLI entrypoint (e.g. a library user) gets a sensible default. Order:NAT_TELEMETRY_ENABLEDenv var, if set.Persisted consent file.
Default OFF — until the CLI prompt or env var resolves it.
- maybe_prompt_for_consent() None#
Run the first-run consent prompt if needed.
Called by the CLI entrypoint group callback. No-op when:
NAT_TELEMETRY_ENABLEDenv var is set (the user opted via env).A persisted consent decision already exists.
The session is non-interactive — see
is_interactive_session(), which requiresstdin,stdout, andstderrto all be TTYs.
Otherwise: print the prompt, read the user’s answer, persist the decision, and update the live
TELEMETRY_ENABLEDflag so the rest of this same invocation honors the choice.