//! Release-package, native-binary, and clean-room runtime audit.

#![allow(clippy::too_many_lines)]

use super::{MatrixError, Result};
use flate2::read::GzDecoder;
use goblin::{Object, mach};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::{BTreeMap, BTreeSet};
use std::ffi::OsStr;
use std::fmt::Write as _;
use std::fs::{self, OpenOptions};
use std::io::{Read, Write};
use std::path::{Component, Path, PathBuf};
use std::process::{Command, Stdio};
use std::thread;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use tar::Archive;

const POLICY_PATH: &str = "ci/artifact-policy.json";
const MAX_ARCHIVE_BYTES: u64 = 256 * 1024 * 1024;
const MAX_ENTRY_BYTES: u64 = 128 * 1024 * 1024;
const MAX_BINARY_BYTES: u64 = 512 * 1024 * 1024;
const SMOKE_TIMEOUT: Duration = Duration::from_secs(30);
const CREDENTIAL_ENV: [&str; 9] = [
    "GRID_USER",
    "GRID_FIRST_NAME",
    "GRID_LAST_NAME",
    "GRID_PASSWORD",
    "GRID_LOGIN_URL",
    "GRID_MASTER_UUID",
    "IRC_HOST",
    "IRC_PORT",
    "IRC_CHANNEL",
];

#[derive(Deserialize)]
struct Policy {
    schema: u32,
    version: String,
    release_packages: Vec<String>,
    binaries: Vec<BinaryPolicy>,
    offline_smokes: Vec<SmokePolicy>,
    allowed_native_ffi: Vec<String>,
    mirrored_inputs: Vec<MirroredInput>,
    forbidden_dependencies: Vec<String>,
    forbidden_artifact_strings: Vec<String>,
    forbidden_source_strings: Vec<String>,
}

#[derive(Deserialize)]
struct BinaryPolicy {
    name: String,
    services: Vec<String>,
}

#[derive(Deserialize)]
struct SmokePolicy {
    binary: String,
    args: Vec<String>,
    required_output: bool,
}

#[derive(Deserialize)]
struct MirroredInput {
    source: String,
    package_path: String,
}

#[derive(Deserialize)]
struct Metadata {
    packages: Vec<MetadataPackage>,
    workspace_members: Vec<String>,
    resolve: Option<Resolve>,
}

#[derive(Deserialize)]
struct MetadataPackage {
    id: String,
    name: String,
    version: String,
    manifest_path: PathBuf,
    dependencies: Vec<MetadataDependency>,
    targets: Vec<MetadataTarget>,
}

#[derive(Deserialize)]
struct MetadataDependency {
    name: String,
    req: String,
    path: Option<PathBuf>,
}

#[derive(Deserialize)]
struct MetadataTarget {
    name: String,
    kind: Vec<String>,
}

#[derive(Deserialize)]
struct Resolve {
    nodes: Vec<ResolveNode>,
}

#[derive(Deserialize)]
struct ResolveNode {
    id: String,
    dependencies: Vec<String>,
}

#[derive(Serialize)]
struct Evidence {
    schema: u32,
    source_commit: String,
    rustc: String,
    operating_system: String,
    architecture: String,
    cargo_graph_packages: usize,
    release_packages: Vec<PackageEvidence>,
    binaries: Vec<BinaryEvidence>,
    clean_package_build: bool,
    reference_checkout_required: bool,
    helper_processes_invoked: Vec<String>,
    forbidden_findings: usize,
}

#[derive(Serialize)]
struct PackageEvidence {
    name: String,
    version: String,
    archive: String,
    sha256: String,
    files: usize,
    unpacked_bytes: u64,
}

#[derive(Serialize)]
struct BinaryEvidence {
    name: String,
    format: String,
    bytes: u64,
    sha256: String,
    linked_libraries: Vec<String>,
    imported_symbols: usize,
    services: Vec<String>,
    smokes: Vec<SmokeEvidence>,
}

#[derive(Serialize)]
struct SmokeEvidence {
    arguments: Vec<String>,
    exit_code: i32,
    output_created: bool,
}

struct InspectedBinary {
    format: String,
    libraries: BTreeSet<String>,
    imported_symbols: usize,
}

