deps(observability): declare rustls roots stack for a shared TLS module [ skip ci ]

Merged
BN
6d ago
+10-0

Dependency/policy-only PR: Cargo.toml + Cargo.lock, no source. It declares the crate set a shared native TLS root loader needs in preloop-observability, and merges before the code PR that uses it.

Why preloop-observability at all

The same policy is implemented twice today:

  • crates/preloop-runner-server/src/shared_http.rs — bundled Mozilla roots (webpki-root-certs), the OS certificate store read on a detached thread with a 5 s deadline, and the PRELOOP_GITHUB_CA_FILE / SSL_CERT_FILE bundles; installed with reqwest's tls_certs_only (engine, CLI, orchestrator, runner-client).
  • crates/preloop-runner/src/client/tls.rs — the same three sources and the same 5 s deadline, re-expressed for the runner's rustls config (use_preconfigured_tls) because preloop-runner does not depend on preloop-runner-server.

A security-relevant root set living in two places is the failure mode: one side adds a source (or changes the deadline) and the other silently keeps verifying against something else. preloop-observability is the only crate both binaries already depend on, so it is where the single loader belongs. It needs rustls and friends declared first — hence this PR, and hence a code PR that touches no manifest.

The declared set

dependencykindwhy
rustls (feature ring)runtimeRootCertStore filtering of the OS-store entries and the ClientConfig the runner installs with use_preconfigured_tls; ring is the provider both crates already build (preloop-runner, preloop-runner-server declare rustls = { version = "0.23", features = ["ring"] }).
rustls-native-certsruntimeReads the OS store (securityd/trustd on macOS), behind the 5 s deadline. Already a workspace dependency.
webpki-root-certsruntimeThe bundled Mozilla anchors — already a workspace dependency (1.x, resolved in the lock via rustls-platform-verifier), and declared directly for preloop-runner-server by b39aceb61.
anyhowruntimeThe client-config helper's error type, which is what both existing call sites (preloop-runner's client::http and main) already return.
rcgendevSo the moved loader tests mint a CA and a localhost leaf in-process instead of shelling out to the openssl CLI. Already a workspace dev-dependency of preloop-runner-server.

webpki-root-certs, not webpki-roots 0.26

Both are Mozilla's store, but only one can serve both binaries from a single list:

  • webpki-root-certs exposes DER (CertificateDer<'static>) directly, which is exactly what reqwest's tls_certs_only takes (reqwest::Certificate::from_der), and rustls parses the same DER list with add_parsable_certificates for the preconfigured config. One list, both verifiers, byte-identical anchors.
  • webpki-roots exposes TrustAnchor, which cannot be fed to reqwest::Certificate::from_der — the engine side would keep a second code path (and a second root snapshot) purely to bridge types.
  • It is already in the tree for preloop-runner-server, so this consolidates on the crate that is already shipped rather than keeping two Mozilla snapshots in step.

That leaves preloop-runner's webpki-roots dependency unused once the code PR lands. Removing it is a separate policy PR, as the guard requires: on main today it is still used by the copy being deleted.

Policy files only

supply-chain/guard-policy-files.sh public/main HEAD:

Dependency/policy PR detected: OK
    - Cargo.lock
    - crates/preloop-observability/Cargo.toml

The rest of the guard's job also passes locally: cargo vet --locked (Succeeded), cargo audit (pre-existing yanked-crate warnings only), cargo deny check all (advisories ok, bans ok, licenses ok, sources ok).

No lockfile versions change — every crate above was already in the graph at the same version, so the Cargo.lock diff is one package's dependency list. cargo check -p preloop-observability --locked passes.

What merges next

The code PR ("refactor(observability): one native TLS root loader for the engine and the runner") is stacked on this branch, contains the new preloop_observability::tls module plus the deletion of both copies, and touches no policy file. Once this PR merges, that PR is rebased on main and the dependency commit cancels out.


Devin Review


Summary by cubic

Declares the rustls roots stack in preloop-observability ahead of a shared native TLS root loader that replaces the duplicate copies in preloop-runner-server and preloop-runner. Dependency/policy-only change: Cargo.toml and Cargo.lock, no source code.

Dependency set

  • Adds rustls (ring), rustls-native-certs, webpki-root-certs, and anyhow as runtime deps, plus rcgen as a dev dep for in-process test certificates.
  • webpki-root-certs is picked over webpki-roots because it exposes DER directly, which both reqwest's tls_certs_only and rustls' add_parsable_certificates consume, keeping a single anchor list for both binaries.
  • No lockfile versions change; every crate was already in the graph at the same version.

Summary by CodeRabbit

  • Chores
    • This update does not change any user-visible features or behavior. There are no new controls, workflows, or settings to report. Internal updates are not included in these release notes.