mirror of
https://github.com/openai/codex.git
synced 2026-05-21 19:45:26 +00:00
Compare commits
1 Commits
xl/plugins
...
xl/req
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06e71ab184 |
@@ -7546,6 +7546,12 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowPluginSharing": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowedApprovalPolicies": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/v2/AskForApproval"
|
||||
|
||||
@@ -3935,6 +3935,12 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowPluginSharing": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowedApprovalPolicies": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/AskForApproval"
|
||||
|
||||
@@ -68,6 +68,12 @@
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowPluginSharing": {
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"allowedApprovalPolicies": {
|
||||
"items": {
|
||||
"$ref": "#/definitions/AskForApproval"
|
||||
|
||||
@@ -6,4 +6,4 @@ import type { AskForApproval } from "./AskForApproval";
|
||||
import type { ResidencyRequirement } from "./ResidencyRequirement";
|
||||
import type { SandboxMode } from "./SandboxMode";
|
||||
|
||||
export type ConfigRequirements = {allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWebSearchModes: Array<WebSearchMode> | null, allowManagedHooksOnly: boolean | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null};
|
||||
export type ConfigRequirements = {allowedApprovalPolicies: Array<AskForApproval> | null, allowedSandboxModes: Array<SandboxMode> | null, allowedWebSearchModes: Array<WebSearchMode> | null, allowManagedHooksOnly: boolean | null, allowPluginSharing: boolean | null, featureRequirements: { [key in string]?: boolean } | null, enforceResidency: ResidencyRequirement | null};
|
||||
|
||||
@@ -358,6 +358,7 @@ pub struct ConfigRequirements {
|
||||
pub allowed_sandbox_modes: Option<Vec<SandboxMode>>,
|
||||
pub allowed_web_search_modes: Option<Vec<WebSearchMode>>,
|
||||
pub allow_managed_hooks_only: Option<bool>,
|
||||
pub allow_plugin_sharing: Option<bool>,
|
||||
pub feature_requirements: Option<BTreeMap<String, bool>>,
|
||||
#[experimental("configRequirements/read.hooks")]
|
||||
pub hooks: Option<ManagedHooksRequirements>,
|
||||
|
||||
@@ -1689,6 +1689,7 @@ fn config_requirements_granular_allowed_approval_policy_is_marked_experimental()
|
||||
allowed_sandbox_modes: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
enforce_residency: None,
|
||||
|
||||
@@ -219,7 +219,7 @@ Example with notification opt-out:
|
||||
- `externalAgentConfig/import` — apply selected external-agent migration items by passing explicit `migrationItems` with `cwd` (`null` for home) and any plugin/session `details` returned by detect. When a request includes migration items, the server emits `externalAgentConfig/import/completed` once after the full import finishes (immediately after the response when everything completed synchronously, or after background imports finish).
|
||||
- `config/value/write` — write a single config key/value to the user's config.toml on disk.
|
||||
- `config/batchWrite` — apply multiple config edits atomically to the user's config.toml on disk, with optional `reloadUserConfig: true` to hot-reload loaded threads.
|
||||
- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), lifecycle hook lockdown (`allowManagedHooksOnly`), pinned feature values (`featureRequirements`), managed lifecycle hooks (`hooks`), `enforceResidency`, and `network` constraints such as canonical domain/socket permissions plus `managedAllowedDomainsOnly` and `dangerFullAccessDenylistOnly`.
|
||||
- `configRequirements/read` — fetch loaded requirements constraints from `requirements.toml` and/or MDM (or `null` if none are configured), including allow-lists (`allowedApprovalPolicies`, `allowedSandboxModes`, `allowedWebSearchModes`), lifecycle hook lockdown (`allowManagedHooksOnly`), plugin sharing control (`allowPluginSharing`), pinned feature values (`featureRequirements`), managed lifecycle hooks (`hooks`), `enforceResidency`, and `network` constraints such as canonical domain/socket permissions plus `managedAllowedDomainsOnly` and `dangerFullAccessDenylistOnly`.
|
||||
|
||||
### Example: Start or resume a thread
|
||||
|
||||
|
||||
@@ -430,6 +430,7 @@ fn map_requirements_toml_to_api(requirements: ConfigRequirementsToml) -> ConfigR
|
||||
normalized
|
||||
}),
|
||||
allow_managed_hooks_only: requirements.allow_managed_hooks_only,
|
||||
allow_plugin_sharing: requirements.allow_plugin_sharing,
|
||||
feature_requirements: requirements
|
||||
.feature_requirements
|
||||
.map(|requirements| requirements.entries),
|
||||
@@ -623,10 +624,12 @@ mod tests {
|
||||
fn requirements_api_includes_allow_managed_hooks_only() {
|
||||
let mapped = map_requirements_toml_to_api(ConfigRequirementsToml {
|
||||
allow_managed_hooks_only: Some(true),
|
||||
allow_plugin_sharing: Some(false),
|
||||
..ConfigRequirementsToml::default()
|
||||
});
|
||||
|
||||
assert_eq!(mapped.allow_managed_hooks_only, Some(true));
|
||||
assert_eq!(mapped.allow_plugin_sharing, Some(false));
|
||||
assert_eq!(mapped.hooks, None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +536,10 @@ impl PluginRequestProcessor {
|
||||
remote_sources.push(RemoteMarketplaceSource::WorkspaceDirectory);
|
||||
}
|
||||
if marketplace_kinds.contains(&PluginListMarketplaceKind::SharedWithMe)
|
||||
&& config.features.enabled(Feature::PluginSharing)
|
||||
&& config
|
||||
.config_layer_stack
|
||||
.requirements()
|
||||
.allow_plugin_sharing()
|
||||
{
|
||||
remote_sources.push(RemoteMarketplaceSource::SharedWithMe);
|
||||
}
|
||||
@@ -849,7 +852,11 @@ impl PluginRequestProcessor {
|
||||
params: PluginShareSaveParams,
|
||||
) -> Result<PluginShareSaveResponse, JSONRPCErrorError> {
|
||||
let (config, auth) = self.load_plugin_share_config_and_auth().await?;
|
||||
if !config.features.enabled(Feature::PluginSharing) {
|
||||
if !config
|
||||
.config_layer_stack
|
||||
.requirements()
|
||||
.allow_plugin_sharing()
|
||||
{
|
||||
return Err(invalid_request("plugin sharing is disabled"));
|
||||
}
|
||||
let PluginShareSaveParams {
|
||||
|
||||
@@ -24,6 +24,7 @@ use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use flate2::Compression;
|
||||
use flate2::write::GzEncoder;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
use tempfile::TempDir;
|
||||
use tokio::time::timeout;
|
||||
use wiremock::Mock;
|
||||
@@ -1898,9 +1899,16 @@ async fn plugin_list_fetches_shared_with_me_kind() -> Result<()> {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn plugin_list_omits_shared_with_me_kind_when_plugin_sharing_disabled() -> Result<()> {
|
||||
async fn plugin_list_omits_shared_with_me_when_sharing_disallowed_by_requirements() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("GET"))
|
||||
.and(path("/backend-api/wham/config/requirements"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
|
||||
"contents": "allow_plugin_sharing = false\n",
|
||||
})))
|
||||
.mount(&server)
|
||||
.await;
|
||||
std::fs::write(
|
||||
codex_home.path().join("config.toml"),
|
||||
format!(
|
||||
@@ -1908,7 +1916,6 @@ async fn plugin_list_omits_shared_with_me_kind_when_plugin_sharing_disabled() ->
|
||||
|
||||
[features]
|
||||
plugins = true
|
||||
plugin_sharing = false
|
||||
"#,
|
||||
server.uri()
|
||||
),
|
||||
@@ -1917,6 +1924,7 @@ plugin_sharing = false
|
||||
codex_home.path(),
|
||||
ChatGptAuthFixture::new("chatgpt-token")
|
||||
.account_id("account-123")
|
||||
.plan_type("business")
|
||||
.chatgpt_user_id("user-123")
|
||||
.chatgpt_account_id("account-123"),
|
||||
AuthCredentialsStoreMode::File,
|
||||
|
||||
@@ -324,11 +324,18 @@ async fn plugin_share_save_rejects_listed_discoverability() -> Result<()> {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn plugin_share_save_rejects_when_plugin_sharing_disabled() -> Result<()> {
|
||||
async fn plugin_share_save_rejects_when_plugin_sharing_disallowed_by_requirements() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let plugin_root = TempDir::new()?;
|
||||
let plugin_path = write_test_plugin(plugin_root.path(), "demo-plugin")?;
|
||||
let server = MockServer::start().await;
|
||||
Mock::given(method("GET"))
|
||||
.and(path("/backend-api/wham/config/requirements"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
|
||||
"contents": "allow_plugin_sharing = false\n",
|
||||
})))
|
||||
.mount(&server)
|
||||
.await;
|
||||
std::fs::write(
|
||||
codex_home.path().join("config.toml"),
|
||||
format!(
|
||||
@@ -338,7 +345,6 @@ chatgpt_base_url = "{}/backend-api"
|
||||
[features]
|
||||
plugins = true
|
||||
remote_plugin = true
|
||||
plugin_sharing = false
|
||||
"#,
|
||||
server.uri()
|
||||
),
|
||||
@@ -347,6 +353,7 @@ plugin_sharing = false
|
||||
codex_home.path(),
|
||||
ChatGptAuthFixture::new("chatgpt-token")
|
||||
.account_id("account-123")
|
||||
.plan_type("business")
|
||||
.chatgpt_user_id("user-123")
|
||||
.chatgpt_account_id("account-123"),
|
||||
AuthCredentialsStoreMode::File,
|
||||
@@ -376,7 +383,14 @@ plugin_sharing = false
|
||||
.received_requests()
|
||||
.await
|
||||
.expect("wiremock should record requests")
|
||||
.is_empty()
|
||||
.iter()
|
||||
.all(|request| {
|
||||
!(request.method == "POST"
|
||||
&& request
|
||||
.url
|
||||
.path()
|
||||
.starts_with("/backend-api/public/plugins/workspace"))
|
||||
})
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1191,7 +1191,10 @@ mod tests {
|
||||
let service = CloudRequirementsService::new(
|
||||
auth_manager_with_plan("business").await,
|
||||
Arc::new(StaticFetcher {
|
||||
contents: Some("allowed_approval_policies = [\"never\"]".to_string()),
|
||||
contents: Some(
|
||||
"allowed_approval_policies = [\"never\"]\nallow_plugin_sharing = false\n"
|
||||
.to_string(),
|
||||
),
|
||||
}),
|
||||
codex_home.path().to_path_buf(),
|
||||
CLOUD_REQUIREMENTS_TIMEOUT,
|
||||
@@ -1205,6 +1208,7 @@ mod tests {
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: Some(false),
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1288,6 +1292,7 @@ mod tests {
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1322,6 +1327,7 @@ mod tests {
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1373,6 +1379,7 @@ mod tests {
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1524,6 +1531,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1605,6 +1613,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1684,6 +1693,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1891,6 +1901,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1932,6 +1943,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -1993,6 +2005,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -2050,6 +2063,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -2109,6 +2123,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -2169,6 +2184,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -2229,6 +2245,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -2319,6 +2336,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
@@ -2351,6 +2369,7 @@ command = "sample-mcp"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
|
||||
@@ -88,6 +88,7 @@ pub struct ConfigRequirements {
|
||||
pub permission_profile: ConstrainedWithSource<PermissionProfile>,
|
||||
pub web_search_mode: ConstrainedWithSource<WebSearchMode>,
|
||||
pub allow_managed_hooks_only: Option<Sourced<bool>>,
|
||||
pub allow_plugin_sharing: Option<Sourced<bool>>,
|
||||
pub feature_requirements: Option<Sourced<FeatureRequirementsToml>>,
|
||||
pub managed_hooks: Option<ConstrainedWithSource<ManagedHooksRequirementsToml>>,
|
||||
pub mcp_servers: Option<Sourced<BTreeMap<String, McpServerRequirement>>>,
|
||||
@@ -122,6 +123,7 @@ impl Default for ConfigRequirements {
|
||||
/*source*/ None,
|
||||
),
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
managed_hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -142,6 +144,13 @@ impl ConfigRequirements {
|
||||
pub fn exec_policy_source(&self) -> Option<&RequirementSource> {
|
||||
self.exec_policy.as_ref().map(|policy| &policy.source)
|
||||
}
|
||||
|
||||
pub fn allow_plugin_sharing(&self) -> bool {
|
||||
self.allow_plugin_sharing
|
||||
.as_ref()
|
||||
.map(|sourced| sourced.value)
|
||||
.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
@@ -691,6 +700,7 @@ pub struct ConfigRequirementsToml {
|
||||
pub remote_sandbox_config: Option<Vec<RemoteSandboxConfigToml>>,
|
||||
pub allowed_web_search_modes: Option<Vec<WebSearchModeRequirement>>,
|
||||
pub allow_managed_hooks_only: Option<bool>,
|
||||
pub allow_plugin_sharing: Option<bool>,
|
||||
#[serde(rename = "features", alias = "feature_requirements")]
|
||||
pub feature_requirements: Option<FeatureRequirementsToml>,
|
||||
pub hooks: Option<ManagedHooksRequirementsToml>,
|
||||
@@ -740,6 +750,7 @@ pub struct ConfigRequirementsWithSources {
|
||||
pub allowed_sandbox_modes: Option<Sourced<Vec<SandboxModeRequirement>>>,
|
||||
pub allowed_web_search_modes: Option<Sourced<Vec<WebSearchModeRequirement>>>,
|
||||
pub allow_managed_hooks_only: Option<Sourced<bool>>,
|
||||
pub allow_plugin_sharing: Option<Sourced<bool>>,
|
||||
pub feature_requirements: Option<Sourced<FeatureRequirementsToml>>,
|
||||
pub hooks: Option<Sourced<ManagedHooksRequirementsToml>>,
|
||||
pub mcp_servers: Option<Sourced<BTreeMap<String, McpServerRequirement>>>,
|
||||
@@ -777,6 +788,7 @@ impl ConfigRequirementsWithSources {
|
||||
remote_sandbox_config: _,
|
||||
allowed_web_search_modes: _,
|
||||
allow_managed_hooks_only: _,
|
||||
allow_plugin_sharing: _,
|
||||
feature_requirements: _,
|
||||
hooks: _,
|
||||
mcp_servers: _,
|
||||
@@ -807,6 +819,7 @@ impl ConfigRequirementsWithSources {
|
||||
allowed_sandbox_modes,
|
||||
allowed_web_search_modes,
|
||||
allow_managed_hooks_only,
|
||||
allow_plugin_sharing,
|
||||
feature_requirements,
|
||||
hooks,
|
||||
mcp_servers,
|
||||
@@ -835,6 +848,7 @@ impl ConfigRequirementsWithSources {
|
||||
allowed_sandbox_modes,
|
||||
allowed_web_search_modes,
|
||||
allow_managed_hooks_only,
|
||||
allow_plugin_sharing,
|
||||
feature_requirements,
|
||||
hooks,
|
||||
mcp_servers,
|
||||
@@ -853,6 +867,7 @@ impl ConfigRequirementsWithSources {
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: allowed_web_search_modes.map(|sourced| sourced.value),
|
||||
allow_managed_hooks_only: allow_managed_hooks_only.map(|sourced| sourced.value),
|
||||
allow_plugin_sharing: allow_plugin_sharing.map(|sourced| sourced.value),
|
||||
feature_requirements: feature_requirements.map(|sourced| sourced.value),
|
||||
hooks: hooks.map(|sourced| sourced.value),
|
||||
mcp_servers: mcp_servers.map(|sourced| sourced.value),
|
||||
@@ -937,6 +952,7 @@ impl ConfigRequirementsToml {
|
||||
&& self.remote_sandbox_config.is_none()
|
||||
&& self.allowed_web_search_modes.is_none()
|
||||
&& self.allow_managed_hooks_only.is_none()
|
||||
&& self.allow_plugin_sharing.is_none()
|
||||
&& self
|
||||
.feature_requirements
|
||||
.as_ref()
|
||||
@@ -975,6 +991,7 @@ impl TryFrom<ConfigRequirementsWithSources> for ConfigRequirements {
|
||||
allowed_sandbox_modes,
|
||||
allowed_web_search_modes,
|
||||
allow_managed_hooks_only,
|
||||
allow_plugin_sharing,
|
||||
feature_requirements,
|
||||
hooks,
|
||||
mcp_servers,
|
||||
@@ -1211,6 +1228,7 @@ impl TryFrom<ConfigRequirementsWithSources> for ConfigRequirements {
|
||||
permission_profile,
|
||||
web_search_mode,
|
||||
allow_managed_hooks_only,
|
||||
allow_plugin_sharing,
|
||||
feature_requirements,
|
||||
managed_hooks,
|
||||
mcp_servers,
|
||||
@@ -1284,6 +1302,7 @@ mod tests {
|
||||
remote_sandbox_config: _,
|
||||
allowed_web_search_modes,
|
||||
allow_managed_hooks_only,
|
||||
allow_plugin_sharing,
|
||||
feature_requirements,
|
||||
hooks,
|
||||
mcp_servers,
|
||||
@@ -1306,6 +1325,8 @@ mod tests {
|
||||
.map(|value| Sourced::new(value, RequirementSource::Unknown)),
|
||||
allow_managed_hooks_only: allow_managed_hooks_only
|
||||
.map(|value| Sourced::new(value, RequirementSource::Unknown)),
|
||||
allow_plugin_sharing: allow_plugin_sharing
|
||||
.map(|value| Sourced::new(value, RequirementSource::Unknown)),
|
||||
feature_requirements: feature_requirements
|
||||
.map(|value| Sourced::new(value, RequirementSource::Unknown)),
|
||||
hooks: hooks.map(|value| Sourced::new(value, RequirementSource::Unknown)),
|
||||
@@ -1348,6 +1369,34 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_allow_plugin_sharing() -> Result<()> {
|
||||
let requirements: ConfigRequirementsToml = from_str(
|
||||
r#"
|
||||
allow_plugin_sharing = false
|
||||
"#,
|
||||
)?;
|
||||
|
||||
assert_eq!(requirements.allow_plugin_sharing, Some(false));
|
||||
assert!(!requirements.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allow_plugin_sharing_defaults_to_allowed() -> Result<()> {
|
||||
let requirements: ConfigRequirements =
|
||||
with_unknown_source(ConfigRequirementsToml::default()).try_into()?;
|
||||
assert!(requirements.allow_plugin_sharing());
|
||||
|
||||
let requirements: ConfigRequirements = with_unknown_source(ConfigRequirementsToml {
|
||||
allow_plugin_sharing: Some(false),
|
||||
..Default::default()
|
||||
})
|
||||
.try_into()?;
|
||||
assert!(!requirements.allow_plugin_sharing());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_unset_fields_copies_every_field_and_sets_sources() {
|
||||
let mut target = ConfigRequirementsWithSources::default();
|
||||
@@ -1380,6 +1429,7 @@ mod tests {
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: Some(allowed_web_search_modes.clone()),
|
||||
allow_managed_hooks_only: Some(true),
|
||||
allow_plugin_sharing: Some(false),
|
||||
feature_requirements: Some(feature_requirements.clone()),
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -1414,6 +1464,10 @@ mod tests {
|
||||
/*value*/ true,
|
||||
enforce_source.clone(),
|
||||
)),
|
||||
allow_plugin_sharing: Some(Sourced::new(
|
||||
/*value*/ false,
|
||||
enforce_source.clone(),
|
||||
)),
|
||||
feature_requirements: Some(Sourced::new(
|
||||
feature_requirements,
|
||||
enforce_source.clone(),
|
||||
@@ -1457,6 +1511,7 @@ mod tests {
|
||||
allowed_sandbox_modes: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -1505,6 +1560,7 @@ mod tests {
|
||||
allowed_sandbox_modes: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
|
||||
@@ -496,9 +496,6 @@
|
||||
"plugin_hooks": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"plugin_sharing": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"plugins": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -4176,9 +4173,6 @@
|
||||
"plugin_hooks": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"plugin_sharing": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"plugins": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -848,6 +848,7 @@ allowed_approval_policies = ["on-request"]
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -906,6 +907,7 @@ allowed_approval_policies = ["on-request"]
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -1115,6 +1117,7 @@ async fn load_config_layers_includes_cloud_requirements() -> anyhow::Result<()>
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
|
||||
@@ -8168,6 +8168,7 @@ async fn test_requirements_web_search_mode_allowlist_does_not_warn_when_unset()
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: Some(vec![codex_config::WebSearchModeRequirement::Cached]),
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
@@ -8881,6 +8882,7 @@ async fn explicit_sandbox_mode_falls_back_when_disallowed_by_requirements() -> s
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: None,
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
mcp_servers: None,
|
||||
|
||||
@@ -2126,6 +2126,7 @@ impl Config {
|
||||
permission_profile: mut constrained_permission_profile,
|
||||
web_search_mode: mut constrained_web_search_mode,
|
||||
allow_managed_hooks_only: _,
|
||||
allow_plugin_sharing: _,
|
||||
feature_requirements,
|
||||
managed_hooks: _,
|
||||
mcp_servers,
|
||||
|
||||
@@ -188,8 +188,6 @@ pub enum Feature {
|
||||
ComputerUse,
|
||||
/// Temporary internal-only flag for PS-backed remote plugin catalog development.
|
||||
RemotePlugin,
|
||||
/// Enable remote plugin sharing flows.
|
||||
PluginSharing,
|
||||
/// Show the startup prompt for migrating external agent config into Codex.
|
||||
ExternalMigration,
|
||||
/// Allow the model to invoke the built-in image generation tool.
|
||||
@@ -1009,12 +1007,6 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::PluginSharing,
|
||||
key: "plugin_sharing",
|
||||
stage: Stage::Stable,
|
||||
default_enabled: true,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::ExternalMigration,
|
||||
key: "external_migration",
|
||||
|
||||
@@ -122,6 +122,7 @@ fn requirements_with_managed_hooks_only(
|
||||
allow_managed_hooks_only,
|
||||
RequirementSource::CloudRequirements,
|
||||
)),
|
||||
allow_plugin_sharing: None,
|
||||
managed_hooks: managed_hooks.clone().map(|hooks| {
|
||||
ConstrainedWithSource::new(
|
||||
Constrained::allow_any(hooks),
|
||||
@@ -132,6 +133,7 @@ fn requirements_with_managed_hooks_only(
|
||||
},
|
||||
ConfigRequirementsToml {
|
||||
allow_managed_hooks_only: Some(allow_managed_hooks_only),
|
||||
allow_plugin_sharing: None,
|
||||
hooks: managed_hooks,
|
||||
..ConfigRequirementsToml::default()
|
||||
},
|
||||
|
||||
@@ -156,6 +156,17 @@ fn render_debug_config_lines(stack: &ConfigLayerStack) -> Vec<Line<'static>> {
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(allow_plugin_sharing) = requirements_toml.allow_plugin_sharing {
|
||||
requirement_lines.push(requirement_line(
|
||||
"allow_plugin_sharing",
|
||||
allow_plugin_sharing.to_string(),
|
||||
requirements
|
||||
.allow_plugin_sharing
|
||||
.as_ref()
|
||||
.map(|sourced| &sourced.source),
|
||||
));
|
||||
}
|
||||
|
||||
if requirements_toml.guardian_policy_config.is_some() {
|
||||
requirement_lines.push(requirement_line(
|
||||
"guardian_policy_config",
|
||||
@@ -662,6 +673,10 @@ mod tests {
|
||||
/*value*/ true,
|
||||
RequirementSource::CloudRequirements,
|
||||
)),
|
||||
allow_plugin_sharing: Some(Sourced::new(
|
||||
/*value*/ false,
|
||||
RequirementSource::CloudRequirements,
|
||||
)),
|
||||
feature_requirements: Some(Sourced::new(
|
||||
FeatureRequirementsToml {
|
||||
entries: BTreeMap::from([("guardian_approval".to_string(), true)]),
|
||||
@@ -700,6 +715,7 @@ mod tests {
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: Some(vec![WebSearchModeRequirement::Cached]),
|
||||
allow_managed_hooks_only: Some(true),
|
||||
allow_plugin_sharing: Some(false),
|
||||
guardian_policy_config: Some("Use the managed guardian policy.".to_string()),
|
||||
feature_requirements: Some(FeatureRequirementsToml {
|
||||
entries: BTreeMap::from([("guardian_approval".to_string(), true)]),
|
||||
@@ -758,6 +774,7 @@ mod tests {
|
||||
)
|
||||
);
|
||||
assert!(rendered.contains("allow_managed_hooks_only: true (source: cloud requirements)"));
|
||||
assert!(rendered.contains("allow_plugin_sharing: false (source: cloud requirements)"));
|
||||
assert!(
|
||||
rendered.contains("guardian_policy_config: configured (source: cloud requirements)")
|
||||
);
|
||||
@@ -911,6 +928,7 @@ approval_policy = "never"
|
||||
remote_sandbox_config: None,
|
||||
allowed_web_search_modes: Some(Vec::new()),
|
||||
allow_managed_hooks_only: None,
|
||||
allow_plugin_sharing: None,
|
||||
guardian_policy_config: None,
|
||||
feature_requirements: None,
|
||||
hooks: None,
|
||||
|
||||
Reference in New Issue
Block a user