/// Audits the complete shipped package and executable surface.
///
/// # Errors
///
/// Fails on metadata drift, unversioned internal dependencies, forbidden
/// runtime/bridge material, unsafe package paths, missing binaries, invalid
/// native objects, smoke failures, helper-process invocation, or a clean-room
/// package build failure. Existing evidence is never overwritten.
pub fn audit_artifacts(
    root: &Path,
    artifact_dir: &Path,
    package_dir: &Path,
    evidence_path: &Path,
) -> Result<()> {
    if evidence_path.exists() {
        return Err(MatrixError::new(format!(
            "{} already exists; preserve or remove it before rerunning the audit",
            evidence_path.display()
        )));
    }
    let policy: Policy = serde_json::from_slice(&fs::read(root.join(POLICY_PATH))?)?;
    validate_policy(&policy)?;
    let metadata = cargo_metadata(root)?;
    let release = validate_metadata(root, &metadata, &policy)?;
    audit_source(root, &release, &policy)?;
    let (packages, extracted) = inspect_packages(package_dir, &policy)?;
    let clean_package_build = build_extracted_packages(root, &extracted, &policy)?;
    let binaries = inspect_and_smoke_binaries(root, artifact_dir, &policy)?;
    let evidence = Evidence {
        schema: 1,
        source_commit: command_output(root, "git", &["rev-parse", "--verify", "HEAD"])?,
        rustc: command_output(root, "rustc", &["--version"])?,
        operating_system: std::env::consts::OS.into(),
        architecture: std::env::consts::ARCH.into(),
        cargo_graph_packages: metadata.packages.len(),
        release_packages: packages,
        binaries,
        clean_package_build,
        reference_checkout_required: false,
        helper_processes_invoked: Vec::new(),
        forbidden_findings: 0,
    };
    write_new_json(evidence_path, &evidence)
}

fn validate_policy(policy: &Policy) -> Result<()> {
    if policy.schema != 1 || policy.version != "0.0.1" {
        return Err(MatrixError::new("invalid artifact policy header"));
    }
    unique_nonempty(&policy.release_packages, "release package")?;
    unique_nonempty(&policy.allowed_native_ffi, "native FFI path")?;
    if policy.mirrored_inputs.is_empty()
        || policy
            .mirrored_inputs
            .iter()
            .any(|input| input.source.trim().is_empty() || input.package_path.trim().is_empty())
    {
        return Err(MatrixError::new("invalid mirrored package input policy"));
    }
    unique_nonempty(&policy.forbidden_dependencies, "forbidden dependency")?;
    unique_nonempty(
        &policy.forbidden_artifact_strings,
        "forbidden artifact string",
    )?;
    unique_nonempty(&policy.forbidden_source_strings, "forbidden source string")?;
    let binary_names = policy
        .binaries
        .iter()
        .map(|item| item.name.as_str())
        .collect::<BTreeSet<_>>();
    if binary_names.len() != policy.binaries.len()
        || policy
            .binaries
            .iter()
            .any(|item| item.name.trim().is_empty() || item.services.is_empty())
    {
        return Err(MatrixError::new("invalid or duplicate binary policy"));
    }
    if policy.offline_smokes.iter().any(|smoke| {
        !binary_names.contains(smoke.binary.as_str())
            || smoke.args.is_empty()
            || smoke.args.iter().any(String::is_empty)
    }) {
        return Err(MatrixError::new("invalid offline smoke policy"));
    }
    Ok(())
}

fn unique_nonempty(values: &[String], label: &str) -> Result<()> {
    let unique = values.iter().map(String::as_str).collect::<BTreeSet<_>>();
    if unique.len() != values.len() || values.iter().any(|value| value.trim().is_empty()) {
        return Err(MatrixError::new(format!("invalid or duplicate {label}")));
    }
    Ok(())
}

fn cargo_metadata(root: &Path) -> Result<Metadata> {
    let output = Command::new("cargo")
        .args(["metadata", "--format-version", "1", "--locked"])
        .current_dir(root)
        .output()?;
    if !output.status.success() {
        return Err(MatrixError::new(format!(
            "cargo metadata failed: {}",
            String::from_utf8_lossy(&output.stderr).trim()
        )));
    }
    Ok(serde_json::from_slice(&output.stdout)?)
}

