From e4e68a77cc3f3089a053c4711d94f3cd0f680375 Mon Sep 17 00:00:00 2001 From: Tyler Earls Date: Tue, 18 Nov 2025 11:56:15 -0600 Subject: [PATCH 1/3] add fix to filter out empty SSL_CERT_FILE with unit test to support it --- crates/uv-client/src/base_client.rs | 4 +- crates/uv-client/tests/it/ssl_certs.rs | 57 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/crates/uv-client/src/base_client.rs b/crates/uv-client/src/base_client.rs index c66c4a038..fa75afd77 100644 --- a/crates/uv-client/src/base_client.rs +++ b/crates/uv-client/src/base_client.rs @@ -366,7 +366,9 @@ impl<'a> BaseClientBuilder<'a> { // Checks for the presence of `SSL_CERT_FILE`. // Certificate loading support is delegated to `rustls-native-certs`. // See https://github.com/rustls/rustls-native-certs/blob/813790a297ad4399efe70a8e5264ca1b420acbec/src/lib.rs#L118-L125 - let ssl_cert_file_exists = env::var_os(EnvVars::SSL_CERT_FILE).is_some_and(|path| { + let ssl_cert_file_exists = env::var_os(EnvVars::SSL_CERT_FILE) + .filter(|v| !v.is_empty()) + .is_some_and(|path| { let path_exists = Path::new(&path).exists(); if !path_exists { warn_user_once!( diff --git a/crates/uv-client/tests/it/ssl_certs.rs b/crates/uv-client/tests/it/ssl_certs.rs index b634b425b..e1215ab60 100644 --- a/crates/uv-client/tests/it/ssl_certs.rs +++ b/crates/uv-client/tests/it/ssl_certs.rs @@ -157,6 +157,63 @@ async fn ssl_env_vars() -> Result<()> { std::env::remove_var(EnvVars::SSL_CERT_FILE); } + // ** Set SSL_CERT_FILE to an empty string + // ** Then verify it is treated as unset (falls back to default behavior) + + unsafe { + std::env::set_var(EnvVars::SSL_CERT_FILE, ""); + } + let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?; + let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?; + let cache = Cache::temp()?.init()?; + let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build(); + let res = client + .cached_client() + .uncached() + .for_host(&url) + .get(Url::from(url)) + .send() + .await; + unsafe { + std::env::remove_var(EnvVars::SSL_CERT_FILE); + } + + // Empty SSL_CERT_FILE should be ignored, falling back to default certificate handling. + // The connection will fail because we're using a self-signed cert without providing the cert, + // but the important thing is it doesn't fail due to "empty path does not exist". + let Some(reqwest_middleware::Error::Middleware(middleware_error)) = res.err() else { + panic!("expected middleware error"); + }; + let reqwest_error = middleware_error + .chain() + .find_map(|err| { + err.downcast_ref::().map(|err| { + if let reqwest_middleware::Error::Reqwest(inner) = err { + inner + } else { + panic!("expected reqwest error") + } + }) + }) + .expect("expected reqwest error"); + assert!(reqwest_error.is_connect()); + + // Validate the server error - should be UnknownCA (not a path-related error) + let server_res = server_task.await?; + let expected_err = if let Err(anyhow_err) = server_res + && let Some(io_err) = anyhow_err.downcast_ref::() + && let Some(wrapped_err) = io_err.get_ref() + && let Some(tls_err) = wrapped_err.downcast_ref::() + && matches!( + tls_err, + rustls::Error::AlertReceived(AlertDescription::UnknownCA) + ) { + true + } else { + false + }; + assert!(expected_err); + // ** Set SSL_CERT_DIR to our cert dir as well as some other dir that does not exist // ** Then verify our request still successfully establishes a connection From 19b7170257ae94321be8c7e39161f21f595adc35 Mon Sep 17 00:00:00 2001 From: Tyler Earls Date: Tue, 18 Nov 2025 12:16:24 -0600 Subject: [PATCH 2/3] run cargo fmt --- crates/uv-client/src/base_client.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/uv-client/src/base_client.rs b/crates/uv-client/src/base_client.rs index fa75afd77..900abfa6d 100644 --- a/crates/uv-client/src/base_client.rs +++ b/crates/uv-client/src/base_client.rs @@ -369,15 +369,15 @@ impl<'a> BaseClientBuilder<'a> { let ssl_cert_file_exists = env::var_os(EnvVars::SSL_CERT_FILE) .filter(|v| !v.is_empty()) .is_some_and(|path| { - let path_exists = Path::new(&path).exists(); - if !path_exists { - warn_user_once!( - "Ignoring invalid `SSL_CERT_FILE`. File does not exist: {}.", - path.simplified_display().cyan() - ); - } - path_exists - }); + let path_exists = Path::new(&path).exists(); + if !path_exists { + warn_user_once!( + "Ignoring invalid `SSL_CERT_FILE`. File does not exist: {}.", + path.simplified_display().cyan() + ); + } + path_exists + }); // Checks for the presence of `SSL_CERT_DIR`. // Certificate loading support is delegated to `rustls-native-certs`. From 8c4ae0383877fe3cdbff2e0e5bfa9a997ad31b98 Mon Sep 17 00:00:00 2001 From: Tyler Earls Date: Thu, 20 Nov 2025 12:31:50 -0600 Subject: [PATCH 3/3] remove test case with false positive --- crates/uv-client/tests/it/ssl_certs.rs | 57 -------------------------- 1 file changed, 57 deletions(-) diff --git a/crates/uv-client/tests/it/ssl_certs.rs b/crates/uv-client/tests/it/ssl_certs.rs index e1215ab60..b634b425b 100644 --- a/crates/uv-client/tests/it/ssl_certs.rs +++ b/crates/uv-client/tests/it/ssl_certs.rs @@ -157,63 +157,6 @@ async fn ssl_env_vars() -> Result<()> { std::env::remove_var(EnvVars::SSL_CERT_FILE); } - // ** Set SSL_CERT_FILE to an empty string - // ** Then verify it is treated as unset (falls back to default behavior) - - unsafe { - std::env::set_var(EnvVars::SSL_CERT_FILE, ""); - } - let (server_task, addr) = start_https_user_agent_server(&standalone_server_cert).await?; - let url = DisplaySafeUrl::from_str(&format!("https://{addr}"))?; - let cache = Cache::temp()?.init()?; - let client = RegistryClientBuilder::new(BaseClientBuilder::default(), cache).build(); - let res = client - .cached_client() - .uncached() - .for_host(&url) - .get(Url::from(url)) - .send() - .await; - unsafe { - std::env::remove_var(EnvVars::SSL_CERT_FILE); - } - - // Empty SSL_CERT_FILE should be ignored, falling back to default certificate handling. - // The connection will fail because we're using a self-signed cert without providing the cert, - // but the important thing is it doesn't fail due to "empty path does not exist". - let Some(reqwest_middleware::Error::Middleware(middleware_error)) = res.err() else { - panic!("expected middleware error"); - }; - let reqwest_error = middleware_error - .chain() - .find_map(|err| { - err.downcast_ref::().map(|err| { - if let reqwest_middleware::Error::Reqwest(inner) = err { - inner - } else { - panic!("expected reqwest error") - } - }) - }) - .expect("expected reqwest error"); - assert!(reqwest_error.is_connect()); - - // Validate the server error - should be UnknownCA (not a path-related error) - let server_res = server_task.await?; - let expected_err = if let Err(anyhow_err) = server_res - && let Some(io_err) = anyhow_err.downcast_ref::() - && let Some(wrapped_err) = io_err.get_ref() - && let Some(tls_err) = wrapped_err.downcast_ref::() - && matches!( - tls_err, - rustls::Error::AlertReceived(AlertDescription::UnknownCA) - ) { - true - } else { - false - }; - assert!(expected_err); - // ** Set SSL_CERT_DIR to our cert dir as well as some other dir that does not exist // ** Then verify our request still successfully establishes a connection