#![allow(
unused_crate_dependencies,
unused_qualifications,
missing_docs,
missing_debug_implementations,
unused_import_braces,
unused_lifetimes,
single_use_lifetimes,
trivial_casts,
trivial_numeric_casts,
elided_lifetimes_in_paths,
explicit_outlives_requirements,
variant_size_differences,
clippy::all,
clippy::pedantic,
clippy::nursery,
clippy::cargo,
clippy::expect_used,
clippy::unwrap_used,
clippy::panic,
clippy::indexing_slicing,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
reason = "integration test -- all lints suppressed per project policy"
)]
use std::collections::HashSet;
fn credential_ladder(caller: (u32, u32), owner: Option<(u32, u32)>) -> Vec<(u32, u32)> {
credential_ladder_with(caller, owner, None, &[])
}
fn credential_ladder_with(caller: (u32, u32), owner: Option<(u32, u32)>, mode: Option<u32>, observed: &[(u32, u32)]) -> Vec<(u32, u32)> {
let mut list = Vec::with_capacity(16);
if let Some((file_uid, file_group)) = owner {
list.push((file_uid, file_group));
if file_group != caller.1 {
list.push((caller.0, file_group));
}
}
list.push((0, 0));
let other_has_access = mode.is_none_or(|m| m & 0o007 != 0);
if !other_has_access {
let mut seen = HashSet::new();
list.retain(|pair| seen.insert(*pair));
return list;
}
list.extend_from_slice(observed);
list.push((65534, 65534));
list.push((1000, 1000));
list.push((33, 33));
list.push((27, 27));
list.push((26, 26));
list.push((1001, 1001));
list.push((1002, 1002));
let mut seen = HashSet::new();
list.retain(|pair| seen.insert(*pair));
list
}
#[test]
fn owner_comes_first_in_ladder() {
let ladder = credential_ladder((1000, 1000), Some((42, 42)));
assert_eq!(ladder[0], (42, 42), "file owner must be the first rung");
}
#[test]
fn caller_with_owner_group_comes_second() {
let ladder = credential_ladder((1000, 1000), Some((42, 99)));
assert_eq!(ladder[0], (42, 99), "owner first");
assert_eq!(ladder[1], (1000, 99), "caller with owner's group second");
}
#[test]
fn caller_group_matches_owner_group_skips_duplicate() {
let ladder = credential_ladder((1000, 42), Some((500, 42)));
assert_eq!(ladder[0], (500, 42), "owner first");
assert_eq!(ladder[1], (0, 0), "root must follow when caller_gid == owner_gid");
}
#[test]
fn root_always_present() {
let ladder = credential_ladder((1000, 1000), None);
assert!(ladder.contains(&(0, 0)), "root must always be in the ladder");
}
#[test]
fn root_is_first_when_no_owner() {
let ladder = credential_ladder((1000, 1000), None);
assert_eq!(ladder[0], (0, 0), "with no owner info, root must be first");
}
#[test]
fn no_duplicates_in_any_ladder() {
let test_cases: Vec<(_, Option<(u32, u32)>)> = vec![((0, 0), Some((0, 0))), ((1000, 1000), Some((1000, 1000))), ((33, 33), Some((33, 33))), ((65534, 65534), None), ((42, 42), Some((0, 0)))];
for (caller, owner) in test_cases {
let ladder = credential_ladder(caller, owner);
let mut seen = HashSet::new();
for pair in &ladder {
assert!(seen.insert(*pair), "duplicate credential {pair:?} in ladder for caller={caller:?} owner={owner:?}");
}
}
}
#[test]
fn owner_matching_service_account_deduped() {
let ladder = credential_ladder((1000, 1000), Some((33, 33)));
assert_eq!(ladder.iter().filter(|p| **p == (33, 33)).count(), 1, "www-data must appear exactly once");
assert_eq!(ladder[0], (33, 33), "www-data as owner must keep highest priority");
}
#[test]
fn root_owner_deduped_with_root_rung() {
let ladder = credential_ladder((1000, 1000), Some((0, 0)));
assert_eq!(ladder.iter().filter(|p| **p == (0, 0)).count(), 1, "root must appear exactly once");
assert_eq!(ladder[0], (0, 0), "root as owner keeps highest priority");
}
#[test]
fn mode_640_prunes_service_accounts() {
let full = credential_ladder_with((1000, 1000), Some((0, 42)), None, &[]);
let pruned = credential_ladder_with((1000, 1000), Some((0, 42)), Some(0o640), &[]);
assert!(pruned.len() < full.len(), "mode 0640 must shorten the ladder");
assert!(!pruned.contains(&(33, 33)), "www-data cannot read a 0640 file it does not own");
assert!(!pruned.contains(&(65534, 65534)), "nobody cannot read a 0640 file");
assert!(!pruned.contains(&(1000, 1000)), "caller should not appear in pruned ladder");
}
#[test]
fn mode_640_preserves_owner_and_group() {
let pruned = credential_ladder_with((1000, 1000), Some((0, 42)), Some(0o640), &[]);
assert!(pruned.contains(&(0, 42)), "the owner must survive pruning");
assert!(pruned.contains(&(1000, 42)), "caller with owner's group must survive pruning");
}
#[test]
fn mode_600_preserves_root() {
let pruned = credential_ladder_with((1000, 1000), Some((5000, 5000)), Some(0o600), &[]);
assert!(pruned.contains(&(0, 0)), "root must survive 0600 pruning");
}
#[test]
fn mode_644_keeps_full_ladder() {
let full = credential_ladder_with((1000, 1000), Some((0, 42)), None, &[]);
let with_mode = credential_ladder_with((1000, 1000), Some((0, 42)), Some(0o644), &[]);
assert_eq!(full.len(), with_mode.len(), "0644 grants other-read, nothing can be ruled out");
}
#[test]
fn mode_777_keeps_full_ladder() {
let full = credential_ladder_with((1000, 1000), Some((0, 42)), None, &[]);
let with_mode = credential_ladder_with((1000, 1000), Some((0, 42)), Some(0o777), &[]);
assert_eq!(full.len(), with_mode.len(), "0777 grants everything, nothing can be ruled out");
}
#[test]
fn observed_identities_outrank_guesses() {
let ladder = credential_ladder_with((1000, 1000), None, Some(0o644), &[(5000, 5000)]);
let observed_pos = ladder.iter().position(|p| *p == (5000, 5000)).expect("observed pair must be present");
let guess_pos = ladder.iter().position(|p| *p == (33, 33)).expect("www-data guess must be present");
assert!(observed_pos < guess_pos, "observed identity must come before guessed service accounts");
}
#[test]
fn observed_identities_deduped() {
let ladder = credential_ladder_with((1000, 1000), None, None, &[(5000, 5000), (5000, 5000), (6000, 6000)]);
assert_eq!(ladder.iter().filter(|p| **p == (5000, 5000)).count(), 1, "duplicates in observed list must be deduped");
}
#[test]
fn observed_identity_matching_owner_deduped() {
let ladder = credential_ladder_with((1000, 1000), Some((42, 42)), None, &[(42, 42)]);
assert_eq!(ladder.iter().filter(|p| **p == (42, 42)).count(), 1);
assert_eq!(ladder[0], (42, 42), "owner takes priority over observed");
}
#[test]
fn observed_pruned_when_no_other_access() {
let pruned = credential_ladder_with((1000, 1000), Some((500, 500)), Some(0o600), &[(5000, 5000)]);
assert!(!pruned.contains(&(5000, 5000)), "observed identity (5000,5000) cannot access a 0600 file owned by (500,500)");
}
#[test]
fn service_accounts_present_in_full_ladder() {
let ladder = credential_ladder_with((42, 42), None, None, &[]);
let expected = vec![(65534, 65534), (1000, 1000), (33, 33), (27, 27), (26, 26), (1001, 1001), (1002, 1002)];
for pair in &expected {
assert!(ladder.contains(pair), "service account {pair:?} must be in the full ladder");
}
}
#[test]
fn service_accounts_come_after_root() {
let ladder = credential_ladder_with((42, 42), None, None, &[]);
let root_pos = ladder.iter().position(|p| *p == (0, 0)).expect("root must be present");
let nobody_pos = ladder.iter().position(|p| *p == (65534, 65534)).expect("nobody must be present");
assert!(root_pos < nobody_pos, "root must come before service accounts");
}
#[test]
fn caller_is_root_with_root_owner() {
let ladder = credential_ladder((0, 0), Some((0, 0)));
assert_eq!(ladder.iter().filter(|p| **p == (0, 0)).count(), 1);
assert_eq!(ladder[0], (0, 0));
}
#[test]
fn ladder_length_is_bounded() {
let ladder = credential_ladder((42, 42), Some((100, 200)));
assert!(ladder.len() <= 10, "ladder must not exceed 10 entries without observed, got {}", ladder.len());
}
#[test]
fn large_observed_list_handled() {
let observed: Vec<(u32, u32)> = (2000..2100).map(|i| (i, i)).collect();
let ladder = credential_ladder_with((1000, 1000), Some((500, 500)), None, &observed);
assert!(ladder.len() >= 100, "all observed identities must be present");
let mut seen = HashSet::new();
for pair in &ladder {
assert!(seen.insert(*pair), "duplicate {pair:?} in large-observed ladder");
}
}