fn validate_metadata<'a>(
    root: &Path,
    metadata: &'a Metadata,
    policy: &Policy,
) -> Result<Vec<&'a MetadataPackage>> {
    let workspace_members = metadata
        .workspace_members
        .iter()
        .map(String::as_str)
        .collect::<BTreeSet<_>>();
    let release_root = root.canonicalize()?.join("crates");
    let programs_manifest = root.canonicalize()?.join("programs/Cargo.toml");
    let discovered = metadata
        .packages
        .iter()
        .filter(|package| workspace_members.contains(package.id.as_str()))
        .filter_map(|package| {
            let manifest = package.manifest_path.canonicalize().ok()?;
            (manifest.starts_with(&release_root) || manifest == programs_manifest)
                .then_some(package.name.as_str())
        })
        .collect::<BTreeSet<_>>();
    let declared = policy
        .release_packages
        .iter()
        .map(String::as_str)
        .collect::<BTreeSet<_>>();
    if discovered != declared {
        return Err(MatrixError::new(format!(
            "release package policy mismatch; expected workspace release surface {discovered:?}, found {declared:?}"
        )));
    }
    let by_name = metadata
        .packages
        .iter()
        .map(|package| (package.name.as_str(), package))
        .collect::<BTreeMap<_, _>>();
    let mut release = Vec::new();
    for name in &policy.release_packages {
        let package = by_name
            .get(name.as_str())
            .copied()
            .ok_or_else(|| MatrixError::new(format!("release package {name} is missing")))?;
        if package.version != policy.version {
            return Err(MatrixError::new(format!(
                "release package {name} has version {}, expected {}",
                package.version, policy.version
            )));
        }
        for dependency in &package.dependencies {
            if dependency.path.is_some()
                && (dependency.req == "*" || dependency.req.trim().is_empty())
            {
                return Err(MatrixError::new(format!(
                    "release package {name} has unversioned path dependency {}",
                    dependency.name
                )));
            }
        }
        let manifest = package.manifest_path.canonicalize()?;
        if !manifest.starts_with(root.canonicalize()?) {
            return Err(MatrixError::new(format!(
                "release package {name} escapes the workspace"
            )));
        }
        release.push(package);
    }
    validate_binary_targets(&release, policy)?;
    validate_dependency_closure(metadata, &release, policy)?;
    Ok(release)
}

fn validate_binary_targets(release: &[&MetadataPackage], policy: &Policy) -> Result<()> {
    let actual = release
        .iter()
        .flat_map(|package| &package.targets)
        .filter(|target| target.kind.iter().any(|kind| kind == "bin"))
        .map(|target| target.name.as_str())
        .collect::<BTreeSet<_>>();
    let expected = policy
        .binaries
        .iter()
        .map(|binary| binary.name.as_str())
        .collect::<BTreeSet<_>>();
    if actual != expected {
        return Err(MatrixError::new(format!(
            "release binary policy mismatch; expected {expected:?}, found {actual:?}"
        )));
    }
    Ok(())
}

fn validate_dependency_closure(
    metadata: &Metadata,
    release: &[&MetadataPackage],
    policy: &Policy,
) -> Result<()> {
    let resolve = metadata
        .resolve
        .as_ref()
        .ok_or_else(|| MatrixError::new("cargo metadata has no dependency resolution"))?;
    let edges = resolve
        .nodes
        .iter()
        .map(|node| (node.id.as_str(), node.dependencies.as_slice()))
        .collect::<BTreeMap<_, _>>();
    let names = metadata
        .packages
        .iter()
        .map(|package| (package.id.as_str(), package.name.as_str()))
        .collect::<BTreeMap<_, _>>();
    let forbidden = policy
        .forbidden_dependencies
        .iter()
        .map(|name| name.to_ascii_lowercase())
        .collect::<BTreeSet<_>>();
    let mut pending = release
        .iter()
        .map(|package| package.id.as_str())
        .collect::<Vec<_>>();
    let mut visited = BTreeSet::new();
    while let Some(id) = pending.pop() {
        if !visited.insert(id) {
            continue;
        }
        let name = names
            .get(id)
            .ok_or_else(|| MatrixError::new(format!("unknown dependency package ID {id}")))?;
        if forbidden.contains(&name.to_ascii_lowercase()) {
            return Err(MatrixError::new(format!(
                "release dependency graph contains forbidden runtime {name}"
            )));
        }
        if let Some(dependencies) = edges.get(id) {
            pending.extend(dependencies.iter().map(String::as_str));
        }
    }
    if metadata.workspace_members.is_empty() {
        return Err(MatrixError::new("cargo workspace has no members"));
    }
    Ok(())
}

fn audit_source(root: &Path, release: &[&MetadataPackage], policy: &Policy) -> Result<()> {
    for input in &policy.mirrored_inputs {
        let source = fs::read(root.join(&input.source))?;
        let package = fs::read(root.join(&input.package_path))?;
        if source != package {
            return Err(MatrixError::new(format!(
                "package mirror {} differs from {}",
                input.package_path, input.source
            )));
        }
    }
    let ffi_allow = policy
        .allowed_native_ffi
        .iter()
        .map(String::as_str)
        .collect::<BTreeSet<_>>();
    let mut visited = BTreeSet::new();
    for package in release {
        let directory = package
            .manifest_path
            .parent()
            .ok_or_else(|| MatrixError::new("package manifest has no parent"))?;
        walk_source(root, directory, &mut visited, &ffi_allow, policy)?;
    }
    Ok(())
}

