mirror of
https://github.com/openai/codex.git
synced 2026-11-07 08:34:29 +00:00
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:
1 parent
507ef0b371
commit
f898ebcafd
28 files changed
+348
-139
No files matched your search
@@ -162,17 +162,17 @@ async fn plugin_list_skips_invalid_marketplace_file_and_reports_error() -> Resul
|
||||
async fn plugin_installed_includes_installed_plugins_and_explicit_install_suggestions() -> Result<()>
|
||||
{
|
||||
let codex_home = TempDir::new()?;
|
||||
write_openai_curated_marketplace(
|
||||
write_openai_api_curated_marketplace(
|
||||
codex_home.path(),
|
||||
&["linear", "computer-use", "not-mentioned"],
|
||||
)?;
|
||||
write_installed_plugin(&codex_home, "openai-curated", "linear")?;
|
||||
write_installed_plugin(&codex_home, "openai-api-curated", "linear")?;
|
||||
std::fs::write(
|
||||
codex_home.path().join("config.toml"),
|
||||
r#"[features]
|
||||
plugins = true
|
||||
|
||||
[plugins."linear@openai-curated"]
|
||||
[plugins."linear@openai-api-curated"]
|
||||
enabled = true
|
||||
"#,
|
||||
)?;
|
||||
@@ -193,7 +193,7 @@ enabled = true
|
||||
timeout(DEFAULT_TIMEOUT, mcp.read_response(request_id)).await??;
|
||||
|
||||
assert_eq!(response.marketplaces.len(), 1);
|
||||
assert_eq!(response.marketplaces[0].name, "openai-curated");
|
||||
assert_eq!(response.marketplaces[0].name, "openai-api-curated");
|
||||
assert_eq!(
|
||||
response.marketplaces[0]
|
||||
.plugins
|
||||
@@ -201,8 +201,8 @@ enabled = true
|
||||
.map(|plugin| (plugin.id.clone(), plugin.installed, plugin.enabled))
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
("linear@openai-curated".to_string(), true, true),
|
||||
("computer-use@openai-curated".to_string(), false, false),
|
||||
("linear@openai-api-curated".to_string(), true, true),
|
||||
("computer-use@openai-api-curated".to_string(), false, false),
|
||||
]
|
||||
);
|
||||
assert_eq!(response.marketplace_load_errors, Vec::new());
|
||||
@@ -4548,16 +4548,19 @@ remote_plugin = true
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn plugin_list_fetches_featured_plugin_ids_without_chatgpt_auth() -> Result<()> {
|
||||
async fn plugin_list_omits_featured_plugin_ids_without_chatgpt_auth() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
let server = MockServer::start().await;
|
||||
write_plugin_sync_config(codex_home.path(), &format!("{}/backend-api/", server.uri()))?;
|
||||
write_openai_curated_marketplace(codex_home.path(), &["linear", "gmail"])?;
|
||||
write_openai_api_curated_marketplace(codex_home.path(), &["linear", "gmail"])?;
|
||||
|
||||
Mock::given(method("GET"))
|
||||
.and(path("/backend-api/plugins/featured"))
|
||||
.and(query_param("platform", "codex"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_string(r#"["linear@openai-curated"]"#))
|
||||
.respond_with(
|
||||
ResponseTemplate::new(200).set_body_string(r#"["linear@openai-api-curated"]"#),
|
||||
)
|
||||
.expect(0)
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
@@ -4577,10 +4580,8 @@ async fn plugin_list_fetches_featured_plugin_ids_without_chatgpt_auth() -> Resul
|
||||
let response: PluginListResponse =
|
||||
timeout(DEFAULT_TIMEOUT, mcp.read_response(request_id)).await??;
|
||||
|
||||
assert_eq!(
|
||||
response.featured_plugin_ids,
|
||||
vec!["linear@openai-curated".to_string()]
|
||||
);
|
||||
assert_eq!(response.featured_plugin_ids, Vec::<String>::new());
|
||||
assert_eq!(response.marketplaces[0].name, "openai-api-curated");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4590,6 +4591,7 @@ async fn plugin_list_uses_warmed_featured_plugin_ids_cache_on_first_request() ->
|
||||
let server = MockServer::start().await;
|
||||
write_plugin_sync_config(codex_home.path(), &format!("{}/backend-api/", server.uri()))?;
|
||||
write_openai_curated_marketplace(codex_home.path(), &["linear", "gmail"])?;
|
||||
write_remote_plugin_test_auth(codex_home.path())?;
|
||||
|
||||
Mock::given(method("GET"))
|
||||
.and(path("/backend-api/plugins/featured"))
|
||||
@@ -5290,6 +5292,7 @@ chatgpt_base_url = "{base_url}"
|
||||
|
||||
[features]
|
||||
plugins = true
|
||||
remote_plugin = false
|
||||
|
||||
[plugins."linear@openai-curated"]
|
||||
enabled = false
|
||||
|
||||
@@ -142,8 +142,13 @@ fn write_cached_remote_plugin_with_skill(
|
||||
Ok(skill_path)
|
||||
}
|
||||
|
||||
fn write_cached_local_curated_plugin_with_skill(codex_home: &std::path::Path) -> Result<()> {
|
||||
let plugin_root = codex_home.join("plugins/cache/openai-curated/google-calendar/local");
|
||||
fn write_cached_local_curated_plugin_with_skill(
|
||||
codex_home: &std::path::Path,
|
||||
marketplace_name: &str,
|
||||
) -> Result<()> {
|
||||
let plugin_root = codex_home.join(format!(
|
||||
"plugins/cache/{marketplace_name}/google-calendar/local"
|
||||
));
|
||||
std::fs::create_dir_all(plugin_root.join(".codex-plugin"))?;
|
||||
std::fs::write(
|
||||
plugin_root.join(".codex-plugin/plugin.json"),
|
||||
@@ -397,7 +402,7 @@ async fn runtime_remote_plugin_toggle_updates_local_curated_plugin_skills() -> R
|
||||
let codex_home = TempDir::new()?;
|
||||
let cwd = TempDir::new()?;
|
||||
let server = MockServer::start().await;
|
||||
write_cached_local_curated_plugin_with_skill(codex_home.path())?;
|
||||
write_cached_local_curated_plugin_with_skill(codex_home.path(), "openai-curated")?;
|
||||
std::fs::write(
|
||||
codex_home.path().join("config.toml"),
|
||||
format!(
|
||||
@@ -842,13 +847,13 @@ async fn skills_list_preserves_requested_cwd_order() -> Result<()> {
|
||||
let first_cwd = TempDir::new()?;
|
||||
let second_cwd = TempDir::new()?;
|
||||
write_skill(&codex_home, "shared-skill")?;
|
||||
write_cached_local_curated_plugin_with_skill(codex_home.path())?;
|
||||
write_cached_local_curated_plugin_with_skill(codex_home.path(), "openai-api-curated")?;
|
||||
std::fs::write(
|
||||
codex_home.path().join("config.toml"),
|
||||
r#"[features]
|
||||
plugins = true
|
||||
|
||||
[plugins."google-calendar@openai-curated"]
|
||||
[plugins."google-calendar@openai-api-curated"]
|
||||
enabled = true
|
||||
"#,
|
||||
)?;
|
||||
@@ -858,7 +863,9 @@ enabled = true
|
||||
std::fs::create_dir_all(cwd.join(".codex"))?;
|
||||
std::fs::write(
|
||||
cwd.join(".codex/config.toml"),
|
||||
format!("[plugins.\"google-calendar@openai-curated\"]\nenabled = {plugin_enabled}\n"),
|
||||
format!(
|
||||
"[plugins.\"google-calendar@openai-api-curated\"]\nenabled = {plugin_enabled}\n"
|
||||
),
|
||||
)?;
|
||||
set_project_trust_level(codex_home.path(), cwd, TrustLevel::Trusted)?;
|
||||
}
|
||||
@@ -955,13 +962,13 @@ async fn skills_list_force_reload_refreshes_cached_plugin_roots() -> Result<()>
|
||||
let codex_home = TempDir::new()?;
|
||||
let first_cwd = TempDir::new()?;
|
||||
let second_cwd = TempDir::new()?;
|
||||
write_cached_local_curated_plugin_with_skill(codex_home.path())?;
|
||||
write_cached_local_curated_plugin_with_skill(codex_home.path(), "openai-api-curated")?;
|
||||
std::fs::write(
|
||||
codex_home.path().join("config.toml"),
|
||||
r#"[features]
|
||||
plugins = true
|
||||
|
||||
[plugins."google-calendar@openai-curated"]
|
||||
[plugins."google-calendar@openai-api-curated"]
|
||||
enabled = true
|
||||
"#,
|
||||
)?;
|
||||
@@ -991,7 +998,7 @@ enabled = true
|
||||
if force_reload {
|
||||
let plugin_root = codex_home
|
||||
.path()
|
||||
.join("plugins/cache/openai-curated/google-calendar/local");
|
||||
.join("plugins/cache/openai-api-curated/google-calendar/local");
|
||||
std::fs::write(
|
||||
plugin_root.join(".codex-plugin/plugin.json"),
|
||||
r#"{"name":"google-calendar","skills":"./replacement-skills"}"#,
|
||||
|
||||
@@ -4414,7 +4414,7 @@ async fn command_execution_notifications_include_trusted_plugin_id() -> Result<(
|
||||
let curated_sha = "0123456789abcdef0123456789abcdef01234567";
|
||||
let plugin_root = codex_home
|
||||
.path()
|
||||
.join("plugins/cache/openai-curated/google-calendar/01234567");
|
||||
.join("plugins/cache/openai-api-curated/google-calendar/01234567");
|
||||
let script_path = plugin_root.join("scripts/run.sh");
|
||||
let synced_root = codex_home.path().join(".tmp/plugins");
|
||||
for path in [
|
||||
@@ -4437,9 +4437,9 @@ async fn command_execution_notifications_include_trusted_plugin_id() -> Result<(
|
||||
format!("{curated_sha}\n"),
|
||||
)?;
|
||||
std::fs::write(
|
||||
synced_root.join(".agents/plugins/marketplace.json"),
|
||||
synced_root.join(".agents/plugins/api_marketplace.json"),
|
||||
r#"{
|
||||
"name": "openai-curated",
|
||||
"name": "openai-api-curated",
|
||||
"plugins": [{
|
||||
"name": "google-calendar",
|
||||
"source": {"source": "local", "path": "./plugins/google-calendar"}
|
||||
@@ -4464,7 +4464,7 @@ async fn command_execution_notifications_include_trusted_plugin_id() -> Result<(
|
||||
.with_sandbox_mode("danger-full-access")
|
||||
.enable_feature(Feature::Plugins)
|
||||
.disable_feature(Feature::RemotePlugin)
|
||||
.with_extra_config("[plugins.\"google-calendar@openai-curated\"]\nenabled = true")
|
||||
.with_extra_config("[plugins.\"google-calendar@openai-api-curated\"]\nenabled = true")
|
||||
.write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
@@ -4506,7 +4506,7 @@ async fn command_execution_notifications_include_trusted_plugin_id() -> Result<(
|
||||
.expect("command execution item should include scriptPath");
|
||||
assert_eq!(
|
||||
(item_json["pluginId"].as_str(), emitted_script_path),
|
||||
(Some("google-calendar@openai-curated"), "scripts/run.sh")
|
||||
(Some("google-calendar@openai-api-curated"), "scripts/run.sh")
|
||||
);
|
||||
assert!(
|
||||
!emitted_script_path.contains(script_path.to_string_lossy().as_ref()),
|
||||
|
||||
Reference in new issue
Block a user