Skip to content

analytics: let bunfig telemetry = true override DO_NOT_TRACK - #40728

Open
robobun wants to merge 3 commits into
mainfrom
farm/3b45829f/bunfig-telemetry-opt-in
Open

robobun wants to merge 3 commits into
mainfrom
farm/3b45829f/bunfig-telemetry-opt-in

Conversation

@robobun

@robobun robobun commented Aug 28, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • telemetry = true in bunfig.toml no longer enables crash reports when DO_NOT_TRACK=1 is set. The explicit opt-in is ignored.
  • is_enabled() in src/analytics/lib.rs:49 returns !DO_NOT_TRACK for TriState::Yes. Only the bunfig setter (src/bunfig/bunfig.rs:394) sets Yes. The Unknown arm already consults DO_NOT_TRACK, so Yes does not need to.
  • Robustness pass across install, css, ffi, crypto, spawn, shell, and node compat #36165 changed the arm from true to !DO_NOT_TRACK without a note in the PR body and without a test. The Zig source had .yes => true.

Fix

  • TriState::Yes => true. An explicit bunfig value wins over the environment. DO_NOT_TRACK decides only the Unknown state. The bunfig docs now state this order.
  • Debug and ASAN builds return from is_reporting_enabled() before they reach is_enabled(). So a test cannot observe the value through a crash. This PR adds crash_handler.isAnalyticsEnabled() to bun:internal-for-testing, next to getFeatureData().
  • Verified: test/config/bunfig/telemetry.test.ts (4 cases). With the binding but without the one-line fix, the telemetry = true plus DO_NOT_TRACK=1 case prints false. Also ran test/config/bunfig/bunfig-errors.test.ts, test/cli/run/run-crash-handler.test.ts, test/internal/macos-cross-config.test.ts, and test/internal/source-lints/.

Background

  • bun_analytics::ENABLED is a process-global TriState (Yes, No, Unknown). It starts as Unknown. The bunfig loader sets Yes or No from the telemetry key.
  • is_enabled() resolves Unknown once from the environment (DO_NOT_TRACK, HYPERFINE_RANDOMIZED_ENVIRONMENT_OFFSET) and caches the result.
  • The crash handler (src/crash_handler/lib.rs:2729) is the only reader. It checks BUN_CRASH_REPORT_URL, BUN_ENABLE_CRASH_REPORTING, debug, and ASAN first, then is_enabled().
Notes
  • Regressing commit: ff512ea (Robustness pass across install, css, ffi, crypto, spawn, shell, and node compat #36165), hunk in src/analytics/lib.rs. The PR body lists no telemetry change. Rust unit tests for the workspace do not run in CI, and no JS test covered this path.
  • The test deletes DO_NOT_TRACK and HYPERFINE_RANDOMIZED_ENVIRONMENT_OFFSET from the inherited env before it sets its own values, because bunEnv spreads the agent environment.
  • bun -e runs as the auto command and loads bunfig.toml from the cwd, so the test uses -e with a tempDir that holds the bunfig.
  • cargo clippy -p bun_analytics --no-deps is clean. cargo fmt --check and prettier are clean for the changed files.

[review] gate passed · iteration 0 · 5 files touched

fails on main (without fix)
ASAN without fix: 4 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/config/bunfig/telemetry.test.ts
bun test v1.4.1 (65362b53b)

test/config/bunfig/telemetry.test.ts:
18 |     cwd: String(dir),
19 |     stdout: "pipe",
20 |     stderr: "pipe",
21 |   });
22 |   const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
23 |   expect(stderr).toBe("");
                      ^
error: expect(received).toBe(expected)

- ""
+ "1 | console.log(require("bun:internal-for-testing").crash_handler.isAnalyticsEnabled());
+                                                                   ^
+ TypeError: require("bun:internal-for-testing").crash_handler.isAnalyticsEnabled is not a function. (In 'require("bun:internal-for-testing").crash_handler.isAnalyticsEnabled()', 'require("bun:internal-for-testing").crash_handler.isAnalyticsEnabled' is undefined)
+       at /tmp/bunfig-telemetry_q8hJI1/[eval]:1:63
+ 
+ Bun v1.4.1-debug+65362b53b (Linux x64)
+ "