fn walk_source(
    root: &Path,
    directory: &Path,
    visited: &mut BTreeSet<PathBuf>,
    ffi_allow: &BTreeSet<&str>,
    policy: &Policy,
) -> Result<()> {
    let mut entries = fs::read_dir(directory)?.collect::<std::io::Result<Vec<_>>>()?;
    entries.sort_by_key(std::fs::DirEntry::file_name);
    for entry in entries {
        let file_type = entry.file_type()?;
        if file_type.is_symlink() {
            return Err(MatrixError::new(format!(
                "release source contains symlink {}",
                entry.path().display()
            )));
        }
        if file_type.is_dir() {
            let name = entry.file_name();
            if name != OsStr::new("target") && name != OsStr::new(".git") {
                walk_source(root, &entry.path(), visited, ffi_allow, policy)?;
            }
        } else if file_type.is_file()
            && matches!(
                entry.path().extension().and_then(OsStr::to_str),
                Some("rs" | "toml")
            )
        {
            let path = entry.path();
            if !visited.insert(path.clone()) {
                continue;
            }
            let relative = relative(root, &path)?;
            let text = fs::read_to_string(&path)?;
            for forbidden in &policy.forbidden_source_strings {
                if text.contains(forbidden) {
                    return Err(MatrixError::new(format!(
                        "release source {relative} contains forbidden runtime hook {forbidden:?}"
                    )));
                }
            }
            if text.contains("extern \"C\"") && !ffi_allow.contains(relative.as_str()) {
                return Err(MatrixError::new(format!(
                    "unreviewed native/generated FFI boundary in {relative}"
                )));
            }
        }
    }
    Ok(())
}

fn inspect_packages(
    package_dir: &Path,
    policy: &Policy,
) -> Result<(Vec<PackageEvidence>, ScratchDir)> {
    if !package_dir.is_dir() {
        return Err(MatrixError::new(format!(
            "package directory {} is missing",
            package_dir.display()
        )));
    }
    let scratch = ScratchDir::new("metacrate-package-audit")?;
    let mut evidence = Vec::new();
    for name in &policy.release_packages {
        let archive_name = format!("{name}-{}.crate", policy.version);
        let archive_path = package_dir.join(&archive_name);
        let metadata = fs::metadata(&archive_path).map_err(|error| {
            MatrixError::new(format!("missing package {archive_name}: {error}"))
        })?;
        if metadata.len() > MAX_ARCHIVE_BYTES {
            return Err(MatrixError::new(format!(
                "package {archive_name} exceeds the archive limit"
            )));
        }
        let (files, bytes) = inspect_and_extract_archive(&archive_path, &scratch.path, policy)?;
        evidence.push(PackageEvidence {
            name: name.clone(),
            version: policy.version.clone(),
            archive: archive_name,
            sha256: hash_file(&archive_path)?,
            files,
            unpacked_bytes: bytes,
        });
    }
    let actual = fs::read_dir(package_dir)?
        .filter_map(std::result::Result::ok)
        .filter(|entry| entry.path().extension() == Some(OsStr::new("crate")))
        .map(|entry| entry.file_name().to_string_lossy().into_owned())
        .collect::<BTreeSet<_>>();
    let expected = evidence
        .iter()
        .map(|item| item.archive.clone())
        .collect::<BTreeSet<_>>();
    if actual != expected {
        return Err(MatrixError::new(format!(
            "package directory contains missing or unexpected archives; expected {expected:?}, found {actual:?}"
        )));
    }
    Ok((evidence, scratch))
}

