Merge branch 'main' into var-expansion

This commit is contained in:
brianm-openai
2026-02-02 16:44:47 -08:00
committed by GitHub
735 changed files with 100049 additions and 1700 deletions

View File

@@ -32,6 +32,12 @@ impl fmt::Debug for CloudRequirementsLoader {
}
}
impl Default for CloudRequirementsLoader {
fn default() -> Self {
Self::new(async { None })
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -52,6 +52,7 @@ pub struct ConfigRequirements {
pub sandbox_policy: Constrained<SandboxPolicy>,
pub mcp_servers: Option<Sourced<BTreeMap<String, McpServerRequirement>>>,
pub(crate) exec_policy: Option<Sourced<RequirementsExecPolicy>>,
pub enforce_residency: Constrained<Option<ResidencyRequirement>>,
}
impl Default for ConfigRequirements {
@@ -61,6 +62,7 @@ impl Default for ConfigRequirements {
sandbox_policy: Constrained::allow_any(SandboxPolicy::ReadOnly),
mcp_servers: None,
exec_policy: None,
enforce_residency: Constrained::allow_any(None),
}
}
}
@@ -84,6 +86,7 @@ pub struct ConfigRequirementsToml {
pub allowed_sandbox_modes: Option<Vec<SandboxModeRequirement>>,
pub mcp_servers: Option<BTreeMap<String, McpServerRequirement>>,
pub rules: Option<RequirementsExecPolicyToml>,
pub enforce_residency: Option<ResidencyRequirement>,
}
/// Value paired with the requirement source it came from, for better error
@@ -114,6 +117,7 @@ pub struct ConfigRequirementsWithSources {
pub allowed_sandbox_modes: Option<Sourced<Vec<SandboxModeRequirement>>>,
pub mcp_servers: Option<Sourced<BTreeMap<String, McpServerRequirement>>>,
pub rules: Option<Sourced<RequirementsExecPolicyToml>>,
pub enforce_residency: Option<Sourced<ResidencyRequirement>>,
}
impl ConfigRequirementsWithSources {
@@ -146,6 +150,7 @@ impl ConfigRequirementsWithSources {
allowed_sandbox_modes,
mcp_servers,
rules,
enforce_residency,
}
);
}
@@ -156,12 +161,14 @@ impl ConfigRequirementsWithSources {
allowed_sandbox_modes,
mcp_servers,
rules,
enforce_residency,
} = self;
ConfigRequirementsToml {
allowed_approval_policies: allowed_approval_policies.map(|sourced| sourced.value),
allowed_sandbox_modes: allowed_sandbox_modes.map(|sourced| sourced.value),
mcp_servers: mcp_servers.map(|sourced| sourced.value),
rules: rules.map(|sourced| sourced.value),
enforce_residency: enforce_residency.map(|sourced| sourced.value),
}
}
}
@@ -193,12 +200,19 @@ impl From<SandboxMode> for SandboxModeRequirement {
}
}
#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum ResidencyRequirement {
Us,
}
impl ConfigRequirementsToml {
pub fn is_empty(&self) -> bool {
self.allowed_approval_policies.is_none()
&& self.allowed_sandbox_modes.is_none()
&& self.mcp_servers.is_none()
&& self.rules.is_none()
&& self.enforce_residency.is_none()
}
}
@@ -211,6 +225,7 @@ impl TryFrom<ConfigRequirementsWithSources> for ConfigRequirements {
allowed_sandbox_modes,
mcp_servers,
rules,
enforce_residency,
} = toml;
let approval_policy: Constrained<AskForApproval> = match allowed_approval_policies {
@@ -298,11 +313,33 @@ impl TryFrom<ConfigRequirementsWithSources> for ConfigRequirements {
None => None,
};
let enforce_residency: Constrained<Option<ResidencyRequirement>> = match enforce_residency {
Some(Sourced {
value: residency,
source: requirement_source,
}) => {
let required = Some(residency);
Constrained::new(required, move |candidate| {
if candidate == &required {
Ok(())
} else {
Err(ConstraintError::InvalidValue {
field_name: "enforce_residency",
candidate: format!("{candidate:?}"),
allowed: format!("{required:?}"),
requirement_source: requirement_source.clone(),
})
}
})?
}
None => Constrained::allow_any(None),
};
Ok(ConfigRequirements {
approval_policy,
sandbox_policy,
mcp_servers,
exec_policy,
enforce_residency,
})
}
}
@@ -329,6 +366,7 @@ mod tests {
allowed_sandbox_modes,
mcp_servers,
rules,
enforce_residency,
} = toml;
ConfigRequirementsWithSources {
allowed_approval_policies: allowed_approval_policies
@@ -337,6 +375,8 @@ mod tests {
.map(|value| Sourced::new(value, RequirementSource::Unknown)),
mcp_servers: mcp_servers.map(|value| Sourced::new(value, RequirementSource::Unknown)),
rules: rules.map(|value| Sourced::new(value, RequirementSource::Unknown)),
enforce_residency: enforce_residency
.map(|value| Sourced::new(value, RequirementSource::Unknown)),
}
}
@@ -350,6 +390,8 @@ mod tests {
SandboxModeRequirement::WorkspaceWrite,
SandboxModeRequirement::DangerFullAccess,
];
let enforce_residency = ResidencyRequirement::Us;
let enforce_source = source.clone();
// Intentionally constructed without `..Default::default()` so adding a new field to
// `ConfigRequirementsToml` forces this test to be updated.
@@ -358,6 +400,7 @@ mod tests {
allowed_sandbox_modes: Some(allowed_sandbox_modes.clone()),
mcp_servers: None,
rules: None,
enforce_residency: Some(enforce_residency),
};
target.merge_unset_fields(source.clone(), other);
@@ -372,6 +415,7 @@ mod tests {
allowed_sandbox_modes: Some(Sourced::new(allowed_sandbox_modes, source)),
mcp_servers: None,
rules: None,
enforce_residency: Some(Sourced::new(enforce_residency, enforce_source)),
}
);
}
@@ -401,6 +445,7 @@ mod tests {
allowed_sandbox_modes: None,
mcp_servers: None,
rules: None,
enforce_residency: None,
}
);
Ok(())
@@ -438,6 +483,7 @@ mod tests {
allowed_sandbox_modes: None,
mcp_servers: None,
rules: None,
enforce_residency: None,
}
);
Ok(())

