use super::*;
use crate::operation::Operation;
use crate::state::mac::{SeLinuxMode, SeLinuxState};
use crate::state::Probe;
use crate::test_helpers::StateBuilder;
#[test]
fn read_still_maps_to_file_read() {
assert_eq!(operation_to_selinux_perm(Operation::Read), ("file", "read"));
}
#[test]
fn write_still_maps_to_file_write() {
assert_eq!(
operation_to_selinux_perm(Operation::Write),
("file", "write")
);
}
#[test]
fn execute_still_maps_to_file_execute() {
assert_eq!(
operation_to_selinux_perm(Operation::Execute),
("file", "execute")
);
}
#[test]
fn stat_still_maps_to_file_read() {
assert_eq!(operation_to_selinux_perm(Operation::Stat), ("file", "read"));
}
#[test]
fn chmod_maps_to_file_setattr() {
assert_eq!(
operation_to_selinux_perm(Operation::Chmod),
("file", "setattr")
);
}
#[test]
fn chown_uid_maps_to_file_setattr() {
assert_eq!(
operation_to_selinux_perm(Operation::ChownUid),
("file", "setattr")
);
}
#[test]
fn chown_gid_maps_to_file_setattr() {
assert_eq!(
operation_to_selinux_perm(Operation::ChownGid),
("file", "setattr")
);
}
#[test]
fn setxattr_user_maps_to_file_setattr() {
use crate::operation::XattrNamespace;
assert_eq!(
operation_to_selinux_perm(Operation::SetXattr {
namespace: XattrNamespace::User
}),
("file", "setattr")
);
}
#[test]
fn setxattr_trusted_maps_to_file_setattr() {
use crate::operation::XattrNamespace;
assert_eq!(
operation_to_selinux_perm(Operation::SetXattr {
namespace: XattrNamespace::Trusted
}),
("file", "setattr")
);
}
#[test]
fn setxattr_security_maps_to_file_setattr() {
use crate::operation::XattrNamespace;
assert_eq!(
operation_to_selinux_perm(Operation::SetXattr {
namespace: XattrNamespace::Security
}),
("file", "setattr")
);
}
#[test]
fn setxattr_posix_acl_maps_to_file_setattr() {
use crate::operation::XattrNamespace;
assert_eq!(
operation_to_selinux_perm(Operation::SetXattr {
namespace: XattrNamespace::SystemPosixAcl
}),
("file", "setattr")
);
}
#[test]
fn operation_to_selinux_perm_read() {
assert_eq!(operation_to_selinux_perm(Operation::Read), ("file", "read"));
}
#[test]
fn operation_to_selinux_perm_stat() {
assert_eq!(operation_to_selinux_perm(Operation::Stat), ("file", "read"));
}
#[test]
fn operation_to_selinux_perm_write() {
assert_eq!(
operation_to_selinux_perm(Operation::Write),
("file", "write")
);
}
#[test]
fn operation_to_selinux_perm_create() {
assert_eq!(
operation_to_selinux_perm(Operation::Create),
("file", "write")
);
}
#[test]
fn operation_to_selinux_perm_delete() {
assert_eq!(
operation_to_selinux_perm(Operation::Delete),
("file", "write")
);
}
#[test]
fn operation_to_selinux_perm_execute() {
assert_eq!(
operation_to_selinux_perm(Operation::Execute),
("file", "execute")
);
}
#[test]
fn selinux_enforcing_access_allowed_returns_pass() {
let state = StateBuilder::new()
.operation(Operation::Read)
.with_selinux_state(SeLinuxState {
mode: SeLinuxMode::Enforcing,
subject_ctx: "unconfined_u:unconfined_r:unconfined_t:s0".into(),
target_ctx: "system_u:object_r:httpd_sys_content_t:s0".into(),
access_allowed: true,
})
.component("/", 0, 0, 0o755)
.component_file("/etc/hosts", 0, 0, 0o644)
.build();
let result = check_selinux(&state);
assert!(
result.is_pass(),
"expected Pass for enforcing+allowed, got {result:?}"
);
if let LayerResult::Pass { warnings, .. } = &result {
assert!(
warnings.is_empty(),
"no warnings expected when enforcing and allowed"
);
}
}
#[test]
fn selinux_enforcing_access_denied_returns_fail() {
let state = StateBuilder::new()
.operation(Operation::Write)
.with_selinux_state(SeLinuxState {
mode: SeLinuxMode::Enforcing,
subject_ctx: "unconfined_u:unconfined_r:unconfined_t:s0".into(),
target_ctx: "system_u:object_r:httpd_sys_content_t:s0".into(),
access_allowed: false,
})
.component("/", 0, 0, 0o755)
.component_file("/var/www/html/index.html", 0, 0, 0o644)
.build();
let result = check_selinux(&state);
assert!(
result.is_fail(),
"expected Fail for enforcing+denied, got {result:?}"
);
}
#[test]
fn selinux_permissive_would_deny_returns_pass_with_warning() {
let state = StateBuilder::new()
.operation(Operation::Write)
.with_selinux_state(SeLinuxState {
mode: SeLinuxMode::Permissive,
subject_ctx: "unconfined_u:unconfined_r:unconfined_t:s0".into(),
target_ctx: "system_u:object_r:httpd_sys_content_t:s0".into(),
access_allowed: false,
})
.component("/", 0, 0, 0o755)
.component_file("/var/www/html/index.html", 0, 0, 0o644)
.build();
let result = check_selinux(&state);
assert!(
result.is_pass(),
"expected Pass (permissive) for permissive+denied, got {result:?}"
);
if let LayerResult::Pass { warnings, .. } = &result {
assert!(
!warnings.is_empty(),
"expected at least one warning in permissive mode"
);
}
}
#[test]
fn selinux_disabled_returns_degraded() {
let state = StateBuilder::new()
.operation(Operation::Read)
.with_selinux_state(SeLinuxState {
mode: SeLinuxMode::Disabled,
subject_ctx: String::new(),
target_ctx: String::new(),
access_allowed: false,
})
.component("/", 0, 0, 0o755)
.component_file("/etc/passwd", 0, 0, 0o644)
.build();
let result = check_selinux(&state);
assert!(
result.is_degraded(),
"expected Degraded for disabled SELinux, got {result:?}"
);
}
#[test]
fn selinux_probe_unknown_returns_degraded() {
let state = StateBuilder::new()
.operation(Operation::Read)
.component("/", 0, 0, 0o755)
.component_file("/etc/shadow", 0, 0, 0o640)
.build();
assert_eq!(state.mac_state.selinux, Probe::Unknown);
let result = check_selinux(&state);
assert!(
result.is_degraded(),
"expected Degraded for unknown probe, got {result:?}"
);
}
#[test]
fn selinux_probe_inaccessible_returns_degraded() {
let mut state = StateBuilder::new()
.operation(Operation::Read)
.component("/", 0, 0, 0o755)
.component_file("/etc/shadow", 0, 0, 0o640)
.build();
state.mac_state.selinux = Probe::Inaccessible;
let result = check_selinux(&state);
assert!(
result.is_degraded(),
"expected Degraded for inaccessible probe, got {result:?}"
);
}