fn inspect_and_extract_archive(
    archive_path: &Path,
    scratch: &Path,
    policy: &Policy,
) -> Result<(usize, u64)> {
    let file = fs::File::open(archive_path)?;
    let mut archive = Archive::new(GzDecoder::new(file));
    let mut files = 0;
    let mut total = 0_u64;
    let forbidden = policy
        .forbidden_artifact_strings
        .iter()
        .map(|value| value.to_ascii_lowercase())
        .collect::<Vec<_>>();
    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?.into_owned();
        validate_archive_path(&path)?;
        let entry_type = entry.header().entry_type();
        if !entry_type.is_file() && !entry_type.is_dir() {
            return Err(MatrixError::new(format!(
                "unsupported link or special entry in source package {}",
                path.display()
            )));
        }
        let size = entry.size();
        if size > MAX_ENTRY_BYTES {
            return Err(MatrixError::new(format!(
                "package entry {} exceeds the size limit",
                path.display()
            )));
        }
        total = total
            .checked_add(size)
            .ok_or_else(|| MatrixError::new("package size overflow"))?;
        if entry_type.is_file() {
            reject_managed_extension(&path)?;
            let mut contents = Vec::with_capacity(usize::try_from(size).unwrap_or(0));
            entry.read_to_end(&mut contents)?;
            reject_forbidden_bytes(&contents, &forbidden, &path)?;
            if path.file_name() == Some(OsStr::new("Cargo.toml")) {
                reject_packaged_path_dependencies(&contents, &path)?;
            }
            let output = scratch.join(&path);
            if let Some(parent) = output.parent() {
                fs::create_dir_all(parent)?;
            }
            fs::write(&output, &contents)?;
            files += 1;
        }
    }
    Ok((files, total))
}

fn reject_packaged_path_dependencies(bytes: &[u8], path: &Path) -> Result<()> {
    let manifest = std::str::from_utf8(bytes).map_err(|_| {
        MatrixError::new(format!("packaged manifest {} is not UTF-8", path.display()))
    })?;
    let mut dependency_section = false;
    for line in manifest.lines() {
        let trimmed = line.trim();
        if trimmed.starts_with('[') && trimmed.ends_with(']') {
            let section = trimmed.trim_matches(['[', ']']);
            dependency_section = section
                .split('.')
                .any(|component| component.ends_with("dependencies"));
        } else if dependency_section && trimmed.contains("path =") {
            return Err(MatrixError::new(format!(
                "packaged manifest {} retains a workspace path dependency",
                path.display()
            )));
        }
    }
    Ok(())
}

fn validate_archive_path(path: &Path) -> Result<()> {
    if path.is_absolute()
        || path.components().any(|component| {
            matches!(
                component,
                Component::ParentDir | Component::RootDir | Component::Prefix(_)
            )
        })
    {
        return Err(MatrixError::new(format!(
            "unsafe package archive path {}",
            path.display()
        )));
    }
    Ok(())
}

fn reject_managed_extension(path: &Path) -> Result<()> {
    let extension = path
        .extension()
        .and_then(OsStr::to_str)
        .map(str::to_ascii_lowercase);
    if extension.as_deref().is_some_and(|value| {
        matches!(
            value,
            "cs" | "csproj" | "dll" | "exe" | "pdb" | "nupkg" | "jar" | "class"
        )
    }) {
        return Err(MatrixError::new(format!(
            "managed/foreign executable material in source package {}",
            path.display()
        )));
    }
    Ok(())
}

fn reject_forbidden_bytes(bytes: &[u8], forbidden: &[String], path: &Path) -> Result<()> {
    let lower = String::from_utf8_lossy(bytes).to_ascii_lowercase();
    if let Some(found) = forbidden
        .iter()
        .find(|value| lower.contains(value.as_str()))
    {
        return Err(MatrixError::new(format!(
            "forbidden runtime marker {found:?} in {}",
            path.display()
        )));
    }
    Ok(())
}

fn build_extracted_packages(root: &Path, scratch: &ScratchDir, policy: &Policy) -> Result<bool> {
    let members = policy
        .release_packages
        .iter()
        .map(|name| format!("\"{name}-{}\"", policy.version))
        .collect::<Vec<_>>()
        .join(",\n  ");
    let patches = policy
        .release_packages
        .iter()
        .map(|name| format!("{name} = {{ path = \"{name}-{}\" }}", policy.version))
        .collect::<Vec<_>>()
        .join("\n");
    let manifest = format!(
        "[workspace]\nresolver = \"3\"\nmembers = [\n  {members}\n]\n\n[patch.crates-io]\n{patches}\n"
    );
    fs::write(scratch.path.join("Cargo.toml"), manifest)?;
    let target = scratch.path.join("target");
    let status = Command::new("cargo")
        .args([
            "check",
            "--workspace",
            "--lib",
            "--bins",
            "--offline",
            "-j",
            "1",
        ])
        .arg("--target-dir")
        .arg(&target)
        .current_dir(&scratch.path)
        .env("CARGO_INCREMENTAL", "0")
        .env("CARGO_PROFILE_DEV_DEBUG", "0")
        .env(
            "METACRATE_REFERENCE_ROOT",
            root.join("reference-checkout-must-not-exist"),
        )
        .status()?;
    if !status.success() {
        return Err(MatrixError::new(
            "extracted release packages failed to build without the reference checkout",
        ));
    }
    Ok(true)
}

