From 5f54c68ad3ee7eb0a6ffaaf5960450ba334cedae Mon Sep 17 00:00:00 2001 From: Assad Yousuf Date: Fri, 10 Oct 2025 17:12:01 -0700 Subject: [PATCH 1/7] first commit --- crates/uv-client/src/base_client.rs | 38 +++++++++++++++++++++++++++++ crates/uv-client/src/error.rs | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/crates/uv-client/src/base_client.rs b/crates/uv-client/src/base_client.rs index c66c4a038..3e823efd4 100644 --- a/crates/uv-client/src/base_client.rs +++ b/crates/uv-client/src/base_client.rs @@ -986,6 +986,14 @@ pub struct UvRetryableStrategy; impl RetryableStrategy for UvRetryableStrategy { fn handle(&self, res: &Result) -> Option { + // Never retry SSL certificate errors (e.g., invalid peer certificate: UnknownIssuer). + if let Err(err) = res { + if is_ssl_certificate_error(err) { + debug!("Not retrying due to SSL certificate error"); + return Some(Retryable::Fatal); + } + } + // Use the default strategy and check for additional transient error cases. let retryable = match DefaultRetryableStrategy.handle(res) { None | Some(Retryable::Fatal) @@ -1019,6 +1027,28 @@ impl RetryableStrategy for UvRetryableStrategy { } } +/// Detect SSL certificate validation errors in a reqwest middleware error chain. +fn is_ssl_certificate_error(err: &reqwest_middleware::Error) -> bool { + // Try to find an inner reqwest::Error and inspect its sources for the rustls message + match err { + reqwest_middleware::Error::Reqwest(reqwest_err) => is_reqwest_ssl_error(reqwest_err), + reqwest_middleware::Error::Middleware(anyhow_err) => anyhow_err + .chain() + .find_map(|e| e.downcast_ref::()) + .is_some_and(is_reqwest_ssl_error), + } +} + +fn is_reqwest_ssl_error(reqwest_err: &reqwest::Error) -> bool { + if !reqwest_err.is_connect() { + return false; + } + // The underlying error messages are opaque types; check the error chain text for rustls message + std::error::Error::source(reqwest_err) + .and_then(|e| e.source()) + .is_some_and(|source| source.to_string().starts_with("invalid peer certificate: ")) +} + /// Whether the error looks like a network error that should be retried. /// /// There are two cases that the default retry strategy is missing: @@ -1035,6 +1065,14 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool { trace!("Considering retry of error: {err:?}"); } + // Do not retry SSL certificate validation errors. + if let Some(wrapped) = find_source::(err) { + if wrapped.is_ssl() { + trace!("Not retrying SSL certificate error"); + return false; + } + } + let mut has_known_error = false; // IO Errors or reqwest errors may be nested through custom IO errors or stream processing // crates diff --git a/crates/uv-client/src/error.rs b/crates/uv-client/src/error.rs index 7dc2b25a2..e8858877b 100644 --- a/crates/uv-client/src/error.rs +++ b/crates/uv-client/src/error.rs @@ -469,7 +469,7 @@ impl WrappedReqwestError { /// Check if the error chain contains a `reqwest` error that looks like this: /// * invalid peer certificate: `UnknownIssuer` - fn is_ssl(&self) -> bool { + pub(crate) fn is_ssl(&self) -> bool { if let Some(reqwest_err) = self.inner() { if !reqwest_err.is_connect() { return false; From 10294d16bc63a37d488b6aa3d2fc5b72fc4799ec Mon Sep 17 00:00:00 2001 From: Assad Yousuf Date: Tue, 14 Oct 2025 16:52:13 -0700 Subject: [PATCH 2/7] Base client and cached client should not be re-trying SSL errors --- crates/uv-client/src/base_client.rs | 87 +++++++++++++++++------------ 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/crates/uv-client/src/base_client.rs b/crates/uv-client/src/base_client.rs index 3e823efd4..9ce158f99 100644 --- a/crates/uv-client/src/base_client.rs +++ b/crates/uv-client/src/base_client.rs @@ -986,10 +986,12 @@ pub struct UvRetryableStrategy; impl RetryableStrategy for UvRetryableStrategy { fn handle(&self, res: &Result) -> Option { - // Never retry SSL certificate errors (e.g., invalid peer certificate: UnknownIssuer). if let Err(err) = res { - if is_ssl_certificate_error(err) { - debug!("Not retrying due to SSL certificate error"); + if contains_ssl_error(err) { + trace!( + "Cannot retry SSL certificate error for {}", + err.url().map(Url::as_str).unwrap_or("unknown URL") + ); return Some(Retryable::Fatal); } } @@ -1027,28 +1029,6 @@ impl RetryableStrategy for UvRetryableStrategy { } } -/// Detect SSL certificate validation errors in a reqwest middleware error chain. -fn is_ssl_certificate_error(err: &reqwest_middleware::Error) -> bool { - // Try to find an inner reqwest::Error and inspect its sources for the rustls message - match err { - reqwest_middleware::Error::Reqwest(reqwest_err) => is_reqwest_ssl_error(reqwest_err), - reqwest_middleware::Error::Middleware(anyhow_err) => anyhow_err - .chain() - .find_map(|e| e.downcast_ref::()) - .is_some_and(is_reqwest_ssl_error), - } -} - -fn is_reqwest_ssl_error(reqwest_err: &reqwest::Error) -> bool { - if !reqwest_err.is_connect() { - return false; - } - // The underlying error messages are opaque types; check the error chain text for rustls message - std::error::Error::source(reqwest_err) - .and_then(|e| e.source()) - .is_some_and(|source| source.to_string().starts_with("invalid peer certificate: ")) -} - /// Whether the error looks like a network error that should be retried. /// /// There are two cases that the default retry strategy is missing: @@ -1065,14 +1045,6 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool { trace!("Considering retry of error: {err:?}"); } - // Do not retry SSL certificate validation errors. - if let Some(wrapped) = find_source::(err) { - if wrapped.is_ssl() { - trace!("Not retrying SSL certificate error"); - return false; - } - } - let mut has_known_error = false; // IO Errors or reqwest errors may be nested through custom IO errors or stream processing // crates @@ -1081,7 +1053,9 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool { if let Some(reqwest_err) = source.downcast_ref::() { has_known_error = true; if let reqwest_middleware::Error::Reqwest(reqwest_err) = &**reqwest_err { - if default_on_request_error(reqwest_err) == Some(Retryable::Transient) { + if is_ssl_request_error(reqwest_err) { + trace!("Cannot retry nested reqwest middleware SSL error"); + } else if default_on_request_error(reqwest_err) == Some(Retryable::Transient) { trace!("Retrying nested reqwest middleware error"); return true; } @@ -1094,7 +1068,9 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool { trace!("Cannot retry nested reqwest middleware error"); } else if let Some(reqwest_err) = source.downcast_ref::() { has_known_error = true; - if default_on_request_error(reqwest_err) == Some(Retryable::Transient) { + if is_ssl_request_error(reqwest_err) { + trace!("Cannot retry nested reqwest SSL error"); + } else if default_on_request_error(reqwest_err) == Some(Retryable::Transient) { trace!("Retrying nested reqwest error"); return true; } @@ -1143,6 +1119,45 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool { false } +fn contains_ssl_error(err: &(dyn Error + 'static)) -> bool { + if let Some(middleware_err) = err.downcast_ref::() { + if let reqwest_middleware::Error::Reqwest(reqwest_err) = middleware_err { + if is_ssl_request_error(reqwest_err) { + return true; + } + } else if let reqwest_middleware::Error::Middleware(inner) = middleware_err { + if contains_ssl_error(inner.as_ref()) { + return true; + } + } + } + + let mut current: Option<&(dyn Error + 'static)> = Some(err); + while let Some(error) = current { + if let Some(reqwest_err) = error.downcast_ref::() { + if is_ssl_request_error(reqwest_err) { + return true; + } + } + current = error.source(); + } + false +} + +fn is_ssl_request_error(reqwest_err: &reqwest::Error) -> bool { + if !reqwest_err.is_connect() { + return false; + } + let mut current = reqwest_err.source(); + while let Some(err) = current { + if err.to_string().starts_with("invalid peer certificate: ") { + return true; + } + current = err.source(); + } + false +} + /// Whether the error is a status code error that is retryable. /// /// Port of `reqwest_retry::default_on_request_success`. @@ -1443,4 +1458,4 @@ mod tests { Ok(()) } -} +} \ No newline at end of file From 9240b04e7753b37a244c5df47d9950f0c7780ee0 Mon Sep 17 00:00:00 2001 From: Assad Yousuf Date: Tue, 14 Oct 2025 17:06:06 -0700 Subject: [PATCH 3/7] Dont need this to be public anymore --- crates/uv-client/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv-client/src/error.rs b/crates/uv-client/src/error.rs index e8858877b..7dc2b25a2 100644 --- a/crates/uv-client/src/error.rs +++ b/crates/uv-client/src/error.rs @@ -469,7 +469,7 @@ impl WrappedReqwestError { /// Check if the error chain contains a `reqwest` error that looks like this: /// * invalid peer certificate: `UnknownIssuer` - pub(crate) fn is_ssl(&self) -> bool { + fn is_ssl(&self) -> bool { if let Some(reqwest_err) = self.inner() { if !reqwest_err.is_connect() { return false; From 8f0875391ae3c59db41b4e8bdc0bdfa37efed491 Mon Sep 17 00:00:00 2001 From: Assad Yousuf Date: Tue, 14 Oct 2025 17:10:45 -0700 Subject: [PATCH 4/7] fmt --- crates/uv-client/src/base_client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv-client/src/base_client.rs b/crates/uv-client/src/base_client.rs index 9ce158f99..e094de0ad 100644 --- a/crates/uv-client/src/base_client.rs +++ b/crates/uv-client/src/base_client.rs @@ -1458,4 +1458,4 @@ mod tests { Ok(()) } -} \ No newline at end of file +} From dc1c712c9bc75c1b965b31a88d0514b9c5c33967 Mon Sep 17 00:00:00 2001 From: samypr100 <3933065+samypr100@users.noreply.github.com> Date: Mon, 17 Nov 2025 22:12:35 -0500 Subject: [PATCH 5/7] fix: add tests and improve detection --- crates/uv-client/Cargo.toml | 1 + crates/uv-client/src/base_client.rs | 87 ++++++++++++-------------- crates/uv-client/tests/it/http_util.rs | 12 ++++ crates/uv-client/tests/it/ssl_certs.rs | 52 ++++++++++++++- 4 files changed, 102 insertions(+), 50 deletions(-) diff --git a/crates/uv-client/Cargo.toml b/crates/uv-client/Cargo.toml index 20756fa34..b272eb584 100644 --- a/crates/uv-client/Cargo.toml +++ b/crates/uv-client/Cargo.toml @@ -57,6 +57,7 @@ reqwest-retry = { workspace = true } rkyv = { workspace = true } rmp-serde = { workspace = true } rustc-hash = { workspace = true } +rustls = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } sys-info = { workspace = true } diff --git a/crates/uv-client/src/base_client.rs b/crates/uv-client/src/base_client.rs index e094de0ad..73749937e 100644 --- a/crates/uv-client/src/base_client.rs +++ b/crates/uv-client/src/base_client.rs @@ -986,14 +986,13 @@ pub struct UvRetryableStrategy; impl RetryableStrategy for UvRetryableStrategy { fn handle(&self, res: &Result) -> Option { - if let Err(err) = res { - if contains_ssl_error(err) { - trace!( - "Cannot retry SSL certificate error for {}", - err.url().map(Url::as_str).unwrap_or("unknown URL") - ); - return Some(Retryable::Fatal); + if let Err(reqwest_middleware::Error::Reqwest(err)) = res + && is_tls_request_error(err) + { + if let Some(url) = err.url() { + trace!("Cannot retry {url} due to TLS error: {err:?}"); } + return Some(Retryable::Fatal); } // Use the default strategy and check for additional transient error cases. @@ -1053,8 +1052,9 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool { if let Some(reqwest_err) = source.downcast_ref::() { has_known_error = true; if let reqwest_middleware::Error::Reqwest(reqwest_err) = &**reqwest_err { - if is_ssl_request_error(reqwest_err) { - trace!("Cannot retry nested reqwest middleware SSL error"); + if is_tls_request_error(reqwest_err) { + trace!("Cannot retry nested reqwest middleware TLS error"); + return false; } else if default_on_request_error(reqwest_err) == Some(Retryable::Transient) { trace!("Retrying nested reqwest middleware error"); return true; @@ -1068,8 +1068,9 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool { trace!("Cannot retry nested reqwest middleware error"); } else if let Some(reqwest_err) = source.downcast_ref::() { has_known_error = true; - if is_ssl_request_error(reqwest_err) { - trace!("Cannot retry nested reqwest SSL error"); + if is_tls_request_error(reqwest_err) { + trace!("Cannot retry nested reqwest TLS error"); + return false; } else if default_on_request_error(reqwest_err) == Some(Retryable::Transient) { trace!("Retrying nested reqwest error"); return true; @@ -1119,43 +1120,8 @@ pub fn is_transient_network_error(err: &(dyn Error + 'static)) -> bool { false } -fn contains_ssl_error(err: &(dyn Error + 'static)) -> bool { - if let Some(middleware_err) = err.downcast_ref::() { - if let reqwest_middleware::Error::Reqwest(reqwest_err) = middleware_err { - if is_ssl_request_error(reqwest_err) { - return true; - } - } else if let reqwest_middleware::Error::Middleware(inner) = middleware_err { - if contains_ssl_error(inner.as_ref()) { - return true; - } - } - } - - let mut current: Option<&(dyn Error + 'static)> = Some(err); - while let Some(error) = current { - if let Some(reqwest_err) = error.downcast_ref::() { - if is_ssl_request_error(reqwest_err) { - return true; - } - } - current = error.source(); - } - false -} - -fn is_ssl_request_error(reqwest_err: &reqwest::Error) -> bool { - if !reqwest_err.is_connect() { - return false; - } - let mut current = reqwest_err.source(); - while let Some(err) = current { - if err.to_string().starts_with("invalid peer certificate: ") { - return true; - } - current = err.source(); - } - false +fn is_tls_request_error(reqwest_err: &reqwest::Error) -> bool { + reqwest_err.is_connect() && find_source_with_io::(&reqwest_err).is_some() } /// Whether the error is a status code error that is retryable. @@ -1184,6 +1150,31 @@ fn find_source(orig: &dyn Error) -> Option<&E> { None } +/// Find the first source error of a specific type while also wrapped in `io::Error`. +/// +/// Inspired by +/// See +fn find_source_with_io(orig: &dyn Error) -> Option<&E> { + let mut cause = orig.source(); + while let Some(err) = cause { + if let Some(concrete_err) = err.downcast_ref() { + return Some(concrete_err); + } + // Walk io::Error in case get_ref wraps the real source + if let Some(io_err) = err.downcast_ref::() { + if let Some(inner_err) = io_err.get_ref() { + if let Some(concrete_err) = inner_err.downcast_ref() { + return Some(concrete_err); + } + cause = Some(inner_err); + continue; + } + } + cause = err.source(); + } + None +} + // TODO(konsti): Remove once we find a native home for `retries_from_env` #[derive(Debug, Error)] pub enum RetryParsingError { diff --git a/crates/uv-client/tests/it/http_util.rs b/crates/uv-client/tests/it/http_util.rs index b879699b3..855809b29 100644 --- a/crates/uv-client/tests/it/http_util.rs +++ b/crates/uv-client/tests/it/http_util.rs @@ -368,6 +368,18 @@ pub(crate) async fn start_https_user_agent_server( .await } +/// Single Request HTTPS server with a self-signed CA that echoes the User Agent Header. +pub(crate) async fn start_https_ca_user_agent_server( + ca_cert: &SelfSigned, + server_cert: &SelfSigned, +) -> Result<(JoinHandle>, SocketAddr)> { + TestServerBuilder::new() + .with_ca_cert(ca_cert) + .with_server_cert(server_cert) + .start() + .await +} + /// Single Request HTTPS mTLS server that echoes the User Agent Header. pub(crate) async fn start_https_mtls_user_agent_server( ca_cert: &SelfSigned, diff --git a/crates/uv-client/tests/it/ssl_certs.rs b/crates/uv-client/tests/it/ssl_certs.rs index b634b425b..02a5c8fa5 100644 --- a/crates/uv-client/tests/it/ssl_certs.rs +++ b/crates/uv-client/tests/it/ssl_certs.rs @@ -1,3 +1,4 @@ +use std::error::Error; use std::str::FromStr; use anyhow::Result; @@ -12,10 +13,57 @@ use uv_static::EnvVars; use crate::http_util::{ generate_self_signed_certs, generate_self_signed_certs_with_ca, - start_https_mtls_user_agent_server, start_https_user_agent_server, test_cert_dir, + start_https_ca_user_agent_server, start_https_mtls_user_agent_server, + start_https_user_agent_server, test_cert_dir, }; -// SAFETY: This test is meant to run with single thread configuration +#[tokio::test] +async fn ssl_retry_once() -> Result<()> { + // Generate self-signed CA, server, and client certs + let (ca_cert, server_cert, _) = generate_self_signed_certs_with_ca()?; + + let (server_task, addr) = start_https_ca_user_agent_server(&ca_cert, &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; + let _ = server_task.await?; + + // Validate the client error + let Some(reqwest_middleware::Error::Middleware(middleware_error)) = res.err() else { + panic!("expected middleware error"); + }; + + // No retries should occur (we can directly get the hyper rustls error) + // We're explicit with our chains to be sensitive to any dependency changes + let expected_err = if let Some(err) = middleware_error.source() + && let Some(err) = err.downcast_ref::() + && let Some(err) = err.source() + && let Some(err) = err.downcast_ref::() + && let Some(err) = err.get_ref() + && let Some(err) = err.downcast_ref::() + && let Some(err) = err.get_ref() + && let Some(err) = err.downcast_ref::() + && matches!( + err, + rustls::Error::InvalidCertificate(rustls::CertificateError::UnknownIssuer) + ) { + true + } else { + false + }; + assert!(expected_err); + + Ok(()) +} + +// SAFETY: This test is meant to run in isolation #[tokio::test] #[allow(unsafe_code)] async fn ssl_env_vars() -> Result<()> { From be2b9e6c3e2ffb168f0cf00301f12dcd64fa415e Mon Sep 17 00:00:00 2001 From: Assad Yousuf Date: Sat, 29 Nov 2025 22:14:39 -0700 Subject: [PATCH 6/7] fix: Update ssl_env_vars test to use find_source_with_io helper --- crates/uv-client/src/base_client.rs | 2 +- crates/uv-client/src/lib.rs | 2 +- crates/uv-client/tests/it/ssl_certs.rs | 64 ++++++++------------------ 3 files changed, 22 insertions(+), 46 deletions(-) diff --git a/crates/uv-client/src/base_client.rs b/crates/uv-client/src/base_client.rs index 73749937e..66f35328a 100644 --- a/crates/uv-client/src/base_client.rs +++ b/crates/uv-client/src/base_client.rs @@ -1154,7 +1154,7 @@ fn find_source(orig: &dyn Error) -> Option<&E> { /// /// Inspired by /// See -fn find_source_with_io(orig: &dyn Error) -> Option<&E> { +pub fn find_source_with_io(orig: &dyn Error) -> Option<&E> { let mut cause = orig.source(); while let Some(err) = cause { if let Some(concrete_err) = err.downcast_ref() { diff --git a/crates/uv-client/src/lib.rs b/crates/uv-client/src/lib.rs index 2862fc6d1..c0043980d 100644 --- a/crates/uv-client/src/lib.rs +++ b/crates/uv-client/src/lib.rs @@ -1,7 +1,7 @@ pub use base_client::{ AuthIntegration, BaseClient, BaseClientBuilder, DEFAULT_RETRIES, ExtraMiddleware, RedirectClientWithMiddleware, RequestBuilder, RetryParsingError, UvRetryableStrategy, - is_transient_network_error, + find_source_with_io, is_transient_network_error, }; pub use cached_client::{CacheControl, CachedClient, CachedClientError, DataWithCachePolicy}; pub use error::{Error, ErrorKind, WrappedReqwestError}; diff --git a/crates/uv-client/tests/it/ssl_certs.rs b/crates/uv-client/tests/it/ssl_certs.rs index 02a5c8fa5..708685f7d 100644 --- a/crates/uv-client/tests/it/ssl_certs.rs +++ b/crates/uv-client/tests/it/ssl_certs.rs @@ -145,23 +145,16 @@ async fn ssl_env_vars() -> Result<()> { std::env::remove_var(EnvVars::SSL_CERT_FILE); } - // Validate the client error + // Validate the client error - TLS errors return Fatal early so we get Middleware variant 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()); + + // TLS errors are deeply nested in io::Error::get_ref() - use find_source_with_io to find them + assert!( + uv_client::find_source_with_io::(middleware_error.as_ref()).is_some(), + "Expected TLS error in chain" + ); // Validate the server error let server_res = server_task.await?; @@ -255,23 +248,16 @@ async fn ssl_env_vars() -> Result<()> { std::env::remove_var(EnvVars::SSL_CERT_DIR); } - // Validate the client error + // Validate the client error - TLS errors return Fatal early so we get Middleware variant 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()); + + // TLS errors are deeply nested in io::Error::get_ref() - use find_source_with_io to find them + assert!( + uv_client::find_source_with_io::(middleware_error.as_ref()).is_some(), + "Expected TLS error in chain" + ); // Validate the server error let server_res = server_task.await?; @@ -344,23 +330,13 @@ async fn ssl_env_vars() -> Result<()> { std::env::remove_var(EnvVars::SSL_CERT_FILE); } - // Validate the client error - let Some(reqwest_middleware::Error::Middleware(middleware_error)) = res.err() else { - panic!("expected middleware error"); + // Validate the client error - this is an mTLS failure (no client cert provided) + // The server closes the connection during handshake, so the client sees a + // generic connection error (e.g., "Connection refused"), not a TLS certificate error + let Err(reqwest_middleware::Error::Middleware(_middleware_error)) = res else { + panic!("expected middleware error, got: {:?}", res); }; - 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()); + // For mTLS, just verify we got an error - the server error below confirms it's TLS-related // Validate the server error let server_res = server_task.await?; From 0a5bfc96adbd8b899746dab94205d756a19a956d Mon Sep 17 00:00:00 2001 From: Assad Yousuf Date: Sat, 29 Nov 2025 22:51:23 -0700 Subject: [PATCH 7/7] fix: Use inline format args to satisfy clippy lint --- crates/uv-client/tests/it/ssl_certs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv-client/tests/it/ssl_certs.rs b/crates/uv-client/tests/it/ssl_certs.rs index 708685f7d..76e185b5a 100644 --- a/crates/uv-client/tests/it/ssl_certs.rs +++ b/crates/uv-client/tests/it/ssl_certs.rs @@ -334,7 +334,7 @@ async fn ssl_env_vars() -> Result<()> { // The server closes the connection during handshake, so the client sees a // generic connection error (e.g., "Connection refused"), not a TLS certificate error let Err(reqwest_middleware::Error::Middleware(_middleware_error)) = res else { - panic!("expected middleware error, got: {:?}", res); + panic!("expected middleware error, got: {res:?}"); }; // For mTLS, just verify we got an error - the server error below confirms it's TLS-related