diff --git a/codex-rs/config/src/config_requirements.rs b/codex-rs/config/src/config_requirements.rs index 59d1cde9eaf7..2567a9a6a32a 100644 --- a/codex-rs/config/src/config_requirements.rs +++ b/codex-rs/config/src/config_requirements.rs @@ -90,6 +90,8 @@ pub struct ConfigRequirements { pub managed_hooks: Option>, pub mcp_servers: Option>>, pub plugins: Option>>, + pub skills: Option>, + pub plugin_marketplaces: Option>, pub exec_policy: Option>, pub enforce_residency: ConstrainedWithSource>, /// Managed network constraints derived from requirements. @@ -123,6 +125,8 @@ impl Default for ConfigRequirements { managed_hooks: None, mcp_servers: None, plugins: None, + skills: None, + plugin_marketplaces: None, exec_policy: None, enforce_residency: ConstrainedWithSource::new( Constrained::allow_any(/*initial_value*/ None), @@ -164,6 +168,57 @@ impl PluginRequirementsToml { } } +#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[serde(rename_all = "lowercase")] +pub enum SkillSourceRequirement { + User, + Repo, + System, + Admin, + Plugin, +} + +#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] +pub struct SkillsRequirementsToml { + pub allowed_sources: Option>, +} + +impl SkillsRequirementsToml { + pub fn is_empty(&self) -> bool { + self.allowed_sources.is_none() + } + + pub fn allows_source(&self, source: SkillSourceRequirement) -> bool { + self.allowed_sources + .as_ref() + .is_none_or(|sources| sources.contains(&source)) + } +} + +#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)] +pub struct PluginMarketplaceRequirementsToml { + pub allowed_names: Option>, + pub allow_user_additions: Option, +} + +impl PluginMarketplaceRequirementsToml { + pub fn is_empty(&self) -> bool { + self.allowed_names.is_none() && self.allow_user_additions.is_none() + } + + pub fn allows_marketplace(&self, marketplace_name: &str) -> bool { + self.allowed_names.as_ref().is_none_or(|allowed_names| { + allowed_names + .iter() + .any(|allowed_name| allowed_name == marketplace_name) + }) + } + + pub fn allows_user_additions(&self) -> bool { + self.allow_user_additions.unwrap_or(true) + } +} + #[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq)] pub struct NetworkDomainPermissionsToml { #[serde(flatten)] @@ -694,6 +749,8 @@ pub struct ConfigRequirementsWithSources { pub hooks: Option>, pub mcp_servers: Option>>, pub plugins: Option>>, + pub skills: Option>, + pub plugin_marketplaces: Option>, pub apps: Option>, pub rules: Option>, pub enforce_residency: Option>, @@ -786,6 +843,8 @@ impl ConfigRequirementsWithSources { hooks, mcp_servers, plugins, + skills: _, + plugin_marketplaces: _, apps, rules, enforce_residency, @@ -923,6 +982,8 @@ impl TryFrom for ConfigRequirements { hooks, mcp_servers, plugins, + skills, + plugin_marketplaces, apps: _apps, rules, enforce_residency, @@ -1158,6 +1219,8 @@ impl TryFrom for ConfigRequirements { managed_hooks, mcp_servers, plugins, + skills, + plugin_marketplaces, exec_policy, enforce_residency, network, @@ -1251,6 +1314,8 @@ mod tests { hooks: hooks.map(|value| Sourced::new(value, RequirementSource::Unknown)), mcp_servers: mcp_servers.map(|value| Sourced::new(value, RequirementSource::Unknown)), plugins: plugins.map(|value| Sourced::new(value, RequirementSource::Unknown)), + skills: None, + plugin_marketplaces: None, apps: apps.map(|value| Sourced::new(value, RequirementSource::Unknown)), rules: rules.map(|value| Sourced::new(value, RequirementSource::Unknown)), enforce_residency: enforce_residency @@ -1330,6 +1395,8 @@ mod tests { hooks: None, mcp_servers: None, plugins: None, + skills: None, + plugin_marketplaces: None, apps: None, rules: None, enforce_residency: Some(Sourced::new(enforce_residency, enforce_source)), @@ -1369,6 +1436,8 @@ mod tests { hooks: None, mcp_servers: None, plugins: None, + skills: None, + plugin_marketplaces: None, apps: None, rules: None, enforce_residency: None, @@ -1416,6 +1485,8 @@ mod tests { hooks: None, mcp_servers: None, plugins: None, + skills: None, + plugin_marketplaces: None, apps: None, rules: None, enforce_residency: None, diff --git a/codex-rs/config/src/lib.rs b/codex-rs/config/src/lib.rs index e88c736db0f8..1841e6ca4b04 100644 --- a/codex-rs/config/src/lib.rs +++ b/codex-rs/config/src/lib.rs @@ -49,11 +49,14 @@ pub use config_requirements::NetworkDomainPermissionsToml; pub use config_requirements::NetworkRequirementsToml; pub use config_requirements::NetworkUnixSocketPermissionToml; pub use config_requirements::NetworkUnixSocketPermissionsToml; +pub use config_requirements::PluginMarketplaceRequirementsToml; pub use config_requirements::PluginRequirementsToml; pub use config_requirements::RemoteSandboxConfigToml; pub use config_requirements::RequirementSource; pub use config_requirements::ResidencyRequirement; pub use config_requirements::SandboxModeRequirement; +pub use config_requirements::SkillSourceRequirement; +pub use config_requirements::SkillsRequirementsToml; pub use config_requirements::Sourced; pub use config_requirements::WebSearchModeRequirement; pub use config_requirements::sandbox_mode_requirement_for_permission_profile; diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index ed355a0ae73f..0952b0fa4944 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -2117,6 +2117,8 @@ impl Config { network: network_requirements, filesystem: filesystem_requirements, guardian_policy_config_source: _, + skills: _, + plugin_marketplaces: _, } = config_layer_stack.requirements().clone(); let user_instructions = AgentsMdManager::load_global_instructions(Some(&codex_home))