config/src/requirements_layers/permissions.rs
82 lines
//! `permissions.filesystem.deny_read` is intentionally additive across//! requirements layers. Other `[permissions]` content stays in the regular TOML//! merge path so permission profile tables follow config-style precedence.use crate::FilesystemDenyReadPattern;use crate::RequirementSource;use crate::Sourced;use crate::config_requirements::FilesystemRequirementsToml;use crate::config_requirements::PermissionsRequirementsToml;use super::stack::merge_output_source;#[derive(Default)]pub(super) struct DenyReadMergeState { deny_read: Vec<FilesystemDenyReadPattern>, source: Option<RequirementSource>,}impl DenyReadMergeState { pub(super) fn merge( &mut self, incoming: Option<PermissionsRequirementsToml>, source: &RequirementSource, ) { let Some(incoming_deny_read) = incoming .and_then(|permissions| permissions.filesystem) .and_then(|filesystem| filesystem.deny_read) .filter(|deny_read| !deny_read.is_empty()) else { return; }; for pattern in incoming_deny_read { if !self.deny_read.contains(&pattern) { self.deny_read.push(pattern); self.merge_source(source); } } } pub(super) fn apply_to(self, target: &mut Option<Sourced<PermissionsRequirementsToml>>) { if self.deny_read.is_empty() { return; } let source = self.source.unwrap_or(RequirementSource::Unknown); let Some(existing) = target.as_mut() else { *target = Some(Sourced::new( PermissionsRequirementsToml { filesystem: Some(FilesystemRequirementsToml { deny_read: Some(self.deny_read), }), profiles: Default::default(), }, source, )); return; }; let filesystem = existing .value .filesystem .get_or_insert_with(Default::default); let deny_read = filesystem.deny_read.get_or_insert_with(Vec::new); for pattern in self.deny_read { if !deny_read.contains(&pattern) { deny_read.push(pattern); } } if existing.source != source { existing.source = RequirementSource::composite([existing.source.clone(), source]); } } fn merge_source(&mut self, source: &RequirementSource) { let Some(existing) = self.source.as_mut() else { self.source = Some(source.clone()); return; }; merge_output_source(existing, source); }}