mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Ignore local curated plugins when remote catalog is active (#29765)
## Summary - suppress configured `openai-curated` plugins when the remote plugin feature is enabled and auth uses the Codex backend - preserve `openai-api-curated` and non-Codex-backend behavior while including remote catalog activation in the plugin load cache key - add core plugin coverage and an app-server integration test for runtime feature enablement ## Why The Codex app enables remote plugins through process-local runtime feature enablement, which can happen after app-server startup tasks have already observed legacy local plugin state. The existing conflict logic only preferred a remote plugin when the same plugin was already installed remotely, so a configured legacy-only plugin could continue exposing skills and other capabilities from `openai-curated`. ## Impact When the remote catalog is active, legacy `openai-curated` plugins no longer contribute skills, MCP servers, apps, or hooks. Remote installed plugins continue to load normally, and `openai-api-curated` remains unaffected. This does not change remote fetch, bundle sync, or uninstall behavior. ## Validation - `just test -p codex-core-plugins remote_global_catalog_ignores_local_curated_plugins remote_plugin_feature_keeps_local_curated_without_codex_backend` - `just test -p codex-app-server runtime_remote_plugin_enablement_excludes_local_curated_plugin_skills` - `just fmt` - `git diff --check`
This commit is contained in:
@@ -118,14 +118,14 @@ pub(crate) async fn load_plugins_from_layer_stack(
|
||||
store: &PluginStore,
|
||||
plugin_skill_snapshots: Option<&PluginSkillSnapshots>,
|
||||
restriction_product: Option<Product>,
|
||||
prefer_remote_curated_conflicts: bool,
|
||||
remote_global_catalog_active: bool,
|
||||
) -> Vec<LoadedPlugin<McpServerConfig>> {
|
||||
let skill_config_rules = skill_config_rules_from_stack(config_layer_stack);
|
||||
load_plugins_from_layer_stack_with_scope(
|
||||
config_layer_stack,
|
||||
extra_plugins,
|
||||
store,
|
||||
prefer_remote_curated_conflicts,
|
||||
remote_global_catalog_active,
|
||||
PluginLoadScope::AllCapabilities {
|
||||
restriction_product,
|
||||
skill_config_rules: &skill_config_rules,
|
||||
@@ -139,14 +139,14 @@ async fn load_plugins_from_layer_stack_with_scope(
|
||||
config_layer_stack: &ConfigLayerStack,
|
||||
extra_plugins: HashMap<String, PluginConfig>,
|
||||
store: &PluginStore,
|
||||
prefer_remote_curated_conflicts: bool,
|
||||
remote_global_catalog_active: bool,
|
||||
scope: PluginLoadScope<'_>,
|
||||
) -> Vec<LoadedPlugin<McpServerConfig>> {
|
||||
let configured_plugins = merge_configured_plugins_with_remote_installed(
|
||||
configured_plugins_from_stack(config_layer_stack),
|
||||
extra_plugins,
|
||||
store,
|
||||
prefer_remote_curated_conflicts,
|
||||
remote_global_catalog_active,
|
||||
);
|
||||
let mut configured_plugins: Vec<_> = configured_plugins.into_iter().collect();
|
||||
configured_plugins.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
|
||||
@@ -178,13 +178,13 @@ pub async fn load_plugin_hooks_from_layer_stack(
|
||||
config_layer_stack: &ConfigLayerStack,
|
||||
extra_plugins: HashMap<String, PluginConfig>,
|
||||
store: &PluginStore,
|
||||
prefer_remote_curated_conflicts: bool,
|
||||
remote_global_catalog_active: bool,
|
||||
) -> PluginHookLoadOutcome {
|
||||
let plugins = load_plugins_from_layer_stack_with_scope(
|
||||
config_layer_stack,
|
||||
extra_plugins,
|
||||
store,
|
||||
prefer_remote_curated_conflicts,
|
||||
remote_global_catalog_active,
|
||||
PluginLoadScope::HooksOnly,
|
||||
)
|
||||
.await;
|
||||
@@ -206,8 +206,17 @@ fn merge_configured_plugins_with_remote_installed(
|
||||
mut configured_plugins: HashMap<String, PluginConfig>,
|
||||
extra_plugins: HashMap<String, PluginConfig>,
|
||||
store: &PluginStore,
|
||||
prefer_remote_curated_conflicts: bool,
|
||||
remote_global_catalog_active: bool,
|
||||
) -> HashMap<String, PluginConfig> {
|
||||
if remote_global_catalog_active {
|
||||
configured_plugins.retain(|plugin_key, _| match PluginId::parse(plugin_key) {
|
||||
Ok(plugin_id) => plugin_id.marketplace_name != crate::OPENAI_CURATED_MARKETPLACE_NAME,
|
||||
Err(_) => true,
|
||||
});
|
||||
configured_plugins.extend(extra_plugins);
|
||||
return configured_plugins;
|
||||
}
|
||||
|
||||
let mut local_curated_installed_plugin_keys = HashMap::<String, Vec<String>>::new();
|
||||
for plugin_key in configured_plugins.keys() {
|
||||
let Ok(plugin_id) = PluginId::parse(plugin_key) else {
|
||||
@@ -234,14 +243,8 @@ fn merge_configured_plugins_with_remote_installed(
|
||||
.as_ref()
|
||||
.and_then(|plugin_name| local_curated_installed_plugin_keys.get(plugin_name));
|
||||
|
||||
if let Some(local_curated_plugin_keys) = local_curated_plugin_keys {
|
||||
if prefer_remote_curated_conflicts {
|
||||
for local_curated_plugin_key in local_curated_plugin_keys {
|
||||
configured_plugins.remove(local_curated_plugin_key);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if local_curated_plugin_keys.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
configured_plugins.insert(plugin_key, plugin_config);
|
||||
|
||||
Reference in New Issue
Block a user