use whyno_core::checks::{run_checks, CheckReport};
use whyno_core::fix::{generate_fixes, FixPlan};
use whyno_core::operation::{MetadataParams, Operation};
use whyno_core::test_helpers::StateBuilder;
use crate::output::checklist;
fn setup_no_color() {
owo_colors::set_override(false);
}
fn render_to_string(
report: &CheckReport,
plan: &FixPlan,
state: &whyno_core::state::SystemState,
) -> String {
let mut buf = Vec::new();
checklist::render(report, plan, state, &mut buf).expect("render should succeed");
String::from_utf8(buf).expect("output should be valid UTF-8")
}
#[test]
fn all_pass_scenario() {
setup_no_color();
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Read)
.component("/", 0, 0, 0o755)
.component("/home", 0, 0, 0o755)
.component_file("/home/file.txt", 1000, 1000, 0o644)
.mount("/", "ext4", "rw")
.build();
let report = run_checks(&state, &MetadataParams::default());
let plan = generate_fixes(&report, &state, &MetadataParams::default());
let output = render_to_string(&report, &plan, &state);
insta::assert_snapshot!(output);
}
#[test]
fn single_layer_failure_with_fix() {
setup_no_color();
let state = StateBuilder::new()
.subject(33, 33, vec![])
.operation(Operation::Read)
.component("/", 0, 0, 0o755)
.component("/var", 0, 0, 0o755)
.component_file("/var/log.txt", 0, 0, 0o640)
.mount("/", "ext4", "rw")
.build();
let report = run_checks(&state, &MetadataParams::default());
let plan = generate_fixes(&report, &state, &MetadataParams::default());
let output = render_to_string(&report, &plan, &state);
insta::assert_snapshot!(output);
}
#[test]
fn multi_layer_failure_with_fix_plan() {
setup_no_color();
let state = StateBuilder::new()
.subject(33, 33, vec![])
.operation(Operation::Read)
.component("/", 0, 0, 0o755)
.component("/var", 0, 0, 0o700)
.component_file("/var/secret.txt", 0, 0, 0o600)
.mount("/", "ext4", "rw")
.build();
let report = run_checks(&state, &MetadataParams::default());
let plan = generate_fixes(&report, &state, &MetadataParams::default());
let output = render_to_string(&report, &plan, &state);
insta::assert_snapshot!(output);
}
#[test]
fn degraded_layer_shows_skip() {
setup_no_color();
let state = StateBuilder::new()
.subject(33, 33, vec![])
.operation(Operation::Read)
.component("/", 0, 0, 0o755)
.component_inaccessible("/secret")
.mount("/", "ext4", "rw")
.build();
let report = run_checks(&state, &MetadataParams::default());
let plan = generate_fixes(&report, &state, &MetadataParams::default());
let output = render_to_string(&report, &plan, &state);
insta::assert_snapshot!(output);
}
#[test]
fn nosuid_warning_on_execute_with_suid_target() {
setup_no_color();
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Execute)
.component("/", 0, 0, 0o755)
.component_file("/mnt/suid_bin", 0, 0, 0o4755)
.mount("/mnt", "ext4", "nosuid")
.build();
let report = run_checks(&state, &MetadataParams::default());
let plan = generate_fixes(&report, &state, &MetadataParams::default());
let output = render_to_string(&report, &plan, &state);
insta::assert_snapshot!(output);
}
#[test]
fn ro_mount_failure() {
setup_no_color();
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Write)
.component("/", 0, 0, 0o755)
.component_file("/mnt/data.txt", 1000, 1000, 0o644)
.mount("/mnt", "ext4", "ro")
.build();
let report = run_checks(&state, &MetadataParams::default());
let plan = generate_fixes(&report, &state, &MetadataParams::default());
let output = render_to_string(&report, &plan, &state);
insta::assert_snapshot!(output);
}