From 5a8c109725b06e3c89c1a934e4bef6ad3814b258 Mon Sep 17 00:00:00 2001 From: ddoemonn Date: Fri, 12 Dec 2025 00:12:33 +0300 Subject: [PATCH 1/3] fix: validate --project directory exists before use --- crates/uv/src/lib.rs | 16 ++++++++++++++++ crates/uv/tests/it/run.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index d8d4dbb91..6f836b2a0 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -99,6 +99,22 @@ async fn run(mut cli: Cli) -> Result { .map(Cow::Owned) .unwrap_or_else(|| Cow::Borrowed(&*CWD)); + // Validate that the project directory exists if explicitly provided via --project. + if let Some(project_path) = cli.top_level.global_args.project.as_ref() { + if !project_dir.exists() { + bail!( + "Project directory `{}` does not exist", + project_path.user_display() + ); + } + if !project_dir.is_dir() { + bail!( + "Project path `{}` is not a directory", + project_path.user_display() + ); + } + } + // Load environment variables not handled by Clap let environment = EnvironmentOptions::new()?; diff --git a/crates/uv/tests/it/run.rs b/crates/uv/tests/it/run.rs index 2350b178a..098d90b88 100644 --- a/crates/uv/tests/it/run.rs +++ b/crates/uv/tests/it/run.rs @@ -6092,3 +6092,41 @@ fn run_only_group_and_extra_conflict() -> Result<()> { Ok(()) } + +#[test] +fn run_project_not_found() -> Result<()> { + let context = TestContext::new("3.12"); + + // Using --project with a non-existent directory should error. + uv_snapshot!(context.filters(), context.run().arg("--project").arg("/tmp/does-not-exist-uv-test").arg("python").arg("-c").arg("print('hello')"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: Project directory `/tmp/does-not-exist-uv-test` does not exist + "###); + + Ok(()) +} + +#[test] +fn run_project_is_file() -> Result<()> { + let context = TestContext::new("3.12"); + + // Create a file instead of a directory. + let file_path = context.temp_dir.child("not-a-directory"); + file_path.write_str("")?; + + // Using --project with a file path should error. + uv_snapshot!(context.filters(), context.run().arg("--project").arg(file_path.path()).arg("python").arg("-c").arg("print('hello')"), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: Project path `not-a-directory` is not a directory + "###); + + Ok(()) +} From b02d92b24c2d5a27dd2b789df8ee1d15a1ed5e94 Mon Sep 17 00:00:00 2001 From: ddoemonn Date: Fri, 12 Dec 2025 00:22:44 +0300 Subject: [PATCH 2/3] Fix clippy warning in run_project_not_found --- crates/uv/tests/it/run.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/uv/tests/it/run.rs b/crates/uv/tests/it/run.rs index 098d90b88..d3abcd6cf 100644 --- a/crates/uv/tests/it/run.rs +++ b/crates/uv/tests/it/run.rs @@ -6094,7 +6094,7 @@ fn run_only_group_and_extra_conflict() -> Result<()> { } #[test] -fn run_project_not_found() -> Result<()> { +fn run_project_not_found() { let context = TestContext::new("3.12"); // Using --project with a non-existent directory should error. @@ -6106,8 +6106,6 @@ fn run_project_not_found() -> Result<()> { ----- stderr ----- error: Project directory `/tmp/does-not-exist-uv-test` does not exist "###); - - Ok(()) } #[test] From 73e68d119c3431d9f506b12bf3841c77f2ec8b00 Mon Sep 17 00:00:00 2001 From: ddoemonn Date: Fri, 12 Dec 2025 00:32:54 +0300 Subject: [PATCH 3/3] fix: skip --project directory validation for uv init --- crates/uv/src/lib.rs | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 6f836b2a0..7a5ff2a3c 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -100,18 +100,25 @@ async fn run(mut cli: Cli) -> Result { .unwrap_or_else(|| Cow::Borrowed(&*CWD)); // Validate that the project directory exists if explicitly provided via --project. - if let Some(project_path) = cli.top_level.global_args.project.as_ref() { - if !project_dir.exists() { - bail!( - "Project directory `{}` does not exist", - project_path.user_display() - ); - } - if !project_dir.is_dir() { - bail!( - "Project path `{}` is not a directory", - project_path.user_display() - ); + let skip_project_validation = matches!( + &*cli.command, + Commands::Project(command) if matches!(**command, ProjectCommand::Init(_)) + ); + + if !skip_project_validation { + if let Some(project_path) = cli.top_level.global_args.project.as_ref() { + if !project_dir.exists() { + bail!( + "Project directory `{}` does not exist", + project_path.user_display() + ); + } + if !project_dir.is_dir() { + bail!( + "Project path `{}` is not a directory", + project_path.user_display() + ); + } } }