- Expected  - 1
+ Received  + 7

      at isAnalyticsEnabled (/workspace/bun/test/config/bunfig/telemetry.test.ts:2
... (truncated)

release without fix: 4 FAILED
bun test v1.4.1-canary.1 (65362b53b)

test/config/bunfig/telemetry.test.ts:
18 |     cwd: String(dir),
19 |     stdout: "pipe",
20 |     stderr: "pipe",
21 |   });
22 |   const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
23 |   expect(stderr).toBe("");
                      ^
error: expect(received).toBe(expected)

- ""
+ "1 | console.log(require("bun:internal-for-testing").crash_handler.isAnalyticsEnabled());
+                                                                   ^
+ TypeError: require("bun:internal-for-testing").crash_handler.isAnalyticsEnabled is not a function. (In 'require("bun:internal-for-testing").crash_handler.isAnalyticsEnabled()', 'require("bun:internal-for-testing").crash_handler.isAnalyticsEnabled' is undefined)
+       at /tmp/bunfig-telemetry_mcFex5/[eval]:1:63
+ 
+ Bun v1.4.1-canary.1+65362b53b (Linux x64)
+ "

- Expected  - 1
+ Received  + 7

      at isAnalyticsEnabled (/workspace/bun/test/config/bunfig/telemetry.test.ts:23:18)
      at async <anonymous> (/workspace/bun/test/config/bunfig/telemetry.test.ts:39:18)
(fail) bunfig telemetry > without a telemetry setting, DO_NOT_TRA
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/config/bunfig/telemetry.test.ts
bun test v1.4.1 (65362b53b)

test/config/bunfig/telemetry.test.ts:
(pass) bunfig telemetry > telemetry = true overrides DO_NOT_TRACK=1 [1444.92ms]
(pass) bunfig telemetry > without a telemetry setting, DO_NOT_TRACK=1 disables analytics [1360.62ms]
(pass) bunfig telemetry > without a telemetry setting, analytics is enabled by default [1364.74ms]
(pass) bunfig telemetry > telemetry = false disables analytics [1425.68ms]

 4 pass
 0 fail
 16 expect() calls
Ran 4 tests across 1 file. [3.78s]
__F:0:S:0

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 791ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[1/22] gen generated_host_exports.rs
generated_host_exports.rs: 122 exports (host=5, lazy=10, generic=107, rust=0); 243 extern-C blocks audited
[2/22] gen JS modules (bundle-modules)
Preprocess modules (9627ms)
Bundle modules (138ms)
Postprocesss modules (930ms)
Bundle Functions (1017ms)
Generate Code (91ms)

[11.81s] Bundled "src/js" for production
  2595 kb
  197 internal modules
  13 native modules
  50 internal functions across 16 files
