Skip to content

feat(http): make the rustls crypto backend a feature - #2317

Merged
chaliy merged 1 commit into
mainfrom
claude/rustls-crypto-backend-feature-onlsat
Aug 19, 2026
Merged

chaliy merged 1 commit into
mainfrom
claude/rustls-crypto-backend-feature-onlsat

Conversation

@chaliy

@chaliy chaliy commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

What changed

Embedders can now choose which crypto backend bashkit's rustls HTTP client uses,
instead of inheriting ring unconditionally:

  • ring — the default, behavior identical to today
  • aws-lc-rs — for consumers who need a FIPS-capable backend, or who already
    link aws-lc-rs elsewhere and don't want two crypto libraries in one binary

http_client no longer implies a backend. ring wins when both features are
enabled, so Cargo's additive unification can never leave two providers racing
for the default slot. Building http_client with neither backend is a
compile_error! rather than a panic at the first TLS handshake.

Compatibility: additive. default = ["bash_tool", "ring"], so existing
consumers see the same provider and the same dependency tree. Consumers on
default-features = false must now name a backend alongside http_client;
in-tree, bashkit-cli names ring and bashkit-eval names it on its own
direct rustls dep.

Why

Because the backend was pinned in the dependency itself, a single crate
selecting rustls/ring pinned ring for its entire graph. Downstream trees
that also link aws-lc-rs ended up shipping both — roughly 800 KiB (~5.8%) of the
release everruns CLI in duplicated AES-GCM and P-256 code, plus two C/assembly
crypto libraries to track CVEs against, two FIPS stories, and a CryptoProvider
ambiguity each embedder had to resolve by hand.

bashkit had already done the hard part: it takes reqwest with
rustls-no-provider and installs the provider itself. Only the choice was
hard-coded, so this is a small change with real downstream leverage.

ring stays the default deliberately — it keeps the tree free of C-compiled
crypto, which is what keeps cross-compiled aarch64 manylinux wheel builds green
(aws-lc-sys trips over the missing AT_HWCAP2 in that cross sysroot).

This does not on its own remove ring from the everruns graph — ureq (via
rakers) pins it too and needs a separate upstream fix. This is the first and
most tractable step.

Before / After

Selecting a backend actually changes the tree. Before, no combination of
features could drop ring. After:

$ cargo tree -p bashkit --no-default-features --features http_client,aws-lc-rs -i ring
warning: nothing to print.

$ cargo tree -p bashkit --no-default-features --features http_client,aws-lc-rs -i aws-lc-sys
aws-lc-sys v0.44.0
└── aws-lc-rs v1.18.0
    └── rustls v0.23.43
        ├── bashkit v0.16.0
        └── hyper-rustls v0.27.9 → reqwest v0.13.4

The default set is unchanged — aws-lc-sys is still absent, exactly as before:

$ cargo tree -p bashkit --features http_client -i aws-lc-sys
error: package ID specification `aws-lc-sys` did not match any packages

A missing backend fails at build time, not at the first handshake:

$ cargo check -p bashkit --no-default-features --features http_client
error: bashkit's `http_client` needs a crypto backend: enable `ring` (default) or `aws-lc-rs`
   --> crates/bashkit/src/lib.rs:430:1

Both backends install a provider correctly (network::client suite, which
includes the provider-install regression and idempotency tests):

Feature set Result
default (ring) 27 passed, 0 failed
--no-default-features --features http_client,aws-lc-rs 27 passed, 0 failed

Risk

  • Low
  • The only way to break an existing consumer is default-features = false +
    http_client with no backend named — and that fails loudly at compile time
    with a message naming the fix, rather than silently changing TLS behavior.
  • CI's --all-features clippy/doc jobs now compile aws-lc-sys (builds clean
    locally; adds a few minutes to those two jobs). No new packages enter
    Cargo.lock — aws-lc-rs was already there with cargo-vet exemptions, so
    cargo deny / cargo vet are unaffected.

Checklist

  • Tests added or updated
  • Backward compatibility considered

http_client took rustls with `ring` hard-coded, so every consumer of
bashkit pinned `ring` for its whole dependency graph. Downstream trees
that also link aws-lc-rs ended up shipping two C/assembly crypto
libraries (~800 KiB and two CVE/FIPS stories in the everruns CLI).

The backend is now selected by feature: `ring` (default, unchanged
behavior) or `aws-lc-rs`. `http_client` no longer implies a backend;
`ring` wins when both are enabled, so Cargo's additive unification can
never leave two providers racing for the default slot, and building
`http_client` with neither is a compile_error! instead of a panic at the
first TLS handshake.

`ring` stays the default because it keeps the tree free of C-compiled
crypto, which is what keeps cross-compiled aarch64 manylinux wheel
builds green.

Consumers on --no-default-features must now name a backend alongside
http_client; in-tree, bashkit-cli names `ring` and bashkit-eval names it
on its own direct rustls dep.

Provider install and its regression tests are cfg'd per backend and pass
under both the default set and
`--no-default-features --features http_client,aws-lc-rs`.
@chaliy
chaliy merged commit d3209be into main Aug 19, 2026
46 checks passed
@chaliy
chaliy deleted the claude/rustls-crypto-backend-feature-onlsat branch August 19, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant