use anyhow::Result;
use landlock::{
make_bitflags, path_beneath_rules, Access, AccessFs, Ruleset, RulesetAttr, RulesetCreatedAttr,
RulesetStatus, ABI,
};
pub fn apply(dir: &std::path::Path) -> Result<()> {
let abi = ABI::V3;
let all_access = AccessFs::from_all(abi);
let read_only = make_bitflags!(AccessFs::{ReadFile | ReadDir | Execute}) & all_access;
let home = dirs::home_dir().unwrap_or_default();
let xdg_data_home = home.join(".local").join("share");
let mut ruleset = Ruleset::default().handle_access(all_access)?.create()?;
ruleset = ruleset.add_rules(path_beneath_rules(["/"], read_only))?;
let mut rw_paths: Vec<&std::path::Path> = vec![dir];
if xdg_data_home.exists() {
rw_paths.push(xdg_data_home.as_path());
}
ruleset = ruleset.add_rules(path_beneath_rules(rw_paths, all_access))?;
let status = ruleset.restrict_self()?;
match status.ruleset {
RulesetStatus::FullyEnforced => {
crate::log_info!(
"Sandbox active (Landlock fully enforced): writes locked to {}",
dir.display()
);
}
RulesetStatus::PartiallyEnforced => {
crate::log_info!(
"Sandbox active (Landlock partially enforced — older kernel): writes locked to {}",
dir.display()
);
}
RulesetStatus::NotEnforced => {
crate::log_info!(
"Sandbox requested but Landlock is not enforced on this kernel — running without restrictions."
);
}
}
Ok(())
}