fix(boot): install rustls CryptoProvider to prevent rc.8 panic on first TLS call#143
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 PR installs an explicit rustls
Confidence Score: 4/5Safe to merge — the fix correctly installs the ring CryptoProvider before any TLS connection and directly resolves the rc.8 boot panic. The fix is minimal and targeted: one function call at the top of No files require special attention. The Cargo.toml choice to make Important Files Changed
Sequence DiagramsequenceDiagram
participant main
participant loginit as logging::init
participant icp as install_crypto_provider
participant rustls
participant initsentry as init_sentry
participant tlssentry as sentry transport TLS
participant tlsreqwest as reqwest pool TLS
main->>loginit: init(mode, verbose)
loginit->>icp: install_crypto_provider()
icp->>rustls: ring::default_provider().install_default()
rustls-->>icp: Ok or Err ignored
icp-->>loginit: return
loginit->>initsentry: init_sentry()
initsentry->>tlssentry: sentry::init first TLS handshake
tlssentry->>rustls: pick CryptoProvider
rustls-->>tlssentry: ring installed no panic
loginit-->>main: InitGuards
main->>tlsreqwest: first HTTP request
tlsreqwest->>rustls: pick CryptoProvider
rustls-->>tlsreqwest: ring consistent
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.
rustls dep is unconditional — not gated on the sentry feature
The panic only manifests when --features sentry is active (that's the build that pulls both ring via reqwest 0.12 and aws-lc-rs via sentry's reqwest 0.13 → rustls-platform-verifier). Without sentry, the dep graph contains only ring, and rustls 0.23 auto-selects it without panicking. Adding rustls as an always-on direct dep (and always calling install_default() from init()) is harmless — ring was already transitively present — but it permanently widens the explicit dep surface for all build profiles. Consider gating it alongside the sentry feature: rustls = { ..., optional = true } and adding "dep:rustls" to the sentry feature entry in [features].
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!
The bug
rc.8 ships with the `--features sentry` binary panicking at first TLS connection. Live event in Sentry: BACKEND-TEST-2RH, level fatal, 2 events under release 0.8.0-rc.8.
```
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.
```
Root cause
Dual rustls crypto backend 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 backends linked, refuses to auto-pick, and panics on the first TLS handshake.
The default-features binary doesn't hit this because the sentry dep is gated and reqwest 0.13 + rustls-platform-verifier never get pulled.
Fix
```rust
rustls::crypto::ring::default_provider().install_default()
```
Called once at the very start of `logging::init()`, before any TLS client is built (sentry transport, reqwest pools, 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 pulls ring). `install_default()` returns Err if 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:
Test suite under `--features sentry`:
```
cargo test --features sentry → 1256 passed / 0 failed
cargo clippy --features sentry --lib --tests -- -D warnings → clean
cargo fmt --all --check → clean
```
After this lands
Sister files
The race fix from PR #141's Greptile review is still orphaned on the now-merged `fix/lazy-schema-discovery` branch as commit `f1f7809`. Not included here — that's a separate P2 worth its own small PR.
🤖 Generated with Claude Code