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:
committed by
GitHub
Unverified
parent
2696e7199b
commit
ff78e21215
@@ -1061,7 +1061,7 @@ enabled = true
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_installed_cache_prefers_remote_curated_conflicts_when_remote_plugin_enabled() {
|
||||
async fn remote_global_catalog_ignores_local_curated_plugins() {
|
||||
let codex_home = TempDir::new().unwrap();
|
||||
write_file(
|
||||
&codex_home.path().join(CONFIG_TOML_FILE),
|
||||
@@ -1086,7 +1086,11 @@ enabled = true
|
||||
write_cached_plugin(codex_home.path(), "openai-curated-remote", "remote-only");
|
||||
|
||||
let config = load_config(codex_home.path(), codex_home.path()).await;
|
||||
let manager = PluginsManager::new(codex_home.path().to_path_buf());
|
||||
let manager = PluginsManager::new_with_options(
|
||||
codex_home.path().to_path_buf(),
|
||||
Some(Product::Codex),
|
||||
Some(AuthMode::Chatgpt),
|
||||
);
|
||||
manager.write_remote_installed_plugins_cache(vec![
|
||||
remote_installed_plugin("linear"),
|
||||
remote_installed_plugin("remote-only"),
|
||||
@@ -1100,13 +1104,54 @@ enabled = true
|
||||
.map(|plugin| plugin.config_name.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
"calendar@openai-curated".to_string(),
|
||||
"linear@openai-api-curated".to_string(),
|
||||
"linear@openai-curated-remote".to_string(),
|
||||
"remote-only@openai-curated-remote".to_string(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_plugin_feature_keeps_local_curated_without_codex_backend() {
|
||||
let codex_home = TempDir::new().unwrap();
|
||||
write_file(
|
||||
&codex_home.path().join(CONFIG_TOML_FILE),
|
||||
r#"[features]
|
||||
plugins = true
|
||||
remote_plugin = true
|
||||
|
||||
[plugins."linear@openai-curated"]
|
||||
enabled = true
|
||||
|
||||
[plugins."linear@openai-api-curated"]
|
||||
enabled = true
|
||||
"#,
|
||||
);
|
||||
write_cached_plugin(codex_home.path(), "openai-curated", "linear");
|
||||
write_cached_plugin(codex_home.path(), "openai-api-curated", "linear");
|
||||
|
||||
let config = load_config(codex_home.path(), codex_home.path()).await;
|
||||
let manager = PluginsManager::new_with_options(
|
||||
codex_home.path().to_path_buf(),
|
||||
Some(Product::Codex),
|
||||
Some(AuthMode::ApiKey),
|
||||
);
|
||||
|
||||
let outcome = manager.plugins_for_config(&config).await;
|
||||
|
||||
assert_eq!(
|
||||
outcome
|
||||
.plugins()
|
||||
.iter()
|
||||
.map(|plugin| plugin.config_name.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
"linear@openai-api-curated".to_string(),
|
||||
"linear@openai-curated".to_string(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn build_remote_installed_plugin_marketplaces_from_cache_uses_remote_metadata() {
|
||||
let codex_home = TempDir::new().unwrap();
|
||||
@@ -2273,7 +2318,7 @@ fn loaded_plugins_cache_invalidation_rejects_stale_load_completion() {
|
||||
let cache_key = PluginLoadCacheKey {
|
||||
configured_plugins: HashMap::new(),
|
||||
skill_config_rules: SkillConfigRules::default(),
|
||||
remote_plugin_enabled: false,
|
||||
remote_global_catalog_active: false,
|
||||
};
|
||||
let stale_generation = manager.loaded_plugins_cache_generation();
|
||||
|
||||
@@ -5398,7 +5443,7 @@ async fn load_plugins_ignores_project_config_files() {
|
||||
&PluginStore::new(codex_home.path().to_path_buf()),
|
||||
/*plugin_skill_snapshots*/ None,
|
||||
Some(Product::Codex),
|
||||
/*prefer_remote_curated_conflicts*/ false,
|
||||
/*remote_global_catalog_active*/ false,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user