Trust the OS certificate store for engine HTTPS requests (#757) (#759)

The engine verified TLS against the Mozilla roots bundled through
webpki-roots only, so behind a TLS-inspecting proxy (Aikido, Zscaler,
Netskope) whose root lives in the OS trust store, `impeccable update`
and `install` failed with `invalid peer certificate: UnknownIssuer`
while curl and npm on the same machine succeeded.

crates/context/src/http.rs builds one rustls ClientConfig per process:
the OS trust store (rustls-native-certs: Keychain, Windows store, the
OpenSSL paths on Linux) merged with the bundled roots. A union, not a
replacement, so a container without ca-certificates or a store that
fails to load still verifies exactly as before. SSL_CERT_FILE and
SSL_CERT_DIR replace the OS store the way they do for OpenSSL and curl.
Every HTTPS call site (bundle and signature downloads, /api/version,
/api/commands, the roll API, image generation) builds its agent from
this module; the plain-HTTP live-server calls on localhost are
untouched.

Verified against a local HTTPS server signed by a throwaway CA: trusted
through SSL_CERT_FILE the update check reaches it; without it the same
server is rejected as UnknownIssuer; with SSL_CERT_FILE pointing at that
CA or at a missing file, impeccable.style still verifies through the
bundled roots. cargo test --workspace and the oracle corpus (832) pass.

Written with AI assistance (Claude Code).

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Abdul Wahab
2026-09-07 13:15:18 -07:00
committed by GitHub
co-authored by Claude Fable 5.1
parent 44e825090e
commit bd6964c35b
10 changed files with 193 additions and 6 deletions
+1 -1
View File
@@ -468,7 +468,7 @@ fn fetch_latest_skill_version(env: &Env) -> Option<String> {
.cloned()
.unwrap_or_else(|| "https://impeccable.style".to_string());
let host = host.strip_suffix('/').unwrap_or(&host).to_string();
let agent = ureq::AgentBuilder::new()
let agent = crate::http::agent_builder()
.timeout(std::time::Duration::from_millis(FETCH_TIMEOUT_MS))
.build();
let res = agent.get(&format!("{}/api/version", host)).call().ok()?;