fix(marmel): bump to 3f238ff, give e2e child a trust store
CI / check (push) Has been cancelled

Track main at 3f238ff (per-role reasoning_effort, #12), 21 commits past
d6627d7 ("1.0.0 (#6)"). cargoHash is unchanged: Cargo.lock is identical
across that range, so the vendored tree is byte-for-byte the same.

The new tests/test_session_boot.rs spawns the real binary with
env_clear(), which drops SSL_CERT_FILE. rustls-native-certs is then left
with a fixed list of /etc paths to probe, none of which exist in the Nix
sandbox, so the child dies in reqwest::Client::new() and four exit-code
assertions observe the panic's 101. The patch forwards the runner's
SSL_CERT_FILE to the child and leaves every assertion intact.

The underlying defect is upstream's rather than Nix's:
src/llm/client.rs builds its client with unwrap_or_default() on a
Result<Client, reqwest::Error>, and reqwest's Client::default() is
Client::new(), which repeats the same build and .expect()s it. The
fallback can therefore never recover; it turns a reportable "no CA
certificates" error into a panic. Reproduced on a stock busybox image
with no /etc/ssl at all, so it hits any minimal container, not just
sandboxed builds.

Tested: 1251 tests pass across 31 targets, 0 failures.
This commit is contained in:
2026-10-16 14:32:15 +03:00
parent 0813f55762
commit 892f30e82a
2 changed files with 55 additions and 7 deletions
@@ -0,0 +1,43 @@
Give the env-cleared child process a trust store.
run_marmel() wipes the child environment so the binary under test cannot
inherit the runner's MARMEL_* variables or its terminal. reqwest's TLS stack
is rustls-native-certs, which reads SSL_CERT_FILE / SSL_CERT_DIR and then the
well-known /etc paths, so where no system trust store exists at all the child
dies inside reqwest::Client::new() ("No CA certificates were loaded from the
system") before it ever reads the bundle. Four cases in this file assert the
CLI's exit codes and stderr, and they then observe the panic's 101 instead.
Forward the test runner's SSL_CERT_FILE when it has one. On a normal Linux
host the child picks the trust store up from /etc as before, so the assertions
themselves are unchanged.
This is a workaround, not the real fix. The panic should not happen at all:
src/llm/client.rs builds the client with unwrap_or_default() on a
Result<Client, reqwest::Error>, and reqwest's Client::default() is
Client::new(), which repeats the same build and .expect()s it, so the fallback
can never recover. Upstream was told; drop this patch once the error is
propagated instead of discarded.
--- a/tests/test_session_boot.rs
+++ b/tests/test_session_boot.rs
@@ -221,8 +221,17 @@
let err_file = std::fs::File::create(&err_path).expect("stderr file");
let mut cmd = Command::new(env!("CARGO_BIN_EXE_marmel"));
- cmd.current_dir(dir)
- .env_clear()
+ cmd.current_dir(dir).env_clear();
+ // rustls-native-certs reads SSL_CERT_FILE / SSL_CERT_DIR, both of which the
+ // env_clear() above drops, so when no system trust store can be probed
+ // either the child dies inside reqwest::Client::new() ("No CA certificates
+ // were loaded from the system") before it ever reaches the bundle, and the
+ // exit-code assertions below then see the panic's 101. Forward the runner's
+ // value when it has one; the assertions themselves are untouched.
+ if let Some(trust_store) = std::env::var("SSL_CERT_FILE").ok().filter(|p| !p.is_empty()) {
+ cmd.env("SSL_CERT_FILE", trust_store);
+ }
+ cmd
// A minimal, deterministic environment: the binary must not inherit the
// test runner's `MARMEL_*` variables or its terminal.
.env("PATH", "/usr/bin:/bin")