[2/6] cargo bun_runtime → libbun_runtime.a
�[1m�[92m   Compiling�[0m bun_analytics v0.0.0 (/workspace/bun/src/analytics)
�[1m�[92m   Compiling�[0m bun_dotenv v0.0.0 (/workspace/bun/src/dotenv)
�[1m�[92m   Compiling�[0m bun_options_types v0.0.0 (/workspace/bun/src/options_types)
�[1m�[92m   Compiling�[0m bun_spawn_sys v0.0.0 (/workspace/bun/src/spawn_sys)
�[1m�[92m   Compiling�[0m bun_io v0.0.0 (/workspace/bun/src/io)
�[1m�[92m   Compiling�[0m bun_api v0.0.0 (/workspace/bun/src/api)
�[1m�[92m   Compiling�[0m bun_crash_handler v0.0.0 (/workspace/bun/src/crash_handler)
�
... (truncated)
diff hotspot
docs/runtime/bunfig.mdx              |  2 +-
 src/analytics/lib.rs                 |  3 ++-
 src/js/internal-for-testing.ts       |  1 +
 src/runtime/api/crash_handler_jsc.rs |  6 +++++
 test/config/bunfig/telemetry.test.ts | 45 ++++++++++++++++++++++++++++++++++++
 5 files changed, 55 insertions(+), 2 deletions(-)

gate history · 1 passed · 0 rejected · iteration 0

evidence per changed file
file                                  reads  edits  tests
docs/runtime/bunfig.mdx                   1      2      0
src/analytics/lib.rs                      2      4      0
src/js/internal-for-testing.ts            1      1      0
src/runtime/api/crash_handler_jsc.rs      2      3      0
test/config/bunfig/telemetry.test.ts      0      1      0

An explicit telemetry = true in bunfig.toml sets TriState::Yes, and
is_enabled() now returns true for that state. The environment variable
only decides the Unknown state, as before #36165.

Add crash_handler.isAnalyticsEnabled() to bun:internal-for-testing so
a test can read the value. Debug builds never consult it in the crash
reporter.
@coderabbitai

coderabbitai Bot commented Aug 28, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

On-demand reviews are free for the next 23 days. After that, they cost $0.25 per reviewed file.

Or wait 9 minutes for your next included review.

View limit details

Limit details: You’ve used all 5 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 143ca1d1-5bf0-422b-bc28-3ae7871f85d3

📥 Commits

Reviewing files that changed from the base of the PR and between f05c8c3 and 37aec1d.

📒 Files selected for processing (5)
  • docs/runtime/bunfig.mdx
  • src/analytics/lib.rs
  • src/js/internal-for-testing.ts
  • src/runtime/api/crash_handler_jsc.rs
  • test/config/bunfig/telemetry.test.ts

Comment @coderabbitai help to get the list of available commands.

Comment thread src/analytics/lib.rs
Comment on lines 50 to +51
match enabled() {
TriState::Yes => !env_var::DO_NOT_TRACK.get().unwrap_or(false),
TriState::Yes => true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Project-controlled bunfig.toml telemetry = true now silently overrides a user's system-wide DO_NOT_TRACK=1 privacy opt-out

Extended reasoning...

bunfig.toml is a project-level file that is routinely checked into repositories a user clones — it is not necessarily authored by the user running Bun. After this change, TriState::Yes => true returns unconditionally, so a repo that ships telemetry = true in its bunfig defeats the user's DO_NOT_TRACK=1 environment variable, and is_reporting_enabled() at src/crash_handler/lib.rs:2729 proceeds to upload crash reports. Relative to the base branch (where TriState::Yes still consulted DO_NOT_TRACK and returned false), a user who has opted out of tracking system-wide now has crash reports uploaded to bun.report because of a file in a project they cloned, without any visible indication. The PR frames this as restoring pre-#36165 Zig behavior, but the docs update and PR body do not address that bunfig is project-scoped rather than user-scoped — this inverts the usual precedence where a user-level privacy signal wins over project config. If the intent is that only a user's own explicit opt-in should override DO_NOT_TRACK, the override belongs in the global bunfig…

Verification: normal — The scenario is real and reachable, and merging leaves the base branch worse on a privacy-relevant path. - src/analytics/lib.rs:51 now reads TriState::Yes => true; the base had TriState::Yes => !env_var::DO_NOT_TRACK.get().unwrap_or(false). So with DO_NOT_TRACK=1 set in the user's environment, is_enabled() flips from false (base) to true (PR) whenever bunfig set Yes. -…

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scenario is reachable. telemetry is parsed only for run commands, and run commands read the local bunfig.toml only (the global file is loaded for package manager commands). So a telemetry = true in a cloned repo is the only way this arm is set, and with this PR it wins over DO_NOT_TRACK=1.

Both orders are defensible. The PR restores the order the code had before #36165, which is what the maintainer who reported the bug asked for. The other order (the environment variable always wins) keeps the current main behavior and needs a docs change instead of a code change. I have raised the choice with the maintainer. This thread stays open until that decision lands.

Comment thread docs/runtime/bunfig.mdx Outdated
Comment thread src/analytics/lib.rs Outdated
Comment thread src/runtime/api/crash_handler_jsc.rs Outdated
@robobun

robobun commented Aug 28, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 12:35 AM PT - Aug 28th, 2026

❌ @robobun, your commit 37aec1d has 3 failures in Build #107449 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 40728

That installs a local version of the PR into your bun-40728 executable, so you can run:

bun-40728 --bun

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no new issues

No new issues were found in this update; 1 finding from earlier reviews is still open above.

@robobun

robobun commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

CI status for 37aec1d (build 107449): 178 of 181 jobs passed. The 3 failed jobs do not touch this diff, and all 3 fail on main too:

  • :windows: 2019 x64 - test-bun, one shard: buildkite-agent artifact download timed out after 120s before any test ran.
  • :debian: 13 x64-asan: test/cli/run/require-cache.test.ts, a 30s timeout in a leak test.
  • :darwin: any x64: test/js/web/url/url.test.ts, TypeError: Invalid URL in the Unicode 16 IDNA case.

test/config/bunfig/telemetry.test.ts passed on every lane. The open review thread on src/analytics/lib.rs is a precedence question (bunfig telemetry vs DO_NOT_TRACK) that waits on a maintainer decision.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants