Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions artifacts/github/bundles/openai-codex-pr-27461.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
"analysis_mode": "pr_first",
"commits": [
{
"author": "felixxia-oai",
"committed_at": "2026-06-11T10:27:17Z",
"message": "Skip plugin MCP OAuth when app route is available",
"sha": "9d5edd7c670d178062a8bee9f194ba41fc4072be",
"url": "https://github.com/openai/codex/commit/9d5edd7c670d178062a8bee9f194ba41fc4072be"
},
{
"author": "felixxia-oai",
"committed_at": "2026-06-15T11:23:58Z",
"message": "Update constructor name",
"sha": "3c9aaf348048ec81f41bdb1d7dcfa8c45aabbe49",
"url": "https://github.com/openai/codex/commit/3c9aaf348048ec81f41bdb1d7dcfa8c45aabbe49"
}
],
"default_branch": "main",
"docs_refs": [],
"examples_refs": [],
"extracted_flags": [
"PR5",
"MCP",
"PR1",
"PR2",
"PR3",
"PR4",
"API",
"--all",
"--check",
"--cached",
"DEFAULT_TIMEOUT",
"JSONRPCR",
"OPENAI_API_KEY",
"REMOTE_PLUGIN_ID",
"TEST_ALLOW_HTTP_REMOTE_PLUGIN_BUNDLE_DOWNLOADS",
"REMOTE_GLOBAL_MARKETPLACE_NAME",
"CONFIG_TOML_FILE"
],
"files": [
{
"additions": 10,
"deletions": 3,
"patch_excerpt": "@@ -1436,7 +1436,11 @@ impl PluginRequestProcessor {\n \n self.on_effective_plugins_changed();\n \n- let plugin_mcp_servers = load_plugin_mcp_servers(result.installed_path.as_path()).await;\n+ let plugin_mcp_servers = load_plugin_mcp_servers(\n+ result.installed_path.as_path(),\n+ auth.as_ref().map(CodexAuth::auth_mode),\n+ )\n+ .await;\n if !plugin_mcp_servers.is_empty() {\n self.start_plugin_mcp_oauth_logins(&config, plugin_mcp_servers)\n .await;\n@@ -1445,7 +1449,6 @@ impl PluginRequestProcessor {\n let plugin_app_declarations = load_plugin_apps(result.installed_path.as_path()).await;\n let plugin_apps =\n codex_plugin::app_connector_ids_from_declarations(&plugin_app_declarations);\n- let auth = self.auth_manager.auth().await;\n let apps_needing_auth = self\n ...",
"path": "codex-rs/app-server/src/request_processors/plugins.rs",
"status": "modified"
},
{
"additions": 378,
"deletions": 0,
"patch_excerpt": "@@ -1027,6 +1027,293 @@ async fn plugin_install_returns_apps_needing_auth() -> Result<()> {\n Ok(())\n }\n \n+#[tokio::test]\n+async fn plugin_install_skips_mcp_oauth_for_chatgpt_dual_surface_plugin() -> Result<()> {\n+ let connectors = vec![AppInfo {\n+ id: \"sample-mcp\".to_string(),\n+ name: \"Sample MCP\".to_string(),\n+ description: Some(\"Sample MCP connector\".to_string()),\n+ logo_url: Some(\"https://example.com/alpha.png\".to_string()),\n+ logo_url_dark: None,\n+ distribution_channel: Some(\"featured\".to_string()),\n+ branding: None,\n+ app_metadata: None,\n+ labels: None,\n+ install_url: None,\n+ is_accessible: false,\n+ is_enabled: true,\n+ plugin_display_names: Vec::new(),\n+ }];\n+ let (apps_server_url, apps_server_handle, _apps_server_control) =\n+ start_apps_server(connectors, Vec::new()).await...",
"path": "codex-rs/app-server/tests/suite/v2/plugin_install.rs",
"status": "modified"
},
{
"additions": 24,
"deletions": 1,
"patch_excerpt": "@@ -10,6 +10,7 @@ use crate::remote::REMOTE_GLOBAL_MARKETPLACE_NAME;\n use crate::remote::RemoteInstalledPlugin;\n use crate::store::PluginStore;\n use crate::store::plugin_version_for_source;\n+use codex_app_server_protocol::AuthMode;\n use codex_config::ConfigLayerStack;\n use codex_config::HooksFile;\n use codex_config::types::McpServerConfig;\n@@ -1079,7 +1080,29 @@ pub async fn plugin_telemetry_metadata_from_root(\n }\n }\n \n-pub async fn load_plugin_mcp_servers(plugin_root: &Path) -> HashMap<String, McpServerConfig> {\n+pub async fn load_plugin_mcp_servers(\n+ plugin_root: &Path,\n+ auth_mode: Option<AuthMode>,\n+) -> HashMap<String, McpServerConfig> {\n+ let mut mcp_servers = load_declared_plugin_mcp_servers(plugin_root).await;\n+ if !auth_mode.is_some_and(AuthMode::uses_codex_backend) || mcp_servers.is_empty() {\n+ return mcp_servers;\n+ }\n+\n+ let app_declarations = loa...",
"path": "codex-rs/core-plugins/src/loader.rs",
"status": "modified"
},
{
"additions": 1,
"deletions": 1,
"patch_excerpt": "@@ -1330,7 +1330,7 @@ impl PluginsManager {\n app_category_by_id.insert(app.connector_id.0.clone(), category.clone());\n }\n }\n- let mut mcp_server_names = load_plugin_mcp_servers(source_path.as_path())\n+ let mut mcp_server_names = load_plugin_mcp_servers(source_path.as_path(), self.auth_mode())\n .await\n .into_keys()\n .collect::<Vec<_>>();",
"path": "codex-rs/core-plugins/src/manager.rs",
"status": "modified"
},
{
"additions": 76,
"deletions": 0,
"patch_excerpt": "@@ -2425,6 +2425,82 @@ enabled = true\n assert!(matches!(err, MarketplaceError::PluginsDisabled));\n }\n \n+#[tokio::test]\n+async fn read_plugin_for_config_filters_mcp_servers_for_codex_backend_auth() {\n+ let tmp = tempfile::tempdir().unwrap();\n+ let repo_root = tmp.path().join(\"repo\");\n+ fs::create_dir_all(repo_root.join(\".git\")).unwrap();\n+ fs::create_dir_all(repo_root.join(\".agents/plugins\")).unwrap();\n+ write_file(\n+ &repo_root.join(\".agents/plugins/marketplace.json\"),\n+ r#\"{\n+ \"name\": \"debug\",\n+ \"plugins\": [\n+ {\n+ \"name\": \"sample-plugin\",\n+ \"source\": {\n+ \"source\": \"local\",\n+ \"path\": \"./sample-plugin\"\n+ }\n+ }\n+ ]\n+}\"#,\n+ );\n+ write_file(\n+ &repo_root.join(\"sample-plugin/.codex-plugin/plugin.json\"),\n+ r#\"{\"name\":\"sample-plugin\"}\"#,\n+ );\n+ write_file(\n+ &repo_root.join(\"sample-plugin/.ap...",
"path": "codex-rs/core-plugins/src/manager_tests.rs",
"status": "modified"
}
],
"linked_issues": [
"#27652",
"#27459",
"#27607",
"#27602",
"#27461"
],
"notes": [
"Built from GitHub pull-request, commits, files, and repo endpoints."
],
"primary_pr": {
"body": "## Context\r\n\r\nThis is PR5 in the plugin auth-routing stack. Earlier PRs make plugin surface projection auth-aware, narrow App/MCP conflicts by App declaration name, and keep connector listings auth-aware. This PR applies the same name-based App/MCP conflict rule into plugin MCP loading, so install-time MCP OAuth and plugin detail metadata both reflect the MCPs available for the current auth route.\r\n\r\n## Stack\r\n\r\n- PR1: #27652 seed plugin manager auth at construction.\r\n- PR2: #27459 route plugin surfaces by auth mode.\r\n- PR3: #27607 dedupe plugin MCP servers by App declaration name.\r\n- PR4: #27602 preserve plugin Apps in connector listings.\r\n- PR5: #27461 skip install-time plugin MCP OAuth for matching App routes.\r\n\r\n## Summary\r\n\r\n- Make `load_plugin_mcp_servers` auth-aware and let it load App declarations before filtering same-name MCP servers for Codex-backend auth.\r\n- Use that filtered MCP list for both install-time MCP OAuth and marketplace plugin detail metadata.\r\n- Preserve API-key/direct auth behavior so plugin MCP servers remain visible and can still start OAuth.\r\n\r\n## Validation\r\n\r\n```bash\r\ncargo fmt --all\r\ncargo test -p codex-core-plugins read_plugin_for_config_filters_mcp_servers_for_codex_backend_auth\r\ncargo check -p codex-core-plugins -p codex-app-server\r\ngit diff --check\r\ngit diff --cached --check\r\n```\r\n",
"labels": [],
"merged_at": "2026-06-15T13:04:01Z",
"number": 27461,
"state": "merged",
"title": "[codex] Skip plugin MCP OAuth for matching app routes",
"url": "https://github.com/openai/codex/pull/27461"
},
"repo": "openai/codex",
"schema": "github_change_bundle/v1"
}
116 changes: 116 additions & 0 deletions artifacts/github/bundles/openai-codex-pr-27602.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{
"analysis_mode": "pr_first",
"commits": [
{
"author": "felixxia-oai",
"committed_at": "2026-06-11T19:38:54Z",
"message": "Preserve plugin apps in connector listings",
"sha": "6a3bac99652534ee250536787b3d40061981283a",
"url": "https://github.com/openai/codex/commit/6a3bac99652534ee250536787b3d40061981283a"
},
{
"author": "felixxia-oai",
"committed_at": "2026-06-12T10:18:45Z",
"message": "Inline plugin app lookup in apps list",
"sha": "e93643d804ea1f7ed68ca286fbe935e5e32ec3a1",
"url": "https://github.com/openai/codex/commit/e93643d804ea1f7ed68ca286fbe935e5e32ec3a1"
},
{
"author": "felixxia-oai",
"committed_at": "2026-06-12T10:32:21Z",
"message": "Simplify connector listing options",
"sha": "6370a49ab0b18daeeaf3b531c4e3b0d1c645c979",
"url": "https://github.com/openai/codex/commit/6370a49ab0b18daeeaf3b531c4e3b0d1c645c979"
}
],
"default_branch": "main",
"docs_refs": [],
"examples_refs": [],
"extracted_flags": [
"PR4",
"MCP",
"SIWC",
"API",
"PR1",
"PR2",
"PR3",
"PR5",
"--check",
"JSONRPCE",
"ZERO",
"DEFAULT_TIMEOUT",
"JSONRPCR"
],
"files": [
{
"additions": 0,
"deletions": 1,
"patch_excerpt": "@@ -2257,7 +2257,6 @@ dependencies = [\n \"codex-app-server-protocol\",\n \"codex-connectors\",\n \"codex-core\",\n- \"codex-core-plugins\",\n \"codex-git-utils\",\n \"codex-login\",\n \"codex-model-provider\",",
"path": "codex-rs/Cargo.lock",
"status": "modified"
},
{
"additions": 1,
"deletions": 0,
"patch_excerpt": "@@ -318,6 +318,7 @@ use codex_core_plugins::PluginInstallError as CorePluginInstallError;\n use codex_core_plugins::PluginInstallRequest;\n use codex_core_plugins::PluginReadRequest;\n use codex_core_plugins::PluginUninstallError as CorePluginUninstallError;\n+use codex_core_plugins::PluginsManager;\n use codex_core_plugins::loader::load_plugin_apps;\n use codex_core_plugins::loader::load_plugin_mcp_servers;\n use codex_core_plugins::loader::plugin_telemetry_metadata_from_root;",
"path": "codex-rs/app-server/src/request_processors.rs",
"status": "modified"
},
{
"additions": 28,
"deletions": 7,
"patch_excerpt": "@@ -89,6 +89,7 @@ impl AppsRequestProcessor {\n let outgoing = Arc::clone(&self.outgoing);\n let environment_manager = self.thread_manager.environment_manager();\n let mcp_manager = self.thread_manager.mcp_manager();\n+ let plugins_manager = self.thread_manager.plugins_manager();\n let shutdown_token = self.shutdown_token.child_token();\n tokio::spawn(async move {\n tokio::select! {\n@@ -100,6 +101,7 @@ impl AppsRequestProcessor {\n config,\n environment_manager,\n mcp_manager,\n+ plugins_manager,\n ) => {}\n }\n });\n@@ -117,14 +119,22 @@ impl AppsRequestProcessor {\n config: Config,\n environment_manager: Arc<EnvironmentManager>,\n mcp_manager: Arc<McpManager>,\n+ plugins_manager: Arc<PluginsManager>,\n ...",
"path": "codex-rs/app-server/src/request_processors/apps_processor.rs",
"status": "modified"
},
{
"additions": 18,
"deletions": 13,
"patch_excerpt": "@@ -1578,7 +1578,7 @@ impl PluginRequestProcessor {\n .as_ref()\n .map(plugin_app_category_by_id_from_value)\n .unwrap_or_default();\n- let all_connectors = connectors::list_cached_all_connectors(&config)\n+ let all_connectors = connectors::list_cached_all_connectors(&config, &[])\n .await\n .unwrap_or_default();\n connectors::connectors_for_plugin_apps(all_connectors, &plugin_apps)\n@@ -1630,7 +1630,7 @@ impl PluginRequestProcessor {\n \n let environment_manager = self.thread_manager.environment_manager();\n let (all_connectors_result, accessible_connectors_result) = tokio::join!(\n- connectors::list_all_connectors_with_options(config, /*force_refetch*/ false),\n+ connectors::list_all_connectors_with_options(config, /*f...",
"path": "codex-rs/app-server/src/request_processors/plugins.rs",
"status": "modified"
},
{
"additions": 87,
"deletions": 0,
"patch_excerpt": "@@ -1,5 +1,6 @@\n use std::borrow::Cow;\n use std::collections::HashMap;\n+use std::path::Path;\n use std::sync::Arc;\n use std::sync::Mutex as StdMutex;\n use std::time::Duration;\n@@ -215,6 +216,50 @@ async fn list_apps_returns_empty_when_workspace_codex_plugins_disabled() -> Resu\n Ok(())\n }\n \n+#[tokio::test]\n+async fn list_apps_includes_plugin_apps_for_chatgpt_auth() -> Result<()> {\n+ let (server_url, server_handle) =\n+ start_apps_server_with_delays(Vec::new(), Vec::new(), Duration::ZERO, Duration::ZERO)\n+ .await?;\n+\n+ let codex_home = TempDir::new()?;\n+ write_connectors_and_plugins_config(codex_home.path(), &server_url)?;\n+ write_plugin_app_fixture(codex_home.path(), \"sample\", \"connector_sample\")?;\n+ write_chatgpt_auth(\n+ codex_home.path(),\n+ ChatGptAuthFixture::new(\"chatgpt-token\")\n+ .account_id(\"account-123\")\n+ .chat...",
"path": "codex-rs/app-server/tests/suite/v2/app_list.rs",
"status": "modified"
},
{
"additions": 0,
"deletions": 1,
"patch_excerpt": "@@ -13,7 +13,6 @@ clap = { workspace = true, features = [\"derive\"] }\n codex-app-server-protocol = { workspace = true }\n codex-connectors = { workspace = true }\n codex-core = { workspace = true }\n-codex-core-plugins = { workspace = true }\n codex-git-utils = { workspace = true }\n codex-login = { workspace = true }\n codex-model-provider = { workspace = true }",
"path": "codex-rs/chatgpt/Cargo.toml",
"status": "modified"
},
{
"additions": 19,
"deletions": 31,
"patch_excerpt": "@@ -19,7 +19,6 @@ pub use codex_core::connectors::list_accessible_connectors_from_mcp_tools_with_o\n pub use codex_core::connectors::list_accessible_connectors_from_mcp_tools_with_options_and_status;\n pub use codex_core::connectors::list_cached_accessible_connectors_from_mcp_tools;\n pub use codex_core::connectors::with_app_enabled_state;\n-use codex_core_plugins::PluginsManager;\n use codex_login::AuthManager;\n use codex_login::CodexAuth;\n use codex_login::default_client::originator;\n@@ -69,33 +68,27 @@ pub async fn list_connectors(config: &Config) -> anyhow::Result<Vec<AppInfo>> {\n }\n \n pub async fn list_all_connectors(config: &Config) -> anyhow::Result<Vec<AppInfo>> {\n- list_all_connectors_with_options(config, /*force_refetch*/ false).await\n+ list_all_connectors_with_options(config, /*force_refetch*/ false, &[]).await\n }\n \n-pub async fn list_cached_all_connectors(config: &Config) ->...",
"path": "codex-rs/chatgpt/src/connectors.rs",
"status": "modified"
}
],
"linked_issues": [
"#27652",
"#27459",
"#27607",
"#27602",
"#27461"
],
"notes": [
"Built from GitHub pull-request, commits, files, and repo endpoints."
],
"primary_pr": {
"body": "## Context\n\nThis is PR4 in the plugin auth-routing stack. The earlier PRs make plugin surface projection auth-aware and narrow App/MCP conflicts by App declaration name. This PR keeps connector listing paths aligned with that projected plugin App set.\n\nThis means ChatGPT/SIWC users will still see plugin-provided Apps in connector listing surfaces like the Apps/connector picker, while API-key users will not see Apps they cannot use.\n\n## Stack\n\n- PR1: #27652 seed plugin manager auth at construction.\n- PR2: #27459 route plugin surfaces by auth mode.\n- PR3: #27607 dedupe plugin MCP servers by App declaration name.\n- PR4: #27602 preserve plugin Apps in connector listings.\n- PR5: #27461 skip install-time plugin MCP OAuth for matching App routes.\n\n## Summary\n\n- Have app-server compute effective plugin Apps from the existing PluginsManager and pass them into connector listing.\n- Keep plugin Apps visible in Apps/connector listing for ChatGPT/SIWC users.\n- Keep API-key-style auth from surfacing plugin Apps in connector listings.\n\n## Validation\n\n```bash\ncargo test -p codex-chatgpt connectors::tests\ncargo test -p codex-app-server list_apps_includes_plugin_apps_for_chatgpt_auth\ngit diff --check\n```",
"labels": [],
"merged_at": "2026-06-15T12:50:08Z",
"number": 27602,
"state": "merged",
"title": "[codex] Preserve plugin apps in connector listings",
"url": "https://github.com/openai/codex/pull/27602"
},
"repo": "openai/codex",
"schema": "github_change_bundle/v1"
}
Loading