fn inspect_and_smoke_binaries(
    root: &Path,
    artifact_dir: &Path,
    policy: &Policy,
) -> Result<Vec<BinaryEvidence>> {
    let trap = HelperTrap::new()?;
    let forbidden = policy
        .forbidden_artifact_strings
        .iter()
        .map(|value| value.to_ascii_lowercase())
        .collect::<Vec<_>>();
    let mut evidence = Vec::new();
    for binary_policy in &policy.binaries {
        let path = binary_path(artifact_dir, &binary_policy.name);
        let metadata = fs::metadata(&path).map_err(|error| {
            MatrixError::new(format!(
                "missing release binary {}: {error}",
                path.display()
            ))
        })?;
        if !metadata.is_file() || metadata.len() > MAX_BINARY_BYTES {
            return Err(MatrixError::new(format!(
                "invalid or oversized release binary {}",
                path.display()
            )));
        }
        let bytes = fs::read(&path)?;
        reject_forbidden_bytes(&bytes, &forbidden, &path)?;
        let inspected = inspect_object(&bytes, &path, &forbidden)?;
        let mut smokes = vec![run_smoke(root, &path, &["--help".into()], false, &trap)?];
        for smoke in policy
            .offline_smokes
            .iter()
            .filter(|smoke| smoke.binary == binary_policy.name)
        {
            smokes.push(run_smoke(
                root,
                &path,
                &smoke.args,
                smoke.required_output,
                &trap,
            )?);
        }
        evidence.push(BinaryEvidence {
            name: binary_policy.name.clone(),
            format: inspected.format,
            bytes: metadata.len(),
            sha256: hash_bytes(&bytes),
            linked_libraries: inspected.libraries.into_iter().collect(),
            imported_symbols: inspected.imported_symbols,
            services: binary_policy.services.clone(),
            smokes,
        });
    }
    trap.verify_clean()?;
    Ok(evidence)
}

fn binary_path(directory: &Path, name: &str) -> PathBuf {
    #[cfg(windows)]
    {
        directory.join(format!("{name}.exe"))
    }
    #[cfg(not(windows))]
    {
        directory.join(name)
    }
}

fn inspect_object(bytes: &[u8], path: &Path, forbidden: &[String]) -> Result<InspectedBinary> {
    let object = Object::parse(bytes).map_err(|error| {
        MatrixError::new(format!("parse native object {}: {error}", path.display()))
    })?;
    let mut libraries = BTreeSet::new();
    let mut symbols = Vec::new();
    let format = match object {
        Object::Elf(elf) => {
            libraries.extend(elf.libraries.into_iter().map(str::to_owned));
            symbols.extend(
                elf.dynsyms
                    .iter()
                    .filter_map(|symbol| elf.dynstrtab.get_at(symbol.st_name))
                    .map(str::to_owned),
            );
            "ELF"
        }
        Object::PE(pe) => {
            libraries.extend(pe.libraries.into_iter().map(str::to_owned));
            symbols.extend(
                pe.imports
                    .into_iter()
                    .map(|import| import.name.into_owned()),
            );
            "PE"
        }
        Object::Mach(mach::Mach::Binary(binary)) => {
            libraries.extend(binary.libs.iter().copied().map(str::to_owned));
            symbols.extend(
                binary
                    .symbols()
                    .filter_map(std::result::Result::ok)
                    .map(|(name, _)| name.to_owned()),
            );
            "Mach-O"
        }
        Object::Mach(mach::Mach::Fat(fat)) => {
            for architecture in &fat {
                if let mach::SingleArch::MachO(binary) = architecture.map_err(|error| {
                    MatrixError::new(format!("parse fat Mach-O {}: {error}", path.display()))
                })? {
                    libraries.extend(binary.libs.iter().copied().map(str::to_owned));
                    symbols.extend(
                        binary
                            .symbols()
                            .filter_map(std::result::Result::ok)
                            .map(|(name, _)| name.to_owned()),
                    );
                }
            }
            "Mach-O-fat"
        }
        _ => {
            return Err(MatrixError::new(format!(
                "{} is not an ELF, PE, or Mach-O executable",
                path.display()
            )));
        }
    };
    for value in libraries.iter().chain(symbols.iter()) {
        let lower = value.to_ascii_lowercase();
        if let Some(found) = forbidden.iter().find(|item| lower.contains(item.as_str())) {
            return Err(MatrixError::new(format!(
                "native object {} references forbidden runtime marker {found:?} through {value:?}",
                path.display()
            )));
        }
    }
    Ok(InspectedBinary {
        format: format.into(),
        libraries,
        imported_symbols: symbols.len(),
    })
}

