ReviewOS

home-lang/home

native-package-run: `bun`/`node` in a package script can resolve outside the running binary

#704
Closed chris opened this 9 days ago ·
9 days ago

tests/runtime/native-package-run.test.mjs is the one persistent failure in scripts/runtime-regression.sh (68 ok / 1 failed). Filing what I have; I did not pin the exact trigger.

Symptom

The fixture's package.json has "native": "bun record.cjs native". The test asserts the spawned bun is the running binary:

assert.equal(record.execPath, realpathSync(process.execPath), result.stdout)

Observed record:

{"execPath":"/Users/…/.bun/bin/bun",
 "npmExecPath":"/Users/…/home/zig-out/bin/home-debug",
 "node":"/opt/homebrew/bin/node","nodeExists":true, …}

So npm_execpath is correctly the Home binary, but the bun the script actually ran, and the node alias, both resolved to the ambient PATH.

Not reproduced minimally

A minimal fixture ({"scripts":{"probe":"bun probe.cjs"}}, home run probe) reports execPath = the Home binary correctly, and creates no shim dir at all — so the bun-prefixed rewrite path works there. Whatever makes the test fail is narrower than "a package script calling bun". Trying "native" / "nested": "npm run native" in a temp dir instead failed earlier, with error: Module not found '<cwd>/native' — home run native was treated as run <file> rather than resolving the named script, which may be a second, separate bug worth checking.

One concrete suspect, unconfirmed

RunCommand.privateNodePath (packages/runtime/src/runtime/cli/run_command.zig:611-645) creates the shims at {dir}/node/node and {dir}/node/bun, sets private_node_path = {dir}/node/node, and sets private_node_dir = {dir} — the parent.

createFakeTemporaryNodeExecutable (:673) correctly appends dirname(node_path) = {dir}/node, but it only runs under needs_to_force_bun. The unconditional branch at :957 appends private_node_dir.? — i.e. {dir}, which contains no executables, only the node/ subdirectory:

if (Environment.isPosix) {
    try new_path.appendSlice(private_node_dir.?);
    try new_path.append(std.fs.path.delimiter);
}

If that is the bug, the fix is to put {dir}/node on PATH there. Bun's live configure_path_for_run documents itself as "Prepends workspace .bin dirs + the bun-node shim dir to PATH" (~/Code/bun/src/runtime/cli/run_command.rs).

Provenance

Pre-existing, not a regression: the test was added in b4ddf3056 ("fix(runtime): unify Node compatibility identity"). I had twice described it in #66 as "environmental / PATH-dependent" — that was imprecise, and this issue corrects it: PATH is involved, but only because Home is not controlling it the way Bun does.

Refs #66

9 days ago

Resolved by cb7d597e5, with fresh acceptance on current main f0327d434.

The repair creates and validates three aliases for the current executable: bun in the outer private shim directory, plus node and bun in its nested Node directory. The unconditional package-script PATH branch can therefore resolve nested bun commands without forcing Node mode, while --bun retains both aliases. Directory ownership/mode and every symlink target are validated before reuse.

tests/runtime/native-package-run.test.mjs now passes completely on the fresh ReleaseFast binary. It covers direct and nested package scripts (native, run native, and npm run native), pre/main/post hooks, the running executable identity, npm_execpath, durable NODE, module/eval flags, dotenv/config parsing, CLI binaries, stdin streaming, signals and failure propagation. A second run placed hostile ambient bun and node executables first on PATH; the same regression passed, proving neither ambient executable ran. No test expectation or package script was changed.

Sign in to comment on this issue.