Skip to content

Commit a479327

Browse files
authored
fix(install): don't treat JS scripts with non-Node shebang as native binaries (#33971)
The native-binary detection added in #33935 went through `node_resolver::read_bin_value`, which returns `BinValue::Executable` for *any* file whose first line isn't a recognized npx-style shebang — not just for files with ELF/Mach-O/PE magic bytes. Bin scripts with a `#!/usr/bin/env deno` shebang (like the `@denotest/lifecycle-scripts-simple` fixture) were therefore classified as native binaries, so `deno install -g` wrote a shim that `exec`'d the `.js` file directly instead of running `deno run`. On Unix the kernel still honored the shebang, but on Windows there is no shebang interpretation, so the install was broken — `specs::install::global::allow_scripts` started failing on the Windows shards once the change landed on main. Fix is to check the bin entry's magic bytes directly with `node_resolver::is_binary` instead of routing through `read_bin_value`, so only real ELF/Mach-O/PE binaries get the exec-the-file shim and ordinary JS bin scripts continue down the `deno run` path regardless of their shebang.
1 parent ab074be commit a479327

1 file changed

Lines changed: 53 additions & 5 deletions

File tree

cli/tools/installer/global.rs

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -584,11 +584,23 @@ fn resolve_native_binary_path(
584584
.clone()
585585
};
586586

587-
let node_resolution_sys =
588-
node_resolver::cache::NodeResolutionSys::new(sys, None);
589-
match node_resolver::read_bin_value(&bin_path, &node_resolution_sys)? {
590-
node_resolver::BinValue::Executable(path) => Some(path),
591-
node_resolver::BinValue::JsFile(_) => None,
587+
// Only treat the bin entry as a native binary if its magic bytes match
588+
// ELF/Mach-O/PE. `node_resolver::read_bin_value` returns `Executable` for
589+
// any file whose first line isn't a recognized npx-style shebang (e.g.
590+
// `#!/usr/bin/env deno` scripts) — which would incorrectly cause us to
591+
// generate an `exec`-the-file shim instead of a `deno run` shim. On
592+
// Windows there is no shebang interpretation, so that breaks installs of
593+
// ordinary npm packages whose bin scripts use a non-Node shebang.
594+
use std::io::Read;
595+
let mut file = std::fs::File::open(&bin_path).ok()?;
596+
let mut buf = [0u8; 4];
597+
if file.read(&mut buf).ok()? < 4 {
598+
return None;
599+
}
600+
if node_resolver::is_binary(&buf) {
601+
Some(bin_path)
602+
} else {
603+
None
592604
}
593605
}
594606

@@ -2289,6 +2301,42 @@ mod tests {
22892301
);
22902302
}
22912303

2304+
#[test]
2305+
fn native_binary_not_detected_for_non_node_shebang_js() {
2306+
// Regression: a JS bin script with a non-Node shebang (e.g.
2307+
// `#!/usr/bin/env deno`) was being misclassified as a native binary,
2308+
// which broke `deno install -g` on Windows since the generated shim
2309+
// execed the .js file directly instead of running `deno run`.
2310+
let temp_dir = TempDir::new();
2311+
let bin_dir = temp_dir.path().join("bin").to_path_buf();
2312+
let config_dir = bin_dir.join(".mytool");
2313+
let pkg_dir = config_dir.join("node_modules").join("mytool");
2314+
std::fs::create_dir_all(&pkg_dir).unwrap();
2315+
2316+
std::fs::write(
2317+
pkg_dir.join("package.json"),
2318+
r#"{"name": "mytool", "bin": {"mytool": "./main.js"}}"#,
2319+
)
2320+
.unwrap();
2321+
std::fs::write(
2322+
pkg_dir.join("main.js"),
2323+
"#!/usr/bin/env deno\nconsole.log('hello');",
2324+
)
2325+
.unwrap();
2326+
2327+
let bin_name_and_url = BinaryNameAndUrl {
2328+
name: "mytool".to_string(),
2329+
module_url: Url::parse("npm:mytool@1.0.0").unwrap(),
2330+
config_name: None,
2331+
};
2332+
2333+
let result = super::resolve_native_binary_path(&bin_name_and_url, &bin_dir);
2334+
assert!(
2335+
result.is_none(),
2336+
"JS file with non-Node shebang must not be classified as native binary"
2337+
);
2338+
}
2339+
22922340
#[cfg(not(windows))]
22932341
#[test]
22942342
fn generate_shim_for_native_binary() {

0 commit comments

Comments
 (0)