fix(config): merge nested permissions requirements

Co-authored-by: Codex noreply@openai.com
This commit is contained in:
viyatb-oai
2026-06-01 12:41:50 -07:00
parent 2391848e69
commit 4c688697db

View File

@@ -991,11 +991,21 @@ impl ConfigRequirementsWithSources {
rules,
enforce_residency,
network,
permissions,
guardian_policy_config,
}
);
if let Some(incoming_permissions) = other.permissions.take() {
if let Some(existing_permissions) = self.permissions.as_mut() {
merge_permissions_requirements_descending(
&mut existing_permissions.value,
incoming_permissions,
);
} else {
self.permissions = Some(Sourced::new(incoming_permissions, source.clone()));
}
}
if let Some(incoming_apps) = other.apps.take() {
if let Some(existing_apps) = self.apps.as_mut() {
merge_app_requirements_descending(&mut existing_apps.value, incoming_apps);
@@ -1054,6 +1064,21 @@ impl ConfigRequirementsWithSources {
}
}
fn merge_permissions_requirements_descending(
existing: &mut PermissionsRequirementsToml,
mut incoming: PermissionsRequirementsToml,
) {
if existing.filesystem.is_none() {
existing.filesystem = incoming.filesystem.take();
}
if existing.network.is_none() {
existing.network = incoming.network.take();
}
for (profile_id, profile) in incoming.profiles {
existing.profiles.entry(profile_id).or_insert(profile);
}
}
fn normalize_hostname(hostname: &str) -> Option<String> {
let hostname = hostname.trim().trim_end_matches('.');
(!hostname.is_empty()).then(|| hostname.to_ascii_lowercase())
@@ -1965,6 +1990,62 @@ mod tests {
Ok(())
}
#[test]
fn merge_unset_fields_merges_nested_permissions_requirements() -> Result<()> {
let deny_read = if cfg!(windows) {
r"C:\Users\alice\.ssh"
} else {
"/home/alice/.ssh"
};
let high_precedence: ConfigRequirementsToml = from_str(&format!(
r#"
[permissions.filesystem]
deny_read = [{deny_read:?}]
"#
))?;
let low_precedence: ConfigRequirementsToml = from_str(
r#"
[permissions.network]
enabled = true
[permissions.managed]
sandbox_mode = "workspace-write"
"#,
)?;
let mut target = ConfigRequirementsWithSources::default();
target.merge_unset_fields(RequirementSource::CloudRequirements, high_precedence);
target.merge_unset_fields(RequirementSource::Unknown, low_precedence);
let merged_toml = target.clone().into_toml();
let requirements = ConfigRequirements::try_from(target)?;
assert!(
merged_toml
.permissions
.as_ref()
.is_some_and(|permissions| permissions.profiles.contains_key("managed"))
);
assert_eq!(
requirements.filesystem,
Some(Sourced::new(
FilesystemConstraints {
deny_read: vec![AbsolutePathBuf::from_absolute_path(deny_read)?.into()],
},
RequirementSource::CloudRequirements,
))
);
assert_eq!(
requirements
.network
.expect("network requirements should merge")
.value
.enabled,
Some(true)
);
Ok(())
}
#[test]
fn merge_unset_fields_ignores_blank_guardian_override() {
let mut target = ConfigRequirementsWithSources::default();