From 3eee34d194319b6a46e3d8aa5cd4c774e35f053a Mon Sep 17 00:00:00 2001 From: Joern Barthel Date: Mon, 10 Aug 2026 12:18:27 +0200 Subject: [PATCH 1/3] chore: added option to build reqwest without rustls provider --- Cargo.lock | 2 ++ Cargo.toml | 9 +++++++-- tests/test_tls_no_provider.rs | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/test_tls_no_provider.rs diff --git a/Cargo.lock b/Cargo.lock index 91d7f8d..bdce941 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2000,6 +2000,7 @@ dependencies = [ "os_info", "regex", "reqwest", + "rustls", "semver", "serde", "serde_json", @@ -2277,6 +2278,7 @@ checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "aws-lc-rs", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", diff --git a/Cargo.toml b/Cargo.toml index bf2fed2..9806fac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ rust-version = "1.78.0" [dependencies] reqwest = { version = "0.13.2", default-features = false, features = [ - "rustls", "blocking", "json", "gzip", @@ -39,6 +38,10 @@ zstd = { version = "0.13", optional = true } [dev-dependencies] dotenv = "0.15.0" +rustls = { version = "0.23", default-features = false, features = [ + "ring", + "std", +] } ctor = "1.0.12" tokio = { version = "1", features = ["full"] } httpmock = "0.7" @@ -48,12 +51,14 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } eyre = "0.6.12" [features] -default = ["async-client", "error-tracking"] +default = ["async-client", "error-tracking", "tls"] e2e-test = [] async-client = ["tokio"] capture-v1 = ["brotli", "zstd"] test-harness = [] error-tracking = ["dep:backtrace", "dep:findshlibs"] +tls = ["reqwest/rustls"] +tls-no-provider = ["reqwest/rustls-no-provider"] [workspace] members = [".", "compliance/adapter"] diff --git a/tests/test_tls_no_provider.rs b/tests/test_tls_no_provider.rs new file mode 100644 index 0000000..1923782 --- /dev/null +++ b/tests/test_tls_no_provider.rs @@ -0,0 +1,37 @@ +#![cfg(feature = "tls-no-provider")] +//! Bring-your-own-provider TLS: with `tls-no-provider` (and without `tls`) +//! the SDK links no rustls crypto provider, so the application must install +//! a process-level provider before constructing a client. reqwest builds its +//! TLS connector at client construction time and panics inside rustls if no +//! provider is available, so successfully constructing a client is the +//! regression check here. + +use posthog_rs::{ClientOptions, ClientOptionsBuilder}; + +fn install_ring_provider() { + // Ignore the result: `install_default` errs if a process-level provider + // is already installed (e.g. by another test in this binary). + let _ = rustls::crypto::ring::default_provider().install_default(); +} + +fn options() -> ClientOptions { + ClientOptionsBuilder::default() + .api_key("phc_test_token".to_string()) + .host("https://eu.i.posthog.com".to_string()) + .build() + .unwrap() +} + +#[cfg(not(feature = "async-client"))] +#[test] +fn blocking_client_builds_with_installed_provider() { + install_ring_provider(); + let _client = posthog_rs::client(options()); +} + +#[cfg(feature = "async-client")] +#[tokio::test] +async fn async_client_builds_with_installed_provider() { + install_ring_provider(); + let _client = posthog_rs::client(options()).await; +} From 4cb4c5f38d3eeeb14f1a34d9c38e22be31a7e019 Mon Sep 17 00:00:00 2001 From: Joern Barthel Date: Mon, 10 Aug 2026 12:18:52 +0200 Subject: [PATCH 2/3] chore: test in ci that tls-no-provider actually works --- .github/workflows/ci.yaml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 33bd9f0..04de3ca 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -87,6 +87,12 @@ jobs: toolchain: stable cache-key: capture-v1 command: cargo build --verbose --features capture-v1 + - name: tls-no-provider + toolchain: stable + cache-key: tls-no-provider + command: >- + cargo build --verbose --no-default-features --features async-client,error-tracking,capture-v1,tls-no-provider + && ! cargo tree --package posthog-rs --edges normal --invert aws-lc-sys --no-default-features --features async-client,error-tracking,capture-v1,tls-no-provider steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -165,9 +171,15 @@ jobs: - name: Unit test (error-tracking + capture-v1, blocking client) cache-key: error-tracking-capture-v1-blocking-client command: cargo test --verbose --no-default-features --features error-tracking,capture-v1 + # Targeted at the tls-no-provider test binary only: without a + # built-in provider, constructing a client panics unless the test + # installs one first, so the rest of the suite cannot run here. + - name: Unit test (tls-no-provider, blocking client) + cache-key: tls-no-provider-blocking-client + command: cargo test --verbose --no-default-features --features tls-no-provider --test test_tls_no_provider - name: E2E test cache-key: e2e - command: cargo test --verbose --features e2e-test --no-default-features + command: cargo test --verbose --features e2e-test,tls --no-default-features steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 From 0420c076c0de8ce1e747e27f8887fc6bb2a9b99b Mon Sep 17 00:00:00 2001 From: Joern Barthel Date: Mon, 10 Aug 2026 12:31:32 +0200 Subject: [PATCH 3/3] chore: added changeset --- .sampo/changesets/virtuous-guardian-sampsa.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .sampo/changesets/virtuous-guardian-sampsa.md diff --git a/.sampo/changesets/virtuous-guardian-sampsa.md b/.sampo/changesets/virtuous-guardian-sampsa.md new file mode 100644 index 0000000..6d40f51 --- /dev/null +++ b/.sampo/changesets/virtuous-guardian-sampsa.md @@ -0,0 +1,11 @@ +--- +cargo/posthog-rs: minor +--- + +TLS backend selection is now a feature choice. `reqwest/rustls` was previously listed unconditionally on the dependency line, so every consumer compiled and linked `aws-lc-rs` -> `aws-lc-sys` with no way to opt out. Two features now control this: `tls` (enabled by default) keeps rustls with reqwest's built-in aws-lc-rs provider, and `tls-no-provider` links rustls with no crypto provider so an application can supply its own. + +Applications that already install a rustls `CryptoProvider` gained nothing from the linked one — rustls resolves the process-level provider before consulting crate features, so an app calling `ring::default_provider().install_default()` already used ring at runtime while still building and linking aws-lc-rs. `tls-no-provider` drops `aws-lc-sys` from the tree entirely, removing the C/assembly build dependency (C toolchain, cmake, nasm on some targets) that complicates cross-compilation, musl targets, and minimal build containers. + +With `tls-no-provider` the application MUST install a process-level provider before constructing a client; reqwest builds its TLS connector at construction time and rustls panics if no provider is available. Cargo features are additive, so `tls-no-provider` only takes effect when nothing in the dependency graph enables `tls`. + +Default users are unaffected — `tls` is in `default` and behavior is unchanged. **Breaking for `default-features = false` consumers:** TLS is no longer implied, so add `tls` (or `tls-no-provider`) explicitly. Without either, the build succeeds but HTTPS requests fail at runtime with `invalid URL, scheme is not http`.