View File

@@ -40,6 +40,7 @@ pub use config_requirements::ConfigRequirementsToml;
pub use config_requirements::McpServerIdentity;
pub use config_requirements::McpServerRequirement;
pub use config_requirements::RequirementSource;
pub use config_requirements::ResidencyRequirement;
pub use config_requirements::SandboxModeRequirement;
pub use config_requirements::Sourced;
pub use diagnostics::ConfigError;
@@ -187,7 +188,7 @@ pub async fn load_config_layers_state(
cwd: Option<AbsolutePathBuf>,
cli_overrides: &[(String, TomlValue)],
overrides: LoaderOverrides,
cloud_requirements: Option<CloudRequirementsLoader>, // TODO(gt): Once exec and app-server are wired up, we can remove the option.
cloud_requirements: CloudRequirementsLoader,
) -> io::Result<ConfigLayerStack> {
load_config_layers_state_with_env(
codex_home,
@@ -219,9 +220,7 @@ async fn load_config_layers_state_with_env(
)
.await?;
if let Some(loader) = cloud_requirements
&& let Some(requirements) = loader.get().await
{
if let Some(requirements) = cloud_requirements.get().await {
config_requirements_toml
.merge_unset_fields(RequirementSource::CloudRequirements, requirements);
}
@@ -554,7 +553,9 @@ async fn load_requirements_from_legacy_scheme(
/// empty array, which indicates that root detection should be disabled).
/// - Returns an error if `project_root_markers` is specified but is not an
/// array of strings.
fn project_root_markers_from_config(config: &TomlValue) -> io::Result<Option<Vec<String>>> {
pub(crate) fn project_root_markers_from_config(
config: &TomlValue,
) -> io::Result<Option<Vec<String>>> {
let Some(table) = config.as_table() else {
return Ok(None);
};
@@ -583,7 +584,7 @@ fn project_root_markers_from_config(config: &TomlValue) -> io::Result<Option<Vec
Ok(Some(markers))
}
fn default_project_root_markers() -> Vec<String> {
pub(crate) fn default_project_root_markers() -> Vec<String> {
DEFAULT_PROJECT_ROOT_MARKERS
.iter()
.map(ToString::to_string)

View File

@@ -76,7 +76,7 @@ async fn returns_config_error_for_invalid_user_config_toml() {
Some(cwd),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await
.expect_err("expected error");
@@ -106,7 +106,7 @@ async fn returns_config_error_for_invalid_managed_config_toml() {
Some(cwd),
&[] as &[(String, TomlValue)],
overrides,
None,
CloudRequirementsLoader::default(),
)
.await
.expect_err("expected error");
@@ -195,7 +195,7 @@ extra = true
Some(cwd),
&[] as &[(String, TomlValue)],
overrides,
None,
CloudRequirementsLoader::default(),
)
.await
.expect("load config");
@@ -232,7 +232,7 @@ async fn returns_empty_when_all_layers_missing() {
Some(cwd),
&[] as &[(String, TomlValue)],
overrides,
None,
CloudRequirementsLoader::default(),
)
.await
.expect("load layers");
@@ -331,7 +331,7 @@ flag = false
Some(cwd),
&[] as &[(String, TomlValue)],
overrides,
None,
CloudRequirementsLoader::default(),
)
.await
.expect("load config");
@@ -371,7 +371,7 @@ allowed_sandbox_modes = ["read-only"]
),
),
},
None,
CloudRequirementsLoader::default(),
)
.await?;
@@ -622,7 +622,7 @@ allowed_approval_policies = ["never"]
),
),
},
None,
CloudRequirementsLoader::default(),
)
.await?;
@@ -649,6 +649,7 @@ async fn load_requirements_toml_produces_expected_constraints() -> anyhow::Resul
&requirements_file,
r#"
allowed_approval_policies = ["never", "on-request"]
enforce_residency = "us"
"#,
)
.await?;
@@ -663,7 +664,6 @@ allowed_approval_policies = ["never", "on-request"]
.cloned(),
Some(vec![AskForApproval::Never, AskForApproval::OnRequest])
);
let config_requirements: ConfigRequirements = config_requirements_toml.try_into()?;
assert_eq!(
config_requirements.approval_policy.value(),
@@ -678,6 +678,10 @@ allowed_approval_policies = ["never", "on-request"]
.can_set(&AskForApproval::OnFailure)
.is_err()
);
assert_eq!(
config_requirements.enforce_residency.value(),
Some(crate::config_loader::ResidencyRequirement::Us)
);
Ok(())
}
@@ -701,6 +705,7 @@ allowed_approval_policies = ["on-request"]
allowed_sandbox_modes: None,
mcp_servers: None,
rules: None,
enforce_residency: None,
},
);
load_requirements_toml(&mut config_requirements_toml, &requirements_file).await?;
@@ -735,6 +740,7 @@ async fn load_config_layers_includes_cloud_requirements() -> anyhow::Result<()>
allowed_sandbox_modes: None,
mcp_servers: None,
rules: None,
enforce_residency: None,
};
let expected = requirements.clone();
let cloud_requirements = CloudRequirementsLoader::new(async move { Some(requirements) });
@@ -744,7 +750,7 @@ async fn load_config_layers_includes_cloud_requirements() -> anyhow::Result<()>
Some(cwd),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
Some(cloud_requirements),
cloud_requirements,
)
.await?;
@@ -797,7 +803,7 @@ async fn project_layers_prefer_closest_cwd() -> std::io::Result<()> {
Some(cwd),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;
@@ -929,7 +935,7 @@ async fn project_layer_is_added_when_dot_codex_exists_without_config_toml() -> s
Some(cwd),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;
@@ -968,7 +974,7 @@ async fn codex_home_is_not_loaded_as_project_layer_from_home_dir() -> std::io::R
Some(cwd),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;
@@ -1018,7 +1024,7 @@ async fn codex_home_within_project_tree_is_not_double_loaded() -> std::io::Resul
Some(cwd),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;
@@ -1088,7 +1094,7 @@ async fn project_layers_disabled_when_untrusted_or_unknown() -> std::io::Result<
Some(cwd.clone()),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;
let project_layers_untrusted: Vec<_> = layers_untrusted
@@ -1126,7 +1132,7 @@ async fn project_layers_disabled_when_untrusted_or_unknown() -> std::io::Result<
Some(cwd),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;
let project_layers_unknown: Vec<_> = layers_unknown
@@ -1240,7 +1246,7 @@ async fn invalid_project_config_ignored_when_untrusted_or_unknown() -> std::io::
Some(cwd.clone()),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;
let project_layers: Vec<_> = layers
@@ -1296,7 +1302,7 @@ async fn cli_overrides_with_relative_paths_do_not_break_trust_check() -> std::io
Some(cwd),
&cli_overrides,
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;
@@ -1338,7 +1344,7 @@ async fn project_root_markers_supports_alternate_markers() -> std::io::Result<()
Some(cwd),
&[] as &[(String, TomlValue)],
LoaderOverrides::default(),
None,
CloudRequirementsLoader::default(),
)
.await?;