fn run_smoke(
    root: &Path,
    binary: &Path,
    arguments: &[String],
    required_output: bool,
    trap: &HelperTrap,
) -> Result<SmokeEvidence> {
    let output = unique_scratch("metacrate-runtime-evidence")?;
    let resolved = arguments
        .iter()
        .map(|argument| {
            if argument == "{output}" {
                output.to_string_lossy().into_owned()
            } else {
                argument.clone()
            }
        })
        .collect::<Vec<_>>();
    let existing_path = std::env::var_os("PATH").unwrap_or_default();
    let joined = std::env::join_paths(
        std::iter::once(trap.directory.as_os_str()).chain(
            std::env::split_paths(&existing_path)
                .map(PathBuf::into_os_string)
                .collect::<Vec<_>>()
                .iter()
                .map(std::ffi::OsString::as_os_str),
        ),
    )
    .map_err(|error| MatrixError::new(format!("construct helper-trap PATH: {error}")))?;
    let mut command = Command::new(binary);
    command
        .args(&resolved)
        .current_dir(root)
        .env("PATH", joined)
        .env("HTTP_PROXY", "http://127.0.0.1:9")
        .env("HTTPS_PROXY", "http://127.0.0.1:9")
        .env("ALL_PROXY", "http://127.0.0.1:9")
        .env("NO_PROXY", "127.0.0.1,localhost")
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null());
    for name in CREDENTIAL_ENV {
        command.env_remove(name);
    }
    let mut child = command.spawn().map_err(|error| {
        MatrixError::new(format!("start runtime smoke {}: {error}", binary.display()))
    })?;
    let started = Instant::now();
    let status = loop {
        if let Some(status) = child.try_wait()? {
            break status;
        }
        if started.elapsed() >= SMOKE_TIMEOUT {
            child.kill()?;
            let _ = child.wait();
            return Err(MatrixError::new(format!(
                "runtime smoke timed out: {} {}",
                binary.display(),
                resolved.join(" ")
            )));
        }
        thread::sleep(Duration::from_millis(10));
    };
    if !status.success() {
        return Err(MatrixError::new(format!(
            "runtime smoke failed with {status}: {} {}",
            binary.display(),
            resolved.join(" ")
        )));
    }
    let output_created = output.is_file();
    if required_output && !output_created {
        return Err(MatrixError::new(format!(
            "runtime smoke did not create required evidence: {} {}",
            binary.display(),
            resolved.join(" ")
        )));
    }
    if output_created {
        fs::remove_file(&output)?;
    }
    Ok(SmokeEvidence {
        arguments: arguments.to_vec(),
        exit_code: status.code().unwrap_or(0),
        output_created,
    })
}

struct HelperTrap {
    directory: PathBuf,
    marker: PathBuf,
}

impl Drop for HelperTrap {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.directory);
    }
}

impl HelperTrap {
    fn new() -> Result<Self> {
        let directory = unique_scratch("metacrate-helper-trap")?;
        fs::create_dir(&directory)?;
        let marker = directory.join("invoked.txt");
        for name in [
            "dotnet",
            "mono",
            "csc",
            "mcs",
            "pwsh",
            "powershell",
            "curl",
            "wget",
        ] {
            write_trap(&directory, &marker, name)?;
        }
        Ok(Self { directory, marker })
    }

    fn verify_clean(&self) -> Result<()> {
        if self.marker.exists() {
            return Err(MatrixError::new(format!(
                "runtime smoke invoked a forbidden helper: {}",
                fs::read_to_string(&self.marker).unwrap_or_default().trim()
            )));
        }
        Ok(())
    }
}

struct ScratchDir {
    path: PathBuf,
}

impl ScratchDir {
    fn new(prefix: &str) -> Result<Self> {
        let path = unique_scratch(prefix)?;
        fs::create_dir(&path)?;
        Ok(Self { path })
    }
}

impl Drop for ScratchDir {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.path);
    }
}

#[cfg(unix)]
fn write_trap(directory: &Path, marker: &Path, name: &str) -> Result<()> {
    use std::os::unix::fs::PermissionsExt as _;
    let path = directory.join(name);
    fs::write(
        &path,
        format!(
            "#!/bin/sh\nprintf '%s\\n' '{name}' > '{}'\nexit 97\n",
            marker.display()
        ),
    )?;
    fs::set_permissions(&path, fs::Permissions::from_mode(0o700))?;
    Ok(())
}

