Skip to content

test: strip inherited npm_config_user_agent from bunEnv - #31928

Open
robobun wants to merge 1 commit into
mainfrom
farm/b34a81f1/bunx-user-agent-env-leak
Open

test: strip inherited npm_config_user_agent from bunEnv#31928
robobun wants to merge 1 commit into
mainfrom
farm/b34a81f1/bunx-user-agent-env-leak

Conversation

@robobun

@robobun robobun commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

Fixes #31925

Repro

On a clean tree:

bun bd test test/cli/install/bunx.test.ts -t "npm_config_user_agent"
397 |   expect(out.trim()).toContain(`bun/${Bun.version}`);
error: expect(received).toContain(expected)
Expected to contain: "bun/1.4.0-debug"
Received: "bun/1.4.0 npm/? node/v24.3.0 linux x64"
(fail) should set "npm_config_user_agent" to bun

Cause

The issue's diagnosis (user agent built from an unsuffixed version) is not what happens: the user agent and Bun.version are built from the same Global::package_json_version constant, suffix included. The real mechanism is environment inheritance:

  1. bun bd test ... runs the bd script under the system bun, whose run_command sets npm_config_user_agent=bun/1.4.0 npm/? node/v24.3.0 linux x64 into the script environment.
  2. The build script execs the debug test runner, which inherits the variable, and bunEnv in test/harness.ts spreads process.env without stripping it.
  3. The spawned bun x print-pm sees a pre-existing npm_config_user_agent and keeps it (put_default in src/runtime/cli/run_command.rs and src/install/lib.rs, intentional inherit-if-set behavior dating back to the Zig implementation).

So the test compares the outer bun's user agent against the inner bun's Bun.version and fails deterministically whenever the two versions differ, i.e. for anyone running the suite through bun bd test / bun run. In CI the runner is launched by node, the variable is absent, and the test passes, so this never showed up there.

Fix

Strip npm_config_user_agent in bunEnv (test/harness.ts), next to the existing JSC_useJIT / FORCE_COLOR strips. Spawned buns then set their own user agent. No runtime change: the inherit-if-set behavior is deliberate and stays as is.

Verification

Note: the CI-lane failures on bunx.test.ts mentioned in the issue are the should handle package that requires node 24 test, not this assertion; those are owned by #31818 / #31820.

An outer bun run (e.g. launching the suite via bun bd test) injects
npm_config_user_agent into the test runner's environment. Spawned buns
keep a pre-existing value (put_default in run_command.rs), so the bunx
user agent test compared the outer bun's user agent against the inner
bun's Bun.version and failed whenever the two versions differ.
@github-actions github-actions Bot added the claude label Jun 6, 2026
@robobun

robobun commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator Author

@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.

LGTM — test-harness-only env strip following the existing pattern.

Extended reasoning...

Overview

This PR adds a single line (plus a comment) to test/harness.ts: npm_config_user_agent: undefined in the bunEnv object. The existing post-spread cleanup loop already deletes undefined keys, so the net effect is that spawned test subprocesses no longer inherit npm_config_user_agent from the outer bun run / bun bd invocation. This fixes a local-only test failure in bunx.test.ts where the inherited outer-bun user agent didn't match the debug Bun.version.

Security risks

None. This is test-harness configuration only — no runtime/production code is touched, and the change only removes an env var from spawned test processes.

Level of scrutiny

Low. It's a one-line addition that follows the exact same idiom already used in this object for JSC_useJIT and FORCE_COLOR. The PR description gives a clear root-cause analysis and verification. A grep confirms no other test relies on npm_config_user_agent being present in bunEnv; the only consumer is the bunx.test.ts assertion this fixes.

Other factors

No outstanding reviewer comments, no prior reviews, and no bugs surfaced by the bug-hunt. The change is mechanical and self-contained.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Worried about impact? Review this PR in Change Stack to explore blast radius before you approve or request changes.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cb77f254-a838-4e6f-a5c1-ed6f997dba0a

📥 Commits

Reviewing files that changed from the base of the PR and between a7839df and 979b09f.

📒 Files selected for processing (1)
  • test/harness.ts

