1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

fix(compile/npm): ignore symlinks to non-existent paths in node_modules directory (#21479)

Part of https://github.com/denoland/deno/issues/21476
This commit is contained in:
David Sherret 2023-12-06 16:25:24 -05:00 committed by GitHub
parent 07f78912d6
commit 7fdc3c8f1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 92 additions and 27 deletions

4
Cargo.lock generated
View file

@ -1476,9 +1476,9 @@ dependencies = [
[[package]]
name = "deno_npm"
version = "0.15.2"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "210f62105862f1ff371e278c623c7ed73d62b0efece4d417c15663d37b730098"
checksum = "718b0b55031643de7808f8b426661b22a685820f1f459e028776bcc49e07b881"
dependencies = [
"anyhow",
"async-trait",

View file

@ -65,7 +65,7 @@ deno_emit = "=0.31.5"
deno_graph = "=0.61.5"
deno_lint = { version = "=0.52.2", features = ["docs"] }
deno_lockfile.workspace = true
deno_npm = "0.15.2"
deno_npm = "0.15.3"
deno_runtime = { workspace = true, features = ["dont_create_runtime_snapshot", "include_js_files_for_snapshotting"] }
deno_semver = "0.5.1"
deno_task_shell = "=0.14.0"

View file

@ -568,9 +568,16 @@ impl<'a> DenoCompileBinaryWriter<'a> {
}
fn build_vfs(&self) -> Result<VfsBuilder, AnyError> {
fn maybe_warn_different_system(system_info: &NpmSystemInfo) {
if system_info != &NpmSystemInfo::default() {
log::warn!("{} The node_modules directory may be incompatible with the target system.", crate::colors::yellow("Warning"));
}
}
match self.npm_resolver.as_inner() {
InnerCliNpmResolverRef::Managed(npm_resolver) => {
if let Some(node_modules_path) = npm_resolver.root_node_modules_path() {
maybe_warn_different_system(&self.npm_system_info);
let mut builder = VfsBuilder::new(node_modules_path.clone())?;
builder.add_dir_recursive(node_modules_path)?;
Ok(builder)
@ -593,6 +600,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
}
}
InnerCliNpmResolverRef::Byonm(npm_resolver) => {
maybe_warn_different_system(&self.npm_system_info);
// the root_node_modules directory will always exist for byonm
let node_modules_path = npm_resolver.root_node_modules_path().unwrap();
let parent_path = node_modules_path.parent().unwrap();

View file

@ -94,27 +94,40 @@ impl VfsBuilder {
} else if file_type.is_file() {
self.add_file_at_path(&path)?;
} else if file_type.is_symlink() {
let target = util::fs::canonicalize_path(&path)
.with_context(|| format!("Reading symlink {}", path.display()))?;
if let Err(StripRootError { .. }) = self.add_symlink(&path, &target) {
if target.is_file() {
// this may change behavior, so warn the user about it
match util::fs::canonicalize_path(&path) {
Ok(target) => {
if let Err(StripRootError { .. }) = self.add_symlink(&path, &target)
{
if target.is_file() {
// this may change behavior, so warn the user about it
log::warn!(
"{} Symlink target is outside '{}'. Inlining symlink at '{}' to '{}' as file.",
crate::colors::yellow("Warning"),
self.root_path.display(),
path.display(),
target.display(),
);
// inline the symlink and make the target file
let file_bytes = std::fs::read(&target)
.with_context(|| format!("Reading {}", path.display()))?;
self.add_file(&path, file_bytes)?;
} else {
log::warn!(
"{} Symlink target is outside '{}'. Excluding symlink at '{}' with target '{}'.",
crate::colors::yellow("Warning"),
self.root_path.display(),
path.display(),
target.display(),
);
}
}
}
Err(err) => {
log::warn!(
"Symlink target is outside '{}'. Inlining symlink at '{}' to '{}' as file.",
self.root_path.display(),
"{} Failed resolving symlink. Ignoring.\n Path: {}\n Message: {:#}",
crate::colors::yellow("Warning"),
path.display(),
target.display(),
);
// inline the symlink and make the target file
let file_bytes = std::fs::read(&target)
.with_context(|| format!("Reading {}", path.display()))?;
self.add_file(&path, file_bytes)?;
} else {
log::warn!(
"Symlink target is outside '{}'. Excluding symlink at '{}' with target '{}'.",
self.root_path.display(),
path.display(),
target.display(),
err
);
}
}

View file

@ -1062,6 +1062,44 @@ fn compile_node_modules_symlink_outside() {
output.assert_matches_file("compile/node_modules_symlink_outside/main.out");
}
#[test]
fn compile_node_modules_symlink_non_existent() {
let context = TestContextBuilder::for_npm().use_temp_cwd().build();
let temp_dir = context.temp_dir().path();
temp_dir.join("main.ts").write(
r#"import { getValue, setValue } from "npm:@denotest/esm-basic";
setValue(4);
console.log(getValue());"#,
);
let node_modules_dir = temp_dir.join("node_modules");
node_modules_dir.create_dir_all();
// create a symlink that points to a non_existent file
node_modules_dir.symlink_dir("non_existent", "folder");
// compile folder
let output = context
.new_command()
.args("compile --allow-read --node-modules-dir --output bin main.ts")
.run();
output.assert_exit_code(0);
output.assert_matches_text(
r#"Download http://localhost:4545/npm/registry/@denotest/esm-basic
Download http://localhost:4545/npm/registry/@denotest/esm-basic/1.0.0.tgz
Initialize @denotest/esm-basic@1.0.0
Check file:///[WILDCARD]/main.ts
Compile file:///[WILDCARD]/main.ts to [WILDCARD]
Warning Failed resolving symlink. Ignoring.
Path: [WILDCARD]
Message: [WILDCARD])
"#,
);
// run
let binary_path =
temp_dir.join(if cfg!(windows) { "bin.exe" } else { "bin" });
let output = context.new_command().name(binary_path).run();
output.assert_matches_text("4\n");
}
#[test]
fn dynamic_imports_tmp_lit() {
let context = TestContextBuilder::new().build();

View file

@ -1,2 +1,2 @@
Compile file:///[WILDCARD]/node_modules_symlink_outside/main.ts to [WILDCARD]
Symlink target is outside '[WILDCARD]node_modules_symlink_outside[WILDCARD]node_modules'. Inlining symlink at '[WILDCARD]node_modules_symlink_outside[WILDCARD]node_modules[WILDCARD]test.txt' to '[WILDCARD]node_modules_symlink_outside[WILDCARD]test.txt' as file.
Warning Symlink target is outside '[WILDCARD]node_modules_symlink_outside[WILDCARD]node_modules'. Inlining symlink at '[WILDCARD]node_modules_symlink_outside[WILDCARD]node_modules[WILDCARD]test.txt' to '[WILDCARD]node_modules_symlink_outside[WILDCARD]test.txt' as file.

View file

@ -3,4 +3,4 @@ Download http://localhost:4545/npm/registry/@denotest/esm-basic/1.0.0.tgz
Initialize @denotest/esm-basic@1.0.0
Check file:///[WILDCARD]/node_modules_symlink_outside/main.ts
Compile file:///[WILDCARD]/node_modules_symlink_outside/main.ts to [WILDCARD]
Symlink target is outside '[WILDCARD]node_modules_symlink_outside[WILDCARD]node_modules'. Excluding symlink at '[WILDCARD]node_modules_symlink_outside[WILDCARD]node_modules[WILDCARD]some_folder' with target '[WILDCARD]node_modules_symlink_outside[WILDCARD]some_folder'.
Warning Symlink target is outside '[WILDCARD]node_modules_symlink_outside[WILDCARD]node_modules'. Excluding symlink at '[WILDCARD]node_modules_symlink_outside[WILDCARD]node_modules[WILDCARD]some_folder' with target '[WILDCARD]node_modules_symlink_outside[WILDCARD]some_folder'.

View file

@ -71,8 +71,9 @@ pub async fn compile(
);
validate_output_path(&output_path)?;
let mut file = std::fs::File::create(&output_path)?;
binary_writer
let mut file = std::fs::File::create(&output_path)
.with_context(|| format!("Opening file '{}'", output_path.display()))?;
let write_result = binary_writer
.write_bin(
&mut file,
eszip,
@ -81,8 +82,13 @@ pub async fn compile(
cli_options,
)
.await
.with_context(|| format!("Writing {}", output_path.display()))?;
.with_context(|| format!("Writing {}", output_path.display()));
drop(file);
if let Err(err) = write_result {
// errored, so attempt to remove the output path
let _ = std::fs::remove_file(output_path);
return Err(err);
}
// set it as executable
#[cfg(unix)]