#[cfg(windows)]
fn write_trap(directory: &Path, marker: &Path, name: &str) -> Result<()> {
    fs::write(
        directory.join(format!("{name}.cmd")),
        format!("@echo {name}>\"{}\"\r\n@exit /b 97\r\n", marker.display()),
    )?;
    Ok(())
}

fn unique_scratch(prefix: &str) -> Result<PathBuf> {
    let nanos = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map_err(|error| MatrixError::new(format!("system clock error: {error}")))?
        .as_nanos();
    let path = std::env::temp_dir().join(format!("{prefix}-{}-{nanos}", std::process::id()));
    if path.exists() {
        return Err(MatrixError::new(format!(
            "scratch path already exists: {}",
            path.display()
        )));
    }
    Ok(path)
}

fn command_output(root: &Path, program: &str, arguments: &[&str]) -> Result<String> {
    let output = Command::new(program)
        .args(arguments)
        .current_dir(root)
        .output()?;
    if !output.status.success() {
        return Err(MatrixError::new(format!(
            "{program} {} failed",
            arguments.join(" ")
        )));
    }
    String::from_utf8(output.stdout)
        .map(|value| value.trim().to_owned())
        .map_err(|_| MatrixError::new(format!("{program} output was not UTF-8")))
}

fn relative(root: &Path, path: &Path) -> Result<String> {
    path.strip_prefix(root)
        .map_err(|_| MatrixError::new(format!("{} is outside the workspace", path.display())))?
        .to_str()
        .map(str::to_owned)
        .ok_or_else(|| MatrixError::new(format!("{} is not UTF-8", path.display())))
}

fn hash_file(path: &Path) -> Result<String> {
    hash_reader(fs::File::open(path)?)
}

fn hash_reader(mut reader: impl Read) -> Result<String> {
    let mut hash = Sha256::new();
    let mut buffer = vec![0_u8; 64 * 1024].into_boxed_slice();
    loop {
        let count = reader.read(&mut buffer)?;
        if count == 0 {
            break;
        }
        hash.update(&buffer[..count]);
    }
    Ok(hex(&hash.finalize()))
}

fn hash_bytes(bytes: &[u8]) -> String {
    hex(&Sha256::digest(bytes))
}

fn hex(bytes: &[u8]) -> String {
    bytes.iter().fold(
        String::with_capacity(bytes.len() * 2),
        |mut output, byte| {
            write!(output, "{byte:02x}").expect("writing to a String cannot fail");
            output
        },
    )
}

fn write_new_json(path: &Path, value: &impl Serialize) -> Result<()> {
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent)?;
    }
    let mut file = OpenOptions::new().write(true).create_new(true).open(path)?;
    let mut bytes = serde_json::to_vec_pretty(value)?;
    bytes.push(b'\n');
    file.write_all(&bytes)?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn policy_covers_every_shipped_binary_and_package() {
        let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
        let policy: Policy =
            serde_json::from_slice(&fs::read(root.join(POLICY_PATH)).unwrap()).unwrap();
        validate_policy(&policy).unwrap();
        assert_eq!(policy.release_packages.len(), 16);
        assert_eq!(policy.binaries.len(), 10);
    }

    #[test]
    fn unsafe_and_managed_package_paths_are_rejected() {
        assert!(validate_archive_path(Path::new("crate/src/lib.rs")).is_ok());
        assert!(validate_archive_path(Path::new("../escape")).is_err());
        assert!(reject_managed_extension(Path::new("crate/payload.dll")).is_err());
        assert!(reject_managed_extension(Path::new("crate/src/lib.rs")).is_ok());
    }

    #[test]
    fn packaged_dependency_paths_are_rejected_but_target_paths_are_allowed() {
        let invalid = b"[dependencies.example]\nversion = \"1\"\npath = \"../example\"\n";
        assert!(reject_packaged_path_dependencies(invalid, Path::new("Cargo.toml")).is_err());
        let inline = b"[dependencies]\nexample = { version = \"1\", path = \"../example\" }\n";
        assert!(reject_packaged_path_dependencies(inline, Path::new("Cargo.toml")).is_err());

        let valid = b"[[bin]]\nname = \"example\"\npath = \"src/main.rs\"\n";
        assert!(reject_packaged_path_dependencies(valid, Path::new("Cargo.toml")).is_ok());
    }
}
