Route curated plugin catalogs by authentication mode (#38429)

## Why

The model provider does not reliably identify which curated plugin catalog is
available. ChatGPT authentication can be used with a custom provider, while an
unauthenticated session should use the API-compatible catalog regardless of its
provider.

## What changed

- Select the ChatGPT curated catalog only for authentication modes that use the
  Codex backend; use the API curated catalog for API-key and unauthenticated
  sessions.
- Initialize standalone plugin managers with the current authentication mode
  across CLI, app-server, MCP, and external-agent migration paths.
- Preserve authentication mode while detecting and importing migrated plugins.

## Testing

- Cover catalog and skill routing across ChatGPT, API-key, unauthenticated,
  Bedrock, and custom-provider configurations.
- Verify authenticated plugin migration uses the ChatGPT curated marketplace.

GitOrigin-RevId: 660a339ee8891c33aad961078d3a979242a6a166
This commit is contained in:
willwang-openai
2026-08-13 20:20:01 +00:00
committed by copyberry
parent 507ef0b371
commit f898ebcafd
28 changed files with 348 additions and 139 deletions
@@ -2,7 +2,7 @@ use super::*;
use crate::plugins::plugins_manager_for_config;
use crate::plugins::test_support::load_plugins_config;
use crate::plugins::test_support::write_curated_plugin_sha;
use crate::plugins::test_support::write_openai_curated_marketplace;
use crate::plugins::test_support::write_openai_api_curated_marketplace;
use crate::plugins::test_support::write_plugins_feature_config;
use codex_config::CONFIG_TOML_FILE;
use codex_config::config_toml::ConfigToml;
@@ -35,15 +35,15 @@ fn request_plugin_install_does_not_support_parallel_tool_calls() {
async fn verified_plugin_install_completed_requires_installed_plugin() {
let codex_home = tempdir().expect("tempdir should succeed");
let curated_root = curated_plugins_repo_path(codex_home.path());
write_openai_curated_marketplace(&curated_root, &["sample"]);
write_openai_api_curated_marketplace(&curated_root, &["sample"]);
write_curated_plugin_sha(codex_home.path());
write_plugins_feature_config(codex_home.path());
let config = load_plugins_config(codex_home.path()).await;
let plugins_manager = plugins_manager_for_config(&config);
let plugins_manager = plugins_manager_for_config(&config, /*auth_mode*/ None);
assert!(!verified_plugin_install_completed(
"sample@openai-curated",
"sample@openai-api-curated",
&config,
&plugins_manager,
));
@@ -54,7 +54,7 @@ async fn verified_plugin_install_completed_requires_installed_plugin() {
PluginInstallRequest {
plugin_name: "sample".to_string(),
marketplace_path: AbsolutePathBuf::try_from(
curated_root.join(".agents/plugins/marketplace.json"),
curated_root.join(".agents/plugins/api_marketplace.json"),
)
.expect("marketplace path"),
},
@@ -64,7 +64,7 @@ async fn verified_plugin_install_completed_requires_installed_plugin() {
let refreshed_config = load_plugins_config(codex_home.path()).await;
assert!(verified_plugin_install_completed(
"sample@openai-curated",
"sample@openai-api-curated",
&refreshed_config,
&plugins_manager,
));