Repository navigation
Trust the OS store and SSL_CERT_FILE for HTTPS (#1107) - #1326
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every HTTPS call (patch API, public proxy, blob and registry fetches, telemetry, self-update) trusted only the bundled Mozilla roots. Behind a TLS-inspecting corporate proxy, whose private CA no setting could add, every request failed with UnknownIssuer. All production reqwest clients are now built by one constructor, utils::http::client_builder(), which adds the platform trust store to the bundled roots. rustls-native-certs reads the macOS keychain, the Windows store or the Linux bundle, and honors SSL_CERT_FILE and SSL_CERT_DIR. The store is read once per process and unusable roots are skipped. Verification is never relaxed. Tests run a local TLS server signed by a private CA: the handshake succeeds only when SSL_CERT_FILE names that CA. A text ratchet keeps new reqwest::Client constructors out of production code. Fixes #1107 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 9, 2026 17:38
Collaborator
Author
|
BugBot review |
Mikola Lysenko (mikolalysenko)
enabled auto-merge
October 9, 2026 17:38
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c510914. Configure here.
CI's scan benchmark showed 5-10 ms more CPU per run: every process read the whole platform store (hundreds of PEM files on Linux) and every client re-parsed those roots. client_builder() now hands reqwest one shared rustls config, built once per process. Its verifier checks the bundled webpki roots first and reads the platform store (or SSL_CERT_FILE / SSL_CERT_DIR) only after an UnknownIssuer, then once per process. Other verification errors are returned unchanged, so trust is still the union of both sets and verification is never relaxed. Building a client no longer parses any roots. The load-error log line flagged by CodeQL is gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Tanmay Singla (Tanmay182003)
approved these changes
Oct 9, 2026
Collaborator
Author
|
Ready for review at
Labeled Generated by Claude Code |
Mikola Lysenko (mikolalysenko)
removed this pull request from the merge queue due to a manual request
Oct 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1107
Summary
Every HTTPS client now trusts the bundled Mozilla (webpki) roots plus the platform trust store, so socket-patch works behind a TLS-inspecting corporate proxy whose CA the OS (or
SSL_CERT_FILE) trusts. Certificate verification is never disabled.Root cause
The workspace builds reqwest with
rustls-tlsonly, which in reqwest 0.12 means the bundled webpki roots. No production client builder added any other root, so neither the OS store norSSL_CERT_FILE/SSL_CERT_DIRwas ever read. Every API, blob, registry, telemetry and self-update call failed withUnknownIssuerbehind an inspecting proxy, while curl/npm/pip in the same environment worked.Changes
utils::http::client_builder()in core: the one constructor for production reqwest clients. It hands reqwest one shared rustlsClientConfig(built once per process; ring provider, TLS 1.2/1.3, HTTP/1.1 ALPN) whose verifier,BundledThenPlatform, runs full webpki verification against the bundled roots first and, only onUnknownIssuer, against the platform roots loaded byrustls-native-certs(macOS keychain, Windows store, Linux bundle;SSL_CERT_FILE/SSL_CERT_DIRwhen set).add_parsable_certificates); an empty or unreadable store leaves the bundled roots.api/client.rs), telemetry, self-update metadata and download, and the vendored registry client (vendor/registry_fetch.rs, which also backs the upstream-restore client). The registry client's silentreqwest::Client::new()fallback (which would have bypassed the roots) is now anexpect, matching the API client.rustls-native-certs =0.8.4(new: plusopenssl-probe,security-frameworkon macOS,schannelon Windows);rustls(std,ring,tls12) andwebpki-rootsare the exact builds reqwest'srustls-tlsalready compiles. Dev-only:tokio-rustls(already in the lockfile,ringprovider) for the local TLS server.CLI_CONTRACT.md(next to theHTTPS_PROXYsentence) anddocs/configuration.mdstate how trust roots are chosen.Tests (per acceptance criterion)
SSL_CERT_FILEcompletes a handshake with a local TLS server whose leaf it signed, and the platform store is read exactly once across two requests:utils::http::tests::client_trusts_a_private_ca_named_by_ssl_cert_file.UnknownIssuer(verification stays on):client_without_the_private_ca_fails_with_unknown_issuer.unparsable_platform_roots_are_skipped_not_fatal.build()):production_builder_builds. Also checked live: the debug binary'sget <uuid> --jsonagainst the real public proxy completes (webpki path).no_client_is_built_outside_client_builderscans core/cli/nodesrc(test modules excluded) forClient::builder(/Client::new(/ClientBuilder::new(. Red before the fix: it listed the 7 production sites (api client ×2, telemetry, update release/download, registry_fetch ×2); green after.crates/socket-patch-core/tests/tls-ca/(P-256 CA + 127.0.0.1 leaf, valid 100 years). Kept out oftests/fixtures/because the VEX discovery golden corpus walks every directory there.Commands run
cargo test -p socket-patch-core --all-features --no-fail-fast: all 39 test binaries green.cargo test -p socket-patch-cli --all-features --test update --test get --test scan_api_retry_e2e --test self_update_e2e --test self_update_failures_e2e --test remove_rollback_api_overrides: 211 passed.cargo clippy --workspace --all-features -- -D warnings: clean.cargo fmt --all -- --check: only a pre-existing diff inpatch/redirect/upstream/mod.rs(untouched here).🤖 Generated with Claude Code
Generated by Claude Code