Walkthrough

The test harness environment initialization is updated to clear the npm_config_user_agent environment variable by setting it to undefined. This prevents spawned bun processes from inheriting the user agent value injected by outer test runners, ensuring test assertions about user agent strings execute against a consistent baseline.

Changes

Test Harness Environment Setup

Layer / File(s) Summary
Clear npm_config_user_agent from test environment
test/harness.ts
The bunEnv constant is updated to explicitly set npm_config_user_agent to undefined in the test environment defaults, preventing spawned bun processes from retaining user agent values from outer bun run or bun bd test launchers.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: stripping the inherited npm_config_user_agent environment variable from bunEnv in the test harness.
Description check ✅ Passed The description thoroughly explains the issue, root cause, fix, and verification steps, matching the template sections with detailed technical context.
Linked Issues check ✅ Passed The PR directly addresses issue #31925 by stripping npm_config_user_agent from bunEnv, preventing environment inheritance that caused deterministic test failures.
Out of Scope Changes check ✅ Passed The changes are narrowly scoped to the test harness environment initialization and directly address the linked issue without introducing unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@robobun

robobun commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator Author

CI analysis for build 60999 (final): 14 test lanes failed (Linux glibc/musl x64/aarch64, Windows x64/aarch64), and every one of them fails only on should handle package that requires node 24 in bunx.test.ts (verified per-job logs, 4 in-lane retries each), exit code 3 from the @angular/cli engines check. That failure is pre-existing on every PR since @angular/cli 22.0.0 published (requires Node ^22.22.3 || ^24.15.0 || >=26.0.0, Bun reports v24.3.0) and is tracked by #31818 and #31820. It is deterministic, so a retrigger will not help until one of those lands. The same failure pattern appears on unrelated PRs, e.g. build 60931 on the markdown-only #31909.

The test this PR fixes, should set "npm_config_user_agent" to bun, passes on all lanes. This diff is test-harness only and is a no-op in CI, where the runner env never carries npm_config_user_agent; it only changes local bun bd test runs. Ready to merge from my side.

@robobun

robobun commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator Author

Re-checked against current main (f426a8e) while going through open test-infra PRs, and this one is still needed.

  • test/harness.ts on main still does not strip npm_config_user_agent, and both src/runtime/cli/run_command.rs and src/install/lib.rs still seed it with put_default, so an inherited value wins.
  • Launching the current debug test runner with the user agent an outer bun run injects (which is what bun bd test does) still fails bunx.test.ts exactly as described above: expected bun/1.4.0-debug, received bun/1.4.0 npm/? node/v26.3.0 linux x64. The same run with the variable unset passes, which is why CI (launched by node) never sees it.
  • bunx.test.ts npm_config_user_agent assertion fails on every canary/debug build #31925 was closed after checking that the user agent string itself carries the version suffix. It does, and it always did; the failing part is the inherited variable, which that check does not cover.

The branch merges cleanly. Leaving it open.

@robobun

robobun commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator Author

Hit the same failure on current main (bdb7382) with bun bd test test/cli/install/bunx.test.ts -t npm_config_user_agent: expected bun/1.4.0-debug, received bun/1.4.0 npm/? node/v26.3.0 linux x64. Same cause as described above, so this PR covers it and I am not opening a second one.

One data point, in case it is worth widening the strip while this is open: npm_config_user_agent is not the only variable the outer bun run bd exports that the bun under test keeps when it is already set. Running the debug binary inside an unrelated package (inner-pkg 9.9.9, script p = env | grep ^npm_) with the values an outer bun run exports present in the environment:

$ npm_config_user_agent='bun/1.4.0 npm/? node/v26.3.0 linux x64' npm_execpath=/workspace/bun/build/release/bun \
  npm_config_local_prefix=/workspace/bun npm_package_json=/workspace/bun/package.json \
  npm_package_name=bun npm_package_version=1.4.0 ./build/debug/bun-debug run --silent p
npm_config_local_prefix=/workspace/bun
npm_config_user_agent=bun/1.4.0 npm/? node/v26.3.0 linux x64
npm_execpath=/workspace/bun/build/release/bun
npm_package_json=/workspace/bun/package.json
npm_package_name=bun
npm_package_version=1.4.0

