From 1e709d19d932d0b66c7696e57f662d678c283614 Mon Sep 17 00:00:00 2001 From: Jacob Stephens Date: Thu, 1 Oct 2026 14:58:21 +0000 Subject: [PATCH 1/2] Read the lockfile to keep OpenSSL out, not cargo tree offline cargo tree --target all --offline needs every platform's crates in the cargo cache, so the test failed on a cold cache: a new CI cache key, or a contributor's machine after a plain cargo test. The lockfile names every package for every target without touching the registry. It names dev-dependencies too, so the check is stricter than before. Co-Authored-By: Claude Opus 5.5 --- tests/packaging.rs | 96 +++++++++++++++++++++++++++++++++------------- 1 file changed, 69 insertions(+), 27 deletions(-) diff --git a/tests/packaging.rs b/tests/packaging.rs index 5e0352172..392fdbcc4 100644 --- a/tests/packaging.rs +++ b/tests/packaging.rs @@ -1,8 +1,10 @@ //! The crates.io package: it carries the sources and the Factory skills the //! binary embeds, and none of the repository's own agent tooling, docs, site -//! or tests. And the binary's dependencies: HTTPS through rustls, never -//! OpenSSL (ADR 0003). +//! or tests. And the binary's dependencies, as the lockfile names them: HTTPS +//! through rustls, never OpenSSL (ADR 0003). +use std::fs; +use std::path::Path; use std::process::Command; /// The paths `cargo package` would put in the crate. @@ -24,6 +26,28 @@ fn package_list() -> Vec { .collect() } +/// The packages in a lockfile that would link OpenSSL, as `name version`. +/// +/// The lockfile names every package for every target without touching the +/// registry, where `cargo tree --target all --offline` fails unless every +/// platform's crates are already in the cargo cache. It also names the +/// dev-dependencies, so this is stricter than ADR 0003's normal and build +/// dependencies: a test-only OpenSSL is caught too. +fn openssl_packages(lockfile: &str) -> Vec { + let lockfile: toml::Table = lockfile.parse().expect("the lockfile is not TOML"); + lockfile["package"] + .as_array() + .expect("the lockfile has no packages") + .iter() + .filter_map(|package| { + let name = package["name"].as_str().unwrap(); + ["openssl-sys", "openssl", "native-tls"] + .contains(&name) + .then(|| format!("{name} {}", package["version"].as_str().unwrap())) + }) + .collect() +} + #[test] fn package_leaves_out_the_repository_tooling() { for path in package_list() { @@ -60,30 +84,48 @@ fn package_carries_the_factory_skills_with_their_license_and_credits() { #[test] fn the_binary_never_links_openssl() { - let output = Command::new(env!("CARGO")) - .args([ - "tree", - "--edges", - "normal,build", - "--prefix", - "none", - "--format", - "{p}", - "--target", - "all", - "--offline", - ]) - .current_dir(env!("CARGO_MANIFEST_DIR")) - .output() - .expect("could not run cargo tree"); - assert!( - output.status.success(), - "stderr: {}", - String::from_utf8_lossy(&output.stderr) + let lockfile = fs::read_to_string(Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.lock")) + .expect("could not read Cargo.lock"); + let linked = openssl_packages(&lockfile); + assert!(linked.is_empty(), "{linked:?} are dependencies"); +} + +#[test] +fn a_lockfile_with_openssl_or_native_tls_in_it_is_caught() { + let lockfile = r#" +version = 4 + +[[package]] +name = "native-tls" +version = "0.2.14" +dependencies = [ + "openssl", + "openssl-probe", + "openssl-sys", +] + +[[package]] +name = "openssl" +version = "0.10.73" + +[[package]] +name = "openssl-probe" +version = "0.2.1" + +[[package]] +name = "openssl-sys" +version = "0.9.109" + +[[package]] +name = "rustls" +version = "0.23.31" +"#; + assert_eq!( + openssl_packages(lockfile), + [ + "native-tls 0.2.14", + "openssl 0.10.73", + "openssl-sys 0.9.109" + ] ); - for package in String::from_utf8(output.stdout).unwrap().lines() { - for linked in ["openssl-sys ", "openssl ", "native-tls "] { - assert!(!package.starts_with(linked), "{package} is a dependency"); - } - } } From 4aee651b8e161d00ef1bce922961e45aa02600bc Mon Sep 17 00:00:00 2001 From: Jacob Stephens Date: Thu, 1 Oct 2026 15:05:44 +0000 Subject: [PATCH 2/2] Address review: the normal and build scope is the old check's, not ADR 0003's Co-Authored-By: Claude Opus 5.5 --- tests/packaging.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/packaging.rs b/tests/packaging.rs index 392fdbcc4..00e227d1b 100644 --- a/tests/packaging.rs +++ b/tests/packaging.rs @@ -31,8 +31,9 @@ fn package_list() -> Vec { /// The lockfile names every package for every target without touching the /// registry, where `cargo tree --target all --offline` fails unless every /// platform's crates are already in the cargo cache. It also names the -/// dev-dependencies, so this is stricter than ADR 0003's normal and build -/// dependencies: a test-only OpenSSL is caught too. +/// dev-dependencies, so this is stricter than the binary's own normal and +/// build dependencies, which is all ADR 0003 needs: a test-only OpenSSL is +/// caught too. fn openssl_packages(lockfile: &str) -> Vec { let lockfile: toml::Table = lockfile.parse().expect("the lockfile is not TOML"); lockfile["package"]