rustd-resolved 0.2.1

A compatibility-oriented reimplementation of systemd-resolved
use std::path::Path;
use std::process::Command;

fn script(name: &str) -> std::path::PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests/parity")
        .join(name)
}

#[test]
fn parity_scripts_are_nonempty() {
    for s in [
        "stub_dig.sh",
        "nss_getent.sh",
        "resolv_conf_paths.sh",
        "check_dbus_abi.sh",
        "dnssec_ad_bit.sh",
        "dbus_manager_methods.sh",
        "split_dns_leak.sh",
        "dot_opportunistic.sh",
        "polkit_setlink.sh",
        "mdns_browse.sh",
        "llmnr_avahi_interop.sh",
        "networkd_split_dns.sh",
        "run_all.sh",
        "../release_feature_boundary.sh",
        "../ops_runtime_contract.sh",
    ] {
        let p = script(s);
        assert!(p.exists(), "missing {s}");
        let meta = std::fs::metadata(&p).unwrap();
        assert!(meta.len() > 40, "{s} still a stub");
    }
}

#[test]
fn parity_runner_does_not_ignore_dbus_failure_or_report_placeholder_success() {
    let runner = std::fs::read_to_string(script("run_all.sh")).expect("read parity runner");
    assert!(!runner.contains("check_dbus_abi.sh\" || true"));
    for required in [
        "dnssec_ad_bit",
        "dbus_manager_methods",
        "direct_root_privilege_drop",
    ] {
        assert!(
            runner.contains(required),
            "run_all.sh does not execute required gate {required}"
        );
    }

    let dnssec = std::fs::read_to_string(script("dnssec_ad_bit.sh")).expect("read DNSSEC gate");
    assert!(!dnssec.contains("inspect AD manually"));
    assert!(dnssec.contains("forged_ad_bit_never_authenticates_unsigned_answer"));
    assert!(dnssec.contains("anchored_chain_reaches_secure_without_trusting_ad"));

    let dbus = std::fs::read_to_string(script("dbus_manager_methods.sh")).expect("read D-Bus gate");
    assert!(dbus.contains("dbus-introspection.sh"));
    assert!(!dbus.contains("check_dbus_abi.sh"));

    let split_dns =
        std::fs::read_to_string(script("split_dns_leak.sh")).expect("read split DNS gate");
    assert!(!split_dns.contains("placeholder"));
    assert!(!split_dns.contains("SKIP"));
    assert!(split_dns.contains("longest_suffix_routes_to_the_matching_link"));

    let dot = std::fs::read_to_string(script("dot_opportunistic.sh")).expect("read DoT gate");
    assert!(!dot.contains("SKIP"));
    assert!(dot.contains("opportunistic_tls_failure_falls_back_to_plain_dns"));
    assert!(dot.contains("opportunistic_tls_accepts_untrusted_certificate_but_uses_sni"));

    let polkit = std::fs::read_to_string(script("polkit_setlink.sh")).expect("read PolicyKit gate");
    assert!(!polkit.contains("SKIP"));
    assert!(polkit.contains("dbus-introspection.sh"));

    let mdns = std::fs::read_to_string(script("mdns_browse.sh")).expect("read mDNS gate");
    assert!(!mdns.contains("SKIP"));
    assert!(mdns.contains("live-dnssd.py"));

    let avahi = std::fs::read_to_string(script("llmnr_avahi_interop.sh")).expect("read Avahi gate");
    assert!(!avahi.contains("SKIP"));
    assert!(!avahi.contains("LLMNR"));
    assert!(avahi.contains("avahi-daemon"));
    assert!(avahi.contains("avahi-browse"));
    assert!(avahi.contains("ip netns"));
    assert!(avahi.contains("mDNS/DNS-SD"));

    let networkd =
        std::fs::read_to_string(script("networkd_split_dns.sh")).expect("read networkd gate");
    assert!(!networkd.contains("SKIP"));
    assert!(networkd.contains("networkd_route_only_link_resolves_without_global_dns_leak"));

    let feature_boundary = std::fs::read_to_string(script("../release_feature_boundary.sh"))
        .expect("read release feature boundary gate");
    assert!(feature_boundary.contains("--locked"));
    assert!(feature_boundary.contains("supremacy"));
    assert!(feature_boundary.contains("certify-replacement-v2.sh"));
}

#[test]
#[ignore = "run with: cargo test -- --ignored (needs root/service)"]
fn boot_smoke_if_available() {
    let smoke = Path::new(env!("CARGO_MANIFEST_DIR")).join("scripts/boot-smoke.sh");
    if !smoke.exists() {
        return;
    }
    let st = Command::new("bash").arg(smoke).status().unwrap();
    assert!(st.success());
}