use super::generators;
use crate::checks::CoreLayer;
use crate::fix::scoring;
use crate::fix::FixAction;
use crate::operation::Operation;
use crate::state::fsflags::FsFlags;
use crate::test_helpers::StateBuilder;
#[test]
fn mount_fixes_noexec_generates_exec_remount() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Execute)
.mount("/mnt", "tmpfs", "noexec")
.component("/mnt", 0, 0, 0o755)
.component_file("/mnt/script.sh", 1000, 1000, 0o755)
.build();
let fixes = generators::mount_fixes(&state);
assert_eq!(fixes.len(), 1);
assert!(matches!(
&fixes[0].action,
FixAction::Remount { options, .. } if options == "exec"
));
assert_eq!(fixes[0].impact, scoring::REMOUNT);
assert_eq!(fixes[0].layer, CoreLayer::Mount);
}
#[test]
fn mount_fixes_ro_write_generates_rw_remount() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Write)
.mount("/mnt", "ext4", "ro")
.component("/mnt", 0, 0, 0o755)
.component_file("/mnt/data.txt", 1000, 1000, 0o644)
.build();
let fixes = generators::mount_fixes(&state);
assert_eq!(fixes.len(), 1);
assert!(matches!(
&fixes[0].action,
FixAction::Remount { options, .. } if options == "rw"
));
}
#[test]
fn mount_fixes_ro_delete_generates_rw_remount() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Delete)
.mount("/mnt", "ext4", "ro")
.component("/mnt", 0, 0, 0o755)
.component_file("/mnt/data.txt", 1000, 1000, 0o644)
.build();
let fixes = generators::mount_fixes(&state);
assert_eq!(fixes.len(), 1);
assert!(matches!(
&fixes[0].action,
FixAction::Remount { options, .. } if options == "rw"
));
}
#[test]
fn mount_fixes_ro_create_generates_rw_remount() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Create)
.mount("/mnt", "ext4", "ro")
.component("/mnt", 0, 0, 0o755)
.component_file("/mnt/new.txt", 1000, 1000, 0o644)
.build();
let fixes = generators::mount_fixes(&state);
assert_eq!(fixes.len(), 1);
assert!(matches!(
&fixes[0].action,
FixAction::Remount { options, .. } if options == "rw"
));
}
#[test]
fn mount_fixes_no_target_returns_empty_for_single_delete() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Delete)
.mount("/", "ext4", "ro")
.component("/", 0, 0, 0o755)
.build();
let fixes = generators::mount_fixes(&state);
assert!(fixes.is_empty());
}
#[test]
fn mount_fixes_no_mount_resolved_returns_empty() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Write)
.component_file("/data.txt", 1000, 1000, 0o644)
.build();
let fixes = generators::mount_fixes(&state);
assert!(fixes.is_empty());
}
#[test]
fn fsflags_fixes_append_only_without_immutable() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Write)
.mount("/", "ext4", "rw")
.component("/", 0, 0, 0o755)
.component_file_with_flags(
"/append.txt",
1000,
1000,
0o644,
FsFlags {
immutable: false,
append_only: true,
},
)
.build();
let fixes = generators::fsflags_fixes(&state);
assert_eq!(fixes.len(), 1);
assert!(matches!(
&fixes[0].action,
FixAction::Chattr { flags, .. } if flags == "-a"
));
assert_eq!(fixes[0].layer, CoreLayer::FsFlags);
}
#[test]
fn fsflags_fixes_immutable_and_append_only_only_immutable_fix() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Write)
.mount("/", "ext4", "rw")
.component("/", 0, 0, 0o755)
.component_file_with_flags(
"/both.txt",
1000,
1000,
0o644,
FsFlags {
immutable: true,
append_only: true,
},
)
.build();
let fixes = generators::fsflags_fixes(&state);
assert_eq!(fixes.len(), 1);
assert!(matches!(
&fixes[0].action,
FixAction::Chattr { flags, .. } if flags == "-i"
));
}
#[test]
fn fsflags_fixes_no_flags_set_returns_empty() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Write)
.mount("/", "ext4", "rw")
.component("/", 0, 0, 0o755)
.component_file_with_flags(
"/normal.txt",
1000,
1000,
0o644,
FsFlags {
immutable: false,
append_only: false,
},
)
.build();
let fixes = generators::fsflags_fixes(&state);
assert!(fixes.is_empty());
}
#[test]
fn fsflags_fixes_no_target_single_delete_returns_empty() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Delete)
.mount("/", "ext4", "rw")
.component("/", 0, 0, 0o755)
.build();
let fixes = generators::fsflags_fixes(&state);
assert!(fixes.is_empty());
}
#[test]
fn fsflags_fixes_unknown_flags_probe_returns_empty() {
let state = StateBuilder::new()
.subject(1000, 1000, vec![])
.operation(Operation::Write)
.mount("/", "ext4", "rw")
.component("/", 0, 0, 0o755)
.component_unknown("/mystery.txt")
.build();
let fixes = generators::fsflags_fixes(&state);
assert!(fixes.is_empty());
}