npm_command, npm_lifecycle_event, npm_lifecycle_script and npm_node_execpath are overwritten and do not leak. Of the ones that do, npm_execpath is the deliberate inherit-if-set sibling of the user agent (src/install/lib.rs and src/runtime/cli/run_command.rs seed both the same way) and under bun bd test it points at the bun that launched the build rather than bunExe(); the npm_package_* / npm_config_local_prefix inheritance is a separate npm compat discrepancy (#11713) that would go away on the runtime side.

Two ways to cover it here, if wanted: add npm_execpath: undefined next to the user agent, or delete the lowercase npm_ prefix in the cleanup loop below, the way it already handles BUN_DEBUG_* and BUILDKITE*. test/preload.ts syncs process.env to bunEnv, so either also cleans the test runner's own environment. Nothing in the suite asserts on those other variables today, and CI sets no npm_* variables, so this stays a local-only change either way. Fine to land as is.

alii pushed a commit that referenced this pull request Aug 15, 2026
### Problem
- `RunCommand::configure_env_for_run` (and its `_without_linker` twin)
take two positional bools, `log_errors` and `store_root_fd`, and three
of the four callers pass bare literals for both. At
`configure_env_for_run(ctx, &mut slot, None, true, true)` in
`bunx_command.rs` nothing says which flag is which, and swapping them
compiles.
- This is the one `bare_bool_args` finding mordant has baselined for
`src/runtime/cli/run_command.rs`.

### Fix
- Replace the two bools with a `ConfigureEnvOptions { log_errors,
store_root_fd }` struct (`run_command.rs`, next to `ExecCfg`, which
already gives `exec` its flags this way). Every caller now spells out
both fields: `filter_run.rs`, `multi_run.rs`, `bunx_command.rs`,
`pack_command.rs`, and the `exec` path inside `run_command.rs`.
- An options struct rather than two enums because two of the callers
compute `log_errors` (from `ExecCfg` and from the pack log level) and a
struct field takes the value as is.
- The private `configure_env_for_run_impl` keeps its single
`with_linker: bool`; the lint only considers functions with two or more
bool parameters, and its only callers are the two wrappers directly
above it.
- The values each caller passes are unchanged, so this is a pure rename
of the arguments; no behavior change.
- The `"bare_bool_args:src/runtime/cli/run_command.rs"` line is removed
from `mordant-baseline.toml`.
- Verified: `cargo fmt --all --check`; `bun bd test` on
`test/cli/run/run_command.test.ts`, `if-present.test.ts` (the
`log_errors: false` path), `multi-run.test.ts`,
`filter-workspace.test.ts`, `test/cli/install/bun-run.test.ts`,
`bunx.test.ts` (the `store_root_fd: true` caller), `bun-pack.test.ts`.
The only failure was `bunx.test.ts` "should set npm_config_user_agent to
bun", which fails on main too when run through `bun bd` (the outer `bun
run` exports its own `npm_config_user_agent` into the test env; #31928
addresses that) and passes with that variable unset.

### Background
- `configure_env_for_run` builds the process-lifetime `Transpiler` that
`bun run`, `bunx`, `bun run --filter`/`--parallel` and `bun pm pack` use
to resolve the working directory's `package.json` and seed the `npm_*`
environment variables for the script they are about to spawn.
- `log_errors`: when the working directory cannot be read, print the
resolver log and an error line; with it off the failure is only returned
(used by `bun <script> --if-present` and by `bun pm pack --silent`).
- `store_root_fd`: keep the working directory's fd open on the `DirInfo`
the function returns. Only `bunx` wants this, because it later reads the
resolved package's `bin` through that fd; the resolver's `store_fd` is
switched back off right after the root directory is read, so no other
directory keeps an fd.
- mordant is the dylint pack run by `bun run rust:mordant` (pinned in
`Cargo.toml`); `mordant-baseline.toml` lists pre-existing findings per
lint and file, so fixing one means deleting its line.
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.

bunx.test.ts npm_config_user_agent assertion fails on every canary/debug build

1 participant