allow-policy-legacy 0.1.9

Legacy policy adapters for cargo-allow migrations.
Documentation
use allow_core::{CargoAllowError, CargoAllowResult};
use std::fs;
use std::path::Path;

pub(crate) fn read_policy(path: &Path) -> CargoAllowResult<String> {
    fs::read_to_string(path).map_err(|e| {
        CargoAllowError::new(format!(
            "failed to read legacy policy {}: {e}",
            path.display()
        ))
    })
}

pub(crate) fn legacy_table(input: &str) -> CargoAllowResult<Option<toml::Table>> {
    toml::from_str::<toml::Table>(input)
        .map(Some)
        .map_err(|e| CargoAllowError::new(format!("failed to parse legacy policy TOML: {e}")))
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;
    use std::time::{SystemTime, UNIX_EPOCH};

    #[test]
    fn read_policy_returns_file_text_or_contextual_error() {
        let path = temp_policy_path("read-policy");
        fs::write(&path, "policy = \"non-rust-allowlist\"\n")
            .unwrap_or_else(|err| std::panic::panic_any(format!("fixture write: {err}")));

        let text = read_policy(&path)
            .unwrap_or_else(|err| std::panic::panic_any(format!("policy reads: {err}")));

        assert_eq!(text, "policy = \"non-rust-allowlist\"\n");
        fs::remove_file(&path)
            .unwrap_or_else(|err| std::panic::panic_any(format!("fixture cleanup: {err}")));

        let err = read_policy(&path).expect_err("missing policy should produce read error");
        assert!(err.to_string().contains("failed to read legacy policy"));
        assert!(err.to_string().contains(&path.display().to_string()));
    }

    #[test]
    fn legacy_table_parses_toml_or_reports_parse_error() {
        let table = legacy_table("policy = \"workflow-allowlist\"\n")
            .unwrap_or_else(|err| std::panic::panic_any(format!("legacy TOML parses: {err}")))
            .unwrap_or_else(|| std::panic::panic_any("legacy table exists"));

        assert_eq!(
            table.get("policy").and_then(toml::Value::as_str),
            Some("workflow-allowlist")
        );

        let err = legacy_table("policy = [").expect_err("invalid TOML should fail");
        assert!(
            err.to_string()
                .contains("failed to parse legacy policy TOML")
        );
    }

    fn temp_policy_path(name: &str) -> std::path::PathBuf {
        let unique = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap_or_else(|err| std::panic::panic_any(format!("system clock ok: {err}")))
            .as_nanos();
        std::env::temp_dir().join(format!(
            "cargo-allow-{name}-{}-{unique}.toml",
            std::process::id()
        ))
    }
}