amiss-bootstrap 0.9.0

Trusted CI wrapper that validates and launches a verified Amiss engine
Documentation
#![expect(clippy::unwrap_used, reason = "integration process fixture")]

use std::path::{Path, PathBuf};
use std::process::{Command, Output};

use amiss_bootstrap::result::{BootstrapResult, parse_result};

fn invoke(root: &Path, constraint: &Path, report: &Path, result: &Path) -> Output {
    let unused = root.join("unused");
    Command::new(env!("CARGO_BIN_EXE_amiss-bootstrap"))
        .arg("exec")
        .arg("--action-repository")
        .arg(&unused)
        .arg("--repository")
        .arg(&unused)
        .arg("--constraint")
        .arg(constraint)
        .arg("--evaluation-request")
        .arg(&unused)
        .arg("--snapshot-request")
        .arg(&unused)
        .arg("--controls-request")
        .arg(&unused)
        .arg("--scratch")
        .arg(root)
        .arg("--report")
        .arg(report)
        .arg("--result")
        .arg(result)
        .output()
        .unwrap()
}

fn output_files(root: &Path) -> (PathBuf, PathBuf) {
    let report = root.join("report");
    let result = root.join("result");
    std::fs::write(&report, b"").unwrap();
    std::fs::write(&result, b"").unwrap();
    (report, result)
}

#[test]
fn a_missing_constraint_records_unavailable() {
    let root = tempfile::tempdir().unwrap();
    let (report, result) = output_files(root.path());

    let output = invoke(root.path(), &root.path().join("missing"), &report, &result);

    assert_eq!(output.status.code(), Some(2));
    assert!(output.stdout.is_empty());
    assert!(std::fs::read(report).unwrap().is_empty());
    assert_eq!(
        parse_result(&std::fs::read(result).unwrap()),
        Some(BootstrapResult::Unavailable)
    );
}

#[test]
fn a_malformed_constraint_records_tampered_runtime() {
    let root = tempfile::tempdir().unwrap();
    let constraint = root.path().join("constraint");
    let (report, result) = output_files(root.path());
    std::fs::write(&constraint, b"not a constraint").unwrap();

    let output = invoke(root.path(), &constraint, &report, &result);

    assert_eq!(output.status.code(), Some(2));
    assert!(output.stdout.is_empty());
    assert!(std::fs::read(report).unwrap().is_empty());
    assert_eq!(
        parse_result(&std::fs::read(result).unwrap()),
        Some(BootstrapResult::TamperedRuntime)
    );
}

#[test]
fn an_existing_result_is_never_replaced() {
    existing_output_is_never_replaced(b"", b"controller-owned");
}

#[test]
fn an_existing_report_is_never_replaced() {
    existing_output_is_never_replaced(b"controller-owned", b"");
}

fn existing_output_is_never_replaced(report_bytes: &[u8], result_bytes: &[u8]) {
    let root = tempfile::tempdir().unwrap();
    let report = root.path().join("report");
    let result = root.path().join("result");
    std::fs::write(&report, report_bytes).unwrap();
    std::fs::write(&result, result_bytes).unwrap();

    let output = invoke(root.path(), &root.path().join("missing"), &report, &result);

    assert_eq!(output.status.code(), Some(2));
    assert_eq!(std::fs::read(report).unwrap(), report_bytes);
    assert_eq!(std::fs::read(result).unwrap(), result_bytes);
    assert!(String::from_utf8_lossy(&output.stderr).contains("invalid-invocation"));
}

#[test]
fn output_files_have_fixed_names() {
    let root = tempfile::tempdir().unwrap();
    let report = root.path().join("first");
    let result = root.path().join("second");
    std::fs::write(&report, b"").unwrap();
    std::fs::write(&result, b"").unwrap();

    let output = invoke(root.path(), &root.path().join("missing"), &report, &result);

    assert_eq!(output.status.code(), Some(2));
    assert!(std::fs::read(report).unwrap().is_empty());
    assert!(std::fs::read(result).unwrap().is_empty());
    assert!(String::from_utf8_lossy(&output.stderr).contains("invalid-invocation"));
}

#[test]
fn output_files_must_be_created_by_the_controller() {
    let root = tempfile::tempdir().unwrap();
    let report = root.path().join("report");
    let result = root.path().join("result");

    let output = invoke(root.path(), &root.path().join("missing"), &report, &result);

    assert_eq!(output.status.code(), Some(2));
    assert!(!report.exists());
    assert!(!result.exists());
    assert!(String::from_utf8_lossy(&output.stderr).contains("invalid-invocation"));
}