use std::collections::BTreeSet;
use std::process::Command;
const FORBIDDEN_CRATES: &[&str] = &[
"reqwest",
"hyper",
"hyper-util",
"h2",
"ureq",
"isahc",
"surf",
"attohttpc",
"curl",
"curl-sys",
"tiny_http",
"actix-web",
"axum",
"warp",
"rouille",
"tokio",
"async-std",
"smol",
"async-io",
"openssl",
"openssl-sys",
"native-tls",
"rustls",
"trust-dns-resolver",
"hickory-resolver",
"sentry",
"sentry-core",
"opentelemetry",
"tracing-opentelemetry",
"posthog",
"posthog-rs",
"segment",
"amplitude",
"mixpanel",
"datadog-apm",
"metrics-exporter-prometheus",
];
#[test]
fn no_networking_or_telemetry_crate_in_dependency_tree() {
let output = match Command::new(env!("CARGO"))
.args(["metadata", "--format-version", "1", "--locked"])
.output()
{
Ok(output) => output,
Err(err) => panic!("failed to run `cargo metadata`: {err}"),
};
assert!(
output.status.success(),
"`cargo metadata` failed:\n{}",
String::from_utf8_lossy(&output.stderr)
);
let meta: serde_json::Value = match serde_json::from_slice(&output.stdout) {
Ok(value) => value,
Err(err) => panic!("`cargo metadata` emitted invalid JSON: {err}"),
};
let packages = match meta["packages"].as_array() {
Some(packages) => packages,
None => panic!("`cargo metadata` output had no `packages` array"),
};
let names: BTreeSet<&str> = packages
.iter()
.filter_map(|pkg| pkg["name"].as_str())
.collect();
let hits: Vec<&str> = FORBIDDEN_CRATES
.iter()
.copied()
.filter(|crate_name| names.contains(crate_name))
.collect();
assert!(
hits.is_empty(),
"Phase 1 forbids networking/telemetry dependencies, but the resolved tree contains: {hits:?}.\n\
Costroid must read local logs only and make no network calls. If a later phase \
intentionally adds one of these, update this denylist and deny.toml together."
);
}