diff --git a/src/config.rs b/src/config.rs index 0ca4d9c..2337719 100644 --- a/src/config.rs +++ b/src/config.rs @@ -41,6 +41,8 @@ pub struct FileCheck { pub required: bool, #[serde(default = "default_false")] pub is_directory: bool, + #[serde(default)] + pub permissions: Option, } fn default_true() -> bool { diff --git a/src/validators/file.rs b/src/validators/file.rs index 29eb8a9..0c99537 100644 --- a/src/validators/file.rs +++ b/src/validators/file.rs @@ -19,12 +19,15 @@ impl Validator for FileValidator { let path = Path::new(&self.check.path); if path.exists() { + let mut item_passed = true; + if self.check.is_directory { if path.is_dir() { results.push(ValidationResult::success( format!("Directory {} exists", self.check.path), )); } else { + item_passed = false; results.push(ValidationResult::error( format!("{} exists but is not a directory", self.check.path), Some(format!("Ensure {} is a directory", self.check.path)), @@ -35,6 +38,36 @@ impl Validator for FileValidator { format!("{} exists", self.check.path), )); } + + if item_passed { + if let Some(required_perms) = self.check.permissions { + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + if let Ok(metadata) = path.metadata() { + let actual_perms = metadata.permissions().mode() & 0o777; + if actual_perms == required_perms { + results.push(ValidationResult::success( + format!("{} has correct permissions ({:o})", self.check.path, actual_perms), + )); + } else { + results.push(ValidationResult::error( + format!("{} has permissions {:o}, but {:o} is required", + self.check.path, actual_perms, required_perms), + Some(format!("Run 'chmod {:o} {}' to fix", required_perms, self.check.path)), + )); + } + } + } + #[cfg(not(unix))] + { + results.push(ValidationResult::warning( + format!("Permission check skipped for {} (not supported on this platform)", self.check.path), + None, + )); + } + } + } } else { let item_type = if self.check.is_directory { "Directory" } else { "File" }; if self.check.required {