Update guardian output schema (#17061)

## Summary
- Update guardian output schema to separate risk, authorization,
outcome, and rationale.
- Feed guardian rationale into rejection messages.
- Split the guardian policy into template and tenant-config sections.

## Validation
- `cargo test -p codex-core mcp_tool_call`
- `env -u CODEX_SANDBOX_NETWORK_DISABLED INSTA_UPDATE=always cargo test
-p codex-core guardian::`

---------

Co-authored-by: Owen Lin <owen@openai.com>
This commit is contained in:
maja-openai
2026-04-08 15:47:29 -07:00
committed by GitHub
parent 49677ec71f
commit dcbc91fd39
45 changed files with 673 additions and 312 deletions

View File

@@ -514,7 +514,7 @@ pub struct ConfigRequirementsToml {
pub enforce_residency: Option<ResidencyRequirement>,
#[serde(rename = "experimental_network")]
pub network: Option<NetworkRequirementsToml>,
pub guardian_developer_instructions: Option<String>,
pub guardian_policy_config: Option<String>,
}
/// Value paired with the requirement source it came from, for better error
@@ -551,7 +551,7 @@ pub struct ConfigRequirementsWithSources {
pub rules: Option<Sourced<RequirementsExecPolicyToml>>,
pub enforce_residency: Option<Sourced<ResidencyRequirement>>,
pub network: Option<Sourced<NetworkRequirementsToml>>,
pub guardian_developer_instructions: Option<Sourced<String>>,
pub guardian_policy_config: Option<Sourced<String>>,
}
impl ConfigRequirementsWithSources {
@@ -583,16 +583,16 @@ impl ConfigRequirementsWithSources {
rules: _,
enforce_residency: _,
network: _,
guardian_developer_instructions: _,
guardian_policy_config: _,
} = &other;
let mut other = other;
if other
.guardian_developer_instructions
.guardian_policy_config
.as_deref()
.is_some_and(|value| value.trim().is_empty())
{
other.guardian_developer_instructions = None;
other.guardian_policy_config = None;
}
fill_missing_take!(
self,
@@ -608,7 +608,7 @@ impl ConfigRequirementsWithSources {
rules,
enforce_residency,
network,
guardian_developer_instructions,
guardian_policy_config,
}
);
@@ -633,7 +633,7 @@ impl ConfigRequirementsWithSources {
rules,
enforce_residency,
network,
guardian_developer_instructions,
guardian_policy_config,
} = self;
ConfigRequirementsToml {
allowed_approval_policies: allowed_approval_policies.map(|sourced| sourced.value),
@@ -646,8 +646,7 @@ impl ConfigRequirementsWithSources {
rules: rules.map(|sourced| sourced.value),
enforce_residency: enforce_residency.map(|sourced| sourced.value),
network: network.map(|sourced| sourced.value),
guardian_developer_instructions: guardian_developer_instructions
.map(|sourced| sourced.value),
guardian_policy_config: guardian_policy_config.map(|sourced| sourced.value),
}
}
}
@@ -704,7 +703,7 @@ impl ConfigRequirementsToml {
&& self.enforce_residency.is_none()
&& self.network.is_none()
&& self
.guardian_developer_instructions
.guardian_policy_config
.as_deref()
.is_none_or(|value| value.trim().is_empty())
}
@@ -725,7 +724,7 @@ impl TryFrom<ConfigRequirementsWithSources> for ConfigRequirements {
rules,
enforce_residency,
network,
guardian_developer_instructions: _guardian_developer_instructions,
guardian_policy_config: _guardian_policy_config,
} = toml;
let approval_policy = match allowed_approval_policies {
@@ -978,7 +977,7 @@ mod tests {
rules,
enforce_residency,
network,
guardian_developer_instructions,
guardian_policy_config,
} = toml;
ConfigRequirementsWithSources {
allowed_approval_policies: allowed_approval_policies
@@ -997,7 +996,7 @@ mod tests {
enforce_residency: enforce_residency
.map(|value| Sourced::new(value, RequirementSource::Unknown)),
network: network.map(|value| Sourced::new(value, RequirementSource::Unknown)),
guardian_developer_instructions: guardian_developer_instructions
guardian_policy_config: guardian_policy_config
.map(|value| Sourced::new(value, RequirementSource::Unknown)),
}
}
@@ -1023,8 +1022,7 @@ mod tests {
};
let enforce_residency = ResidencyRequirement::Us;
let enforce_source = source.clone();
let guardian_developer_instructions =
"Use the company-managed guardian policy.".to_string();
let guardian_policy_config = "Use the company-managed guardian policy.".to_string();
// Intentionally constructed without `..Default::default()` so adding a new field to
// `ConfigRequirementsToml` forces this test to be updated.
@@ -1039,7 +1037,7 @@ mod tests {
rules: None,
enforce_residency: Some(enforce_residency),
network: None,
guardian_developer_instructions: Some(guardian_developer_instructions.clone()),
guardian_policy_config: Some(guardian_policy_config.clone()),
};
target.merge_unset_fields(source.clone(), other);
@@ -1069,10 +1067,7 @@ mod tests {
rules: None,
enforce_residency: Some(Sourced::new(enforce_residency, enforce_source)),
network: None,
guardian_developer_instructions: Some(Sourced::new(
guardian_developer_instructions,
source,
)),
guardian_policy_config: Some(Sourced::new(guardian_policy_config, source)),
}
);
}
@@ -1108,7 +1103,7 @@ mod tests {
rules: None,
enforce_residency: None,
network: None,
guardian_developer_instructions: None,
guardian_policy_config: None,
}
);
Ok(())
@@ -1152,7 +1147,7 @@ mod tests {
rules: None,
enforce_residency: None,
network: None,
guardian_developer_instructions: None,
guardian_policy_config: None,
}
);
Ok(())
@@ -1164,7 +1159,7 @@ mod tests {
target.merge_unset_fields(
RequirementSource::CloudRequirements,
ConfigRequirementsToml {
guardian_developer_instructions: Some(" \n\t".to_string()),
guardian_policy_config: Some(" \n\t".to_string()),
..Default::default()
},
);
@@ -1174,15 +1169,13 @@ mod tests {
.expect("system requirements.toml path"),
},
ConfigRequirementsToml {
guardian_developer_instructions: Some(
"Use the system guardian policy.".to_string(),
),
guardian_policy_config: Some("Use the system guardian policy.".to_string()),
..Default::default()
},
);
assert_eq!(
target.guardian_developer_instructions,
target.guardian_policy_config,
Some(Sourced::new(
"Use the system guardian policy.".to_string(),
RequirementSource::SystemRequirementsToml {
@@ -1194,27 +1187,27 @@ mod tests {
}
#[test]
fn deserialize_guardian_developer_instructions() -> Result<()> {
fn deserialize_guardian_policy_config() -> Result<()> {
let requirements: ConfigRequirementsToml = from_str(
r#"
guardian_developer_instructions = """
guardian_policy_config = """
Use the cloud-managed guardian policy.
"""
"#,
)?;
assert_eq!(
requirements.guardian_developer_instructions.as_deref(),
requirements.guardian_policy_config.as_deref(),
Some("Use the cloud-managed guardian policy.\n")
);
Ok(())
}
#[test]
fn blank_guardian_developer_instructions_is_empty() -> Result<()> {
fn blank_guardian_policy_config_is_empty() -> Result<()> {
let requirements: ConfigRequirementsToml = from_str(
r#"
guardian_developer_instructions = """
guardian_policy_config = """
"""
"#,