fix(http): switch rustls crypto provider to ring#1493
Merged
Conversation
Cross-compiled aarch64 manylinux wheel builds were failing inside PyO3/maturin-action's auto manylinux container with: aws-lc-sys-0.39.1/aws-lc/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c:27: error: 'AT_HWCAP2' undeclared `AT_HWCAP2` lives in glibc 2.18+ headers, but the manylinux2014 aarch64 cross sysroot ships glibc 2.17. aws-lc-sys 0.39.x began referencing it unconditionally, breaking the entire publish-python job after v0.2.0 was tagged. The other six wheel targets (linux x86_64, macOS x86/arm64, windows, musl x86/aarch64) were unaffected because they don't cross-compile through that container. Switch reqwest from `rustls` (which transitively pulls `__rustls-aws-lc-rs`, `aws-lc-rs`, and `aws-lc-sys` -- all C-compiled) to `rustls-no-provider`, then add a direct workspace dep on rustls 0.23 with `ring` enabled and install ring as the process-wide default provider before any reqwest client is built. After this change, `cargo tree -i aws-lc-sys` returns no match -- the C-compiled crypto stack is gone. ring is pure-Rust + asm and builds on every target we ship without a host toolchain dependency. Two sites must install the provider: - bashkit::network::client::build_client (under `http_client`, feeds bashkit-cli, bashkit-python via bashkit-cli, etc.) - bashkit-eval main, which uses reqwest directly without going through bashkit's http_client feature Both go through an idempotent `Once` guard so the install is crash-safe across multiple call sites and re-entry. Tests: - new test_build_client_installs_ring_crypto_provider asserts that after `build_client`, a second `install_default()` returns Err -- proving the first install succeeded - new test_install_default_crypto_provider_is_idempotent confirms multiple calls don't panic - existing 14 client tests still pass under --features http_client Verified locally: - cargo build --workspace - cargo fmt --check - cargo clippy --workspace --all-targets -- -D warnings - cargo test -p bashkit --lib --features http_client client (16 passed, 0 failed) - cargo tree -i aws-lc-sys -> "did not match any packages" - cargo tree -i ring -> ring v0.17.14 used by all 5 bashkit-* crates
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bashkit | 7f61c8b | Commit Preview URL Branch Preview URL |
Apr 30 2026, 04:38 PM |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
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.
Summary
The aarch64 manylinux wheel build for v0.2.0 failed with a C compile error in the
aws-lc-syscrate:AT_HWCAP2lives in glibc 2.18+ headers, but themanylinux2014aarch64 cross sysroot baked into PyO3/maturin-action's auto container ships glibc 2.17.aws-lc-sys0.39.x began referencing the constant unconditionally, breaking the entirepublish-python.ymljob after the v0.2.0 tag was created. The other six wheel targets (linux x86_64, macOS x86/arm64, windows, musl x86/aarch64) were unaffected because they don't cross-compile through that container.Worse,
aws-lc-sysis pulled in transitively byreqwest'srustlsfeature, so this regression could surface again any time the cross-sysroot vs. aws-lc-sys minimum-glibc gap shifts.Fix
Drop the C-compiled crypto stack entirely:
reqwestfromrustls(which transitively activates__rustls-aws-lc-rs→aws-lc-rs→aws-lc-sys) torustls-no-provider.rustls = "0.23"with theringfeature.ringas the process-wide defaultCryptoProviderbefore any reqwest client is built. ring is pure-Rust + asm and builds on every target we ship without a host toolchain dependency.After this change:
Two install sites
The provider has to be installed before the first TLS handshake. Two places do this:
bashkit::network::client::build_client(under thehttp_clientfeature) — feedsbashkit-cli,bashkit-python, anything embedding bashkit with HTTP enabled.bashkit-evalmain— this binary usesreqwestdirectly without going through bashkit'shttp_clientfeature, so it can't piggyback on the helper above.Both call paths go through an idempotent
Onceguard, so multiple invocations across crates and re-entrant code are safe.install_defaultreturnsErrafter a provider is already present; we treat that as success because some provider is now active, which is all rustls needs.Why this regressed silently
PR CI runs
cargo build/cargo testonubuntu-latest(x86_64) only. The aarch64 cross-compile path only fires insidepublish-python.yml, which runs onrelease: published. So the bad combination rode all the way to the v0.2.0 GitHub Release.Test coverage
Added in
crates/bashkit/src/network/client.rs:test_build_client_installs_ring_crypto_provider— callsbuild_client, then asserts a secondinstall_default()returnsErr. That's the proof the first install succeeded — exactly the invariant we need to keep TLS from panicking on first use.test_install_default_crypto_provider_is_idempotent— multiple direct invocations don't panic; theOnceguard works.The 14 existing client tests under
--features http_clientcontinue to pass — none of them needed adjustment.The actual end-to-end verification is the
publish-python.ymlaarch64 manylinux build itself, which can be re-dispatched against the v0.2.0 GitHub Release once this lands on main (no version bump needed).Test plan
cargo fmt --checkcargo clippy --workspace --all-targets -- -D warningscargo test -p bashkit --lib --features http_client client(16 passed)cargo tree -i aws-lc-sysreturns "did not match any packages"cargo tree -i ringshows ring as the sole crypto in all bashkit-* cratespublish-python.ymlfor v0.2.0 and confirm aarch64 wheel builds + PyPI publishesCoordination with #1492
This PR is independent of #1492 (Windows mount path fix). After both merge, we can re-run
publish-python.ymlandpublish-js.ymlagainst the existingv0.2.0GitHub Release to push the missing wheels and npm package without cutting a new version.Generated by Claude Code