fix(windows): make pnpm dev:app:win work behind TLS-inspecting proxies (#2449)

This commit is contained in:
Mega Mind
2026-05-21 23:29:01 +05:30
committed by GitHub
parent 7aa1bf1f88
commit beba562df2
14 changed files with 261 additions and 57 deletions
+4 -3
View File
@@ -78,10 +78,11 @@ fn build_backend_reqwest_client() -> Result<Client> {
);
}
// Force rustls for consistent cross-platform TLS behavior.
Client::builder()
// Platform-appropriate TLS backend: Windows → schannel (honors the OS
// cert store, required for corporate TLS-inspection proxies); macOS /
// Linux → rustls. See [`crate::openhuman::tls::tls_client_builder`].
crate::openhuman::tls::tls_client_builder()
.default_headers(default_headers)
.use_rustls_tls()
.http1_only()
.timeout(Duration::from_secs(120))
.connect_timeout(Duration::from_secs(15))
+2 -2
View File
@@ -263,8 +263,8 @@ fn save_stored_app_state(config: &Config, state: &StoredAppState) -> Result<(),
}
fn build_client() -> Result<Client, String> {
Client::builder()
.use_rustls_tls()
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
crate::openhuman::tls::tls_client_builder()
.http1_only()
.timeout(Duration::from_secs(30))
.connect_timeout(Duration::from_secs(10))
+4 -5
View File
@@ -455,11 +455,10 @@ impl ComposioClient {
// from `IntegrationClient`, which we intentionally avoid so the
// public surface of that type doesn't widen for one caller.
//
// Mirror the TLS settings of the shared client
// (`use_rustls_tls + http1_only`) so this path has the same
// connection behaviour as the other backend calls.
let http_client = reqwest::Client::builder()
.use_rustls_tls()
// Mirror the TLS settings of the shared client so this path has the
// same connection behaviour as the other backend calls.
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
let http_client = crate::openhuman::tls::tls_client_builder()
.http1_only()
.timeout(std::time::Duration::from_secs(60))
.connect_timeout(std::time::Duration::from_secs(15))
+17 -5
View File
@@ -441,10 +441,15 @@ pub fn build_runtime_proxy_client(service_key: &str) -> reqwest::Client {
return client;
}
let builder = apply_runtime_proxy_to_builder(reqwest::Client::builder(), service_key);
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
let builder =
apply_runtime_proxy_to_builder(crate::openhuman::tls::tls_client_builder(), service_key);
let client = builder.build().unwrap_or_else(|error| {
tracing::warn!(service_key, "Failed to build proxied client: {error}");
reqwest::Client::new()
// Apply the same platform TLS selection on the fallback path so the
// error-path client also honors the Windows cert store.
let fb = crate::openhuman::tls::tls_client_builder();
fb.build().unwrap_or_default()
});
set_runtime_proxy_cached_client(cache_key, client.clone());
client
@@ -461,16 +466,23 @@ pub fn build_runtime_proxy_client_with_timeouts(
return client;
}
let builder = reqwest::Client::builder()
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
let raw = crate::openhuman::tls::tls_client_builder()
.timeout(std::time::Duration::from_secs(timeout_secs))
.connect_timeout(std::time::Duration::from_secs(connect_timeout_secs));
let builder = apply_runtime_proxy_to_builder(builder, service_key);
let builder = apply_runtime_proxy_to_builder(raw, service_key);
let client = builder.build().unwrap_or_else(|error| {
tracing::warn!(
service_key,
"Failed to build proxied timeout client: {error}"
);
reqwest::Client::new()
// Apply the same platform TLS selection and timeouts on the fallback
// path so the error-path client also honors the Windows cert store
// and remains bounded.
let fb = crate::openhuman::tls::tls_client_builder()
.timeout(std::time::Duration::from_secs(timeout_secs))
.connect_timeout(std::time::Duration::from_secs(connect_timeout_secs));
fb.build().unwrap_or_default()
});
set_runtime_proxy_cached_client(cache_key, client.clone());
client
+10 -6
View File
@@ -278,8 +278,8 @@ impl OpenAiCompatibleProvider {
headers.insert(USER_AGENT, value);
}
let builder = Client::builder()
.use_rustls_tls()
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
let builder = crate::openhuman::tls::tls_client_builder()
.timeout(std::time::Duration::from_secs(120))
.connect_timeout(std::time::Duration::from_secs(10))
.default_headers(headers);
@@ -290,12 +290,14 @@ impl OpenAiCompatibleProvider {
return builder.build().unwrap_or_else(|error| {
tracing::warn!("Failed to build proxied timeout client with user-agent: {error}");
Client::new()
crate::openhuman::tls::tls_client_builder()
.build()
.unwrap_or_default()
});
}
let builder = Client::builder()
.use_rustls_tls()
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
let builder = crate::openhuman::tls::tls_client_builder()
.timeout(std::time::Duration::from_secs(120))
.connect_timeout(std::time::Duration::from_secs(10));
let builder = crate::openhuman::config::apply_runtime_proxy_to_builder(
@@ -304,7 +306,9 @@ impl OpenAiCompatibleProvider {
);
builder.build().unwrap_or_else(|error| {
tracing::warn!("Failed to build proxied timeout client: {error}");
Client::new()
crate::openhuman::tls::tls_client_builder()
.build()
.unwrap_or_default()
})
}
+5 -10
View File
@@ -92,16 +92,11 @@ impl IntegrationClient {
// to fix up the input so the regression is observable in logs.
let backend_url = sanitize_backend_url(&backend_url);
// Match the TLS config used by `BackendOAuthClient` in
// `src/api/rest.rs`: force rustls + HTTP/1.1 so we get the same
// consistent cross-platform behaviour every other backend-proxied
// domain (billing, team, webhooks, referral, …) already relies
// on. The default builder picks up native-tls on macOS, which
// has historically failed on staging TLS handshakes while
// rustls succeeds — so the integrations client was the odd one
// out with raw "error sending request" failures.
let http_client = reqwest::Client::builder()
.use_rustls_tls()
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
// Windows uses schannel (native-tls) to honor the OS cert store;
// macOS / Linux keep rustls which avoids the OpenSSL runtime dep and
// has historically been more reliable on staging TLS handshakes.
let http_client = crate::openhuman::tls::tls_client_builder()
.http1_only()
.timeout(Duration::from_secs(60))
.connect_timeout(Duration::from_secs(15))
+2 -2
View File
@@ -23,8 +23,8 @@ fn shared_http_client() -> reqwest::Client {
SHARED_HTTP_CLIENT
.get_or_init(|| {
tracing::debug!("[searxng] initializing shared HTTP client");
reqwest::Client::builder()
.use_rustls_tls()
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
crate::openhuman::tls::tls_client_builder()
.build()
.expect("failed to build shared SearXNG HTTP client")
})
+2 -2
View File
@@ -64,8 +64,8 @@ impl SeltzSearchTool {
timeout_secs: u64,
) -> Self {
let timeout = timeout_secs.max(1);
let http_client = reqwest::Client::builder()
.use_rustls_tls()
// Platform-appropriate TLS backend — see [`crate::openhuman::tls`].
let http_client = crate::openhuman::tls::tls_client_builder()
.http1_only()
.timeout(Duration::from_secs(timeout))
.connect_timeout(Duration::from_secs(10))
+1
View File
@@ -74,6 +74,7 @@ pub mod team;
pub mod test_support;
pub mod text_input;
pub mod threads;
pub mod tls;
pub mod todos;
pub mod tokenjuice;
pub mod tool_registry;
+34
View File
@@ -0,0 +1,34 @@
//! Platform-conditional TLS backend selection for reqwest clients.
//!
//! Centralises the `#[cfg(target_os = "windows")]` / `#[cfg(not(target_os = "windows"))]`
//! guard so every HTTP-client construction site stays at one line and future
//! policy changes (e.g. adding native-tls on macOS) only require editing this file.
//!
//! # Policy
//! - **Windows**: `native-tls` (schannel) — honors the Windows certificate store,
//! including any corporate CA installed by AV / TLS-inspecting proxies that
//! re-sign certificates with a private root. `rustls` + webpki-roots only knows
//! Mozilla CAs and fails such environments with `UnknownIssuer`.
//! - **macOS / Linux**: `rustls` + webpki-roots — avoids the OpenSSL runtime
//! dependency on Linux and has historically been more reliable on macOS staging
//! TLS handshakes than `native-tls`.
/// Return a `reqwest::ClientBuilder` pre-configured with the platform-appropriate
/// TLS backend.
///
/// Use this as the starting point for every client that needs to reach external
/// HTTPS endpoints:
/// ```rust,ignore
/// let client = tls_client_builder()
/// .http1_only()
/// .timeout(Duration::from_secs(30))
/// .build()?;
/// ```
pub fn tls_client_builder() -> reqwest::ClientBuilder {
let b = reqwest::Client::builder();
#[cfg(target_os = "windows")]
let b = b.use_native_tls();
#[cfg(not(target_os = "windows"))]
let b = b.use_rustls_tls();
b
}