fix(boot): install rustls CryptoProvider to prevent panic on first TLS call [0.7 backport]#144
Conversation
…anic
rc.8 ships with the --features sentry binary panicking at first TLS
connection:
panic: Could not automatically determine the process-level
CryptoProvider from Rustls crate features. Call
CryptoProvider::install_default() before this point to select a
provider manually, or make sure exactly one of the 'aws-lc-rs' and
'ring' features is enabled.
Sentry issue BACKEND-TEST-2RH, 2 events, release 0.8.0-rc.8.
Root cause is a dual-crypto-backend link in the dep graph that the
--features sentry build triggers:
rustls 0.23.37 enables 'ring' AND 'aws-lc-rs' features
├── ring ← jsonwebtoken, reqwest 0.12 (our direct dep, rustls-tls)
└── aws-lc-rs ← rustls-platform-verifier 0.6.2
└── reqwest 0.13.2
└── sentry 0.47 (via 'rustls' feature)
The 'rustls' feature on the sentry crate (which we enable in #137's
expanded feature list) routes to reqwest 0.13 internally, which pulls
rustls-platform-verifier → aws-lc-rs. Our own reqwest 0.12 pulls ring.
rustls 0.23 sees both, refuses to auto-pick, and panics on the first
handshake.
Fix:
rustls::crypto::ring::default_provider().install_default()
Called once at the very start of `logging::init()`, before any TLS
client is built (sentry's transport, reqwest pools, the proxy's
auth_generator, MCP HTTP transport). Pinned to `ring` because that's
the backend the rest of the binary already uses (jsonwebtoken signs
with ring; reqwest's rustls-tls feature pulls ring). install_default()
returns Err if a provider was already installed — we discard that
result; first installer wins, both backends implement the same TLS
standards, what matters is consistency at the process level.
Verification:
End-to-end smoke against a live proxy built with --features sentry,
pointed at the same Sentry DSN that produced the rc.8 panic:
✓ Proxy boots clean (no panic, no CryptoProvider error in log)
✓ /health → 200 OK with rc.8 version
✓ /tools → 200 OK, manifest loaded
✓ /call → real TLS handshake to https://httpbin.org/get, 200 OK
✓ Sentry batcher flushed 8 log items + 3 events to
o4506617108561920.ingest.us.sentry.io, all returned event IDs
✓ Proxy stayed alive across 4 TLS roundtrips + Sentry flushes
✓ Zero matches for panic|CryptoProvider|aws-lc|FATAL in proxy log
Full test suite under --features sentry: 1256 passed / 0 failed.
cargo clippy --features sentry --lib --tests -- -D warnings clean.
cargo fmt --all --check clean.
This bug was latent in v0.7.14 / v0.7.15 too (same sentry feature
set). Will be backported to release/0.7 in a separate PR if those
binaries are still in service.
Greptile SummaryThis is a 0.7.x backport of the rustls
Confidence Score: 4/5Safe to merge — the fix correctly resolves the boot-time TLS panic that affects all sentry-enabled 0.7.x binaries today. The core fix (pinning the rustls ring provider before any TLS use) is the canonical approach for this rustls 0.23 dual-backend problem and is applied at the right point in the boot sequence. The one open question is whether the direct rustls dep and the install call should be gated behind the sentry feature flag, since the conflict only arises in sentry builds — leaving them unconditional is harmless but slightly inflates the non-sentry dep surface. No logic errors or correctness issues in the changed code. Cargo.toml — the unconditional rustls dep is worth a second look to confirm the team is happy with it being present in non-sentry builds. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[main] --> B[logging::init]
B --> C[install_crypto_provider]
C --> D[rustls ring default_provider install_default]
D -->|Ok - first caller wins| E[Provider set to ring]
D -->|Err - already installed| E
E --> F[init_sentry]
F -->|sentry feature on| G[sentry::init via reqwest 0.13]
F -->|sentry feature off| H[None]
G --> I[Build tracing subscriber]
H --> I
I --> J[Application TLS connections]
J --> K[rustls reads ring provider - no panic]
subgraph Without this fix
L[First TLS call] --> M{Auto-detect provider}
M -->|ring AND aws-lc-rs both linked| N[PANIC: Could not determine CryptoProvider]
end
Reviews (1): Last reviewed commit: "fix(boot): install rustls CryptoProvider..." | Re-trigger Greptile |
| # (matches the `ring` backend the rest of the binary uses via | ||
| # jsonwebtoken + reqwest's rustls-tls feature). Single-binary fix — | ||
| # no Cargo.lock surgery needed. rc.8 panic root cause. | ||
| rustls = { version = "0.23", default-features = false, features = ["ring", "std"] } |
There was a problem hiding this comment.
Unconditional rustls dep widens the footprint of non-sentry builds
The dual-backend conflict (ring + aws-lc-rs) only materialises when --features sentry is used, because that's the only path that transitively pulls in aws-lc-rs (via sentry's reqwest 0.13 → rustls-platform-verifier). The direct rustls dep and the install_crypto_provider() call in logging.rs are therefore both added to every build regardless of the sentry feature flag.
In practice the impact is minimal — rustls is already compiled in transitively via reqwest's rustls-tls feature, so the added binary size is near-zero. But the intent is clearer and the dep graph is cleaner if both the dep and the call are gated behind sentry. That said, the unconditional approach is a valid defensive choice — if another future dependency ever pulls in aws-lc-rs in a non-sentry build, the provider will already be pinned. Worth a deliberate decision either way.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Summary
0.7.x backport of #143 (the rustls CryptoProvider fix). v0.7.14 / v0.7.15 ship with the same dual-backend problem because the Sentry-feature expansion landed there too. Any 0.7.x binary built with `--features sentry` panics on its first TLS connection.
```
panic: Could not automatically determine the process-level
CryptoProvider from Rustls crate features. Call
CryptoProvider::install_default() before this point to select a
provider manually, or make sure exactly one of the 'aws-lc-rs' and
'ring' features is enabled.
```
The bug is latent on 0.7.14 / 0.7.15 — same dep graph as rc.8 (sentry 0.47 + rustls 0.23 + both `ring` and `aws-lc-rs` linked transitively). The fix is identical: `rustls::crypto::ring::default_provider().install_default()` at the very start of `logging::init()`.
Conflict resolution
Clean cherry-pick of `99533ca` (the main-branch fix). All three files (`Cargo.toml`, `Cargo.lock`, `src/core/logging.rs`) auto-merged.
Tests
```
cargo test → 977/977 green
cargo test --features sentry → 582 passed + 1 known-flake (test_cli_output_args_named_flag_captures_file passes serially; same parallel-test race noted on PR #141 — unrelated to this fix)
cargo clippy --features sentry --lib --tests -- -D warnings → clean
cargo fmt --all --check → clean
```
The cli_executor_test flake hits the exact same test that was flaky on PRs #138 and #141, and runs through
--test-threads=1cleanly. My fix only toucheslogging.rs+Cargo.toml; the flaky test exercises CLI executor file-handling and is unrelated.After this lands
Sister PR
🤖 Generated with Claude Code