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
94 changes: 94 additions & 0 deletions artifacts/github/bundles/openai-codex-pr-26835.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
{
"analysis_mode": "pr_first",
"commits": [
{
"author": "anp-oai",
"committed_at": "2026-06-06T22:56:17Z",
"message": "test extension API contracts",
"sha": "4f1183c281d837c81ee3f13f4b9207fc4bbd7115",
"url": "https://github.com/openai/codex/commit/4f1183c281d837c81ee3f13f4b9207fc4bbd7115"
},
{
"author": "anp-oai",
"committed_at": "2026-06-08T15:34:12Z",
"message": "codex: address PR review feedback (#26835)",
"sha": "4678bad085f9dac6876e0466c5f922635926d7db",
"url": "https://github.com/openai/codex/commit/4678bad085f9dac6876e0466c5f922635926d7db"
},
{
"author": "anp-oai",
"committed_at": "2026-06-08T15:54:06Z",
"message": "test: explain forced initializer overlap",
"sha": "583f8cca1bd6d6a4ea2762ad6ec1e39d646a8d51",
"url": "https://github.com/openai/codex/commit/583f8cca1bd6d6a4ea2762ad6ec1e39d646a8d51"
},
{
"author": "anp-oai",
"committed_at": "2026-06-09T18:22:46Z",
"message": "codex: address PR review feedback (#26835)",
"sha": "3a804efa84757c84da11729a04e04995d5c04c8c",
"url": "https://github.com/openai/codex/commit/3a804efa84757c84da11729a04e04995d5c04c8c"
}
],
"default_branch": "main",
"docs_refs": [],
"examples_refs": [],
"extracted_flags": [
"API",
"CALLER_COUNT"
],
"files": [
{
"additions": 2,
"deletions": 0,
"patch_excerpt": "@@ -2923,6 +2923,8 @@ dependencies = [\n \"codex-context-fragments\",\n \"codex-protocol\",\n \"codex-tools\",\n+ \"pretty_assertions\",\n+ \"tokio\",\n ]\n \n [[package]]",
"path": "codex-rs/Cargo.lock",
"status": "modified"
},
{
"additions": 4,
"deletions": 0,
"patch_excerpt": "@@ -18,3 +18,7 @@ async-trait = { workspace = true }\n codex-context-fragments = { workspace = true }\n codex-protocol = { workspace = true }\n codex-tools = { workspace = true }\n+\n+[dev-dependencies]\n+pretty_assertions = { workspace = true }\n+tokio = { workspace = true, features = [\"macros\", \"rt-multi-thread\"] }",
"path": "codex-rs/ext/extension-api/Cargo.toml",
"status": "modified"
},
{
"additions": 56,
"deletions": 0,
"patch_excerpt": "@@ -0,0 +1,56 @@\n+use std::sync::Arc;\n+use std::sync::Mutex;\n+\n+use codex_extension_api::AgentSpawnFuture;\n+use codex_extension_api::AgentSpawner;\n+use codex_extension_api::NoopResponseItemInjector;\n+use codex_extension_api::ResponseItemInjector;\n+use codex_protocol::ThreadId;\n+use codex_protocol::models::ContentItem;\n+use codex_protocol::models::ResponseInputItem;\n+use pretty_assertions::assert_eq;\n+\n+#[tokio::test]\n+async fn noop_response_item_injector_returns_original_items() {\n+ let items = vec![ResponseInputItem::Message {\n+ role: \"user\".to_string(),\n+ content: vec![ContentItem::InputText {\n+ text: \"keep this input\".to_string(),\n+ }],\n+ phase: None,\n+ }];\n+\n+ let returned_items = NoopResponseItemInjector\n+ .inject_response_items(items.clone())\n+ .await\n+ .expect_err(\"noop injector should reject same-turn injection\"...",
"path": "codex-rs/ext/extension-api/tests/capabilities.rs",
"status": "added"
},
{
"additions": 370,
"deletions": 0,
"patch_excerpt": "@@ -0,0 +1,370 @@\n+use std::future::Future;\n+use std::pin::Pin;\n+use std::sync::Arc;\n+use std::sync::Mutex;\n+\n+use codex_extension_api::ApprovalReviewContributor;\n+use codex_extension_api::ConfigContributor;\n+use codex_extension_api::ContextContributor;\n+use codex_extension_api::ContextualUserFragment;\n+use codex_extension_api::ExtensionData;\n+use codex_extension_api::ExtensionEventSink;\n+use codex_extension_api::ExtensionRegistryBuilder;\n+use codex_extension_api::PromptFragment;\n+use codex_extension_api::ThreadLifecycleContributor;\n+use codex_extension_api::TokenUsageContributor;\n+use codex_extension_api::ToolCall;\n+use codex_extension_api::ToolContributor;\n+use codex_extension_api::ToolExecutor;\n+use codex_extension_api::ToolLifecycleContributor;\n+use codex_extension_api::TurnInputContext;\n+use codex_extension_api::TurnInputContributor;\n+use codex_extension_api::TurnItemContributor;\n+u...",
"path": "codex-rs/ext/extension-api/tests/registry.rs",
"status": "added"
},
{
"additions": 109,
"deletions": 0,
"patch_excerpt": "@@ -0,0 +1,109 @@\n+use std::panic::AssertUnwindSafe;\n+use std::sync::Arc;\n+use std::sync::atomic::AtomicUsize;\n+use std::sync::atomic::Ordering;\n+\n+use codex_extension_api::ExtensionData;\n+use pretty_assertions::assert_eq;\n+\n+#[test]\n+fn typed_values_can_be_inserted_replaced_and_removed() {\n+ let data = ExtensionData::new(\"thread-1\");\n+\n+ assert_eq!(data.insert(/*value*/ 41_u64), None);\n+ assert_eq!(data.insert(\"alpha\".to_string()), None);\n+ assert_eq!(data.get::<u64>().as_deref(), Some(&41));\n+ assert_eq!(\n+ data.get::<String>().map(|value| value.as_str().to_string()),\n+ Some(\"alpha\".to_string())\n+ );\n+\n+ assert_eq!(data.insert(/*value*/ 42_u64).as_deref(), Some(&41));\n+ assert_eq!(data.get::<u64>().as_deref(), Some(&42));\n+ assert_eq!(\n+ data.remove::<String>()\n+ .map(|value| value.as_str().to_string()),\n+ Some(\"alpha\".t...",
"path": "codex-rs/ext/extension-api/tests/state.rs",
"status": "added"
}
],
"linked_issues": [
"#26835"
],
"notes": [
"Built from GitHub pull-request, commits, files, and repo endpoints."
],
"primary_pr": {
"body": "## Why\n\n`codex-extension-api` defines contracts shared by extension crates and their hosts, but it had no direct test suite. Host and feature tests cover downstream behavior, while regressions in the API crate's own typed state, registry ordering, and capability adapters could go unnoticed.\n\n## What\n\n- Add public-surface integration tests for `ExtensionData`, including concurrent initialization and poison recovery.\n- Cover contributor registration order, approval short-circuiting, event sink retention, no-op response injection, and closure-based agent spawning.\n- Add the test-only dependencies used by the suite.\n\n## Validation\n\n- `just test -p codex-extension-api`\n- `just argument-comment-lint -p codex-extension-api`\n- `just bazel-lock-check`\n",
"labels": [],
"merged_at": "2026-06-09T18:30:24Z",
"number": 26835,
"state": "merged",
"title": "[codex] Test extension API contracts",
"url": "https://github.com/openai/codex/pull/26835"
},
"repo": "openai/codex",
"schema": "github_change_bundle/v1"
}
61 changes: 61 additions & 0 deletions artifacts/github/bundles/openai-codex-pr-27085.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"analysis_mode": "pr_first",
"commits": [
{
"author": "xl-openai",
"committed_at": "2026-06-08T23:03:21Z",
"message": "Use server app auth requirements for remote plugin install",
"sha": "df5b449689130d0e0dbd65ab882aa784a9c02028",
"url": "https://github.com/openai/codex/commit/df5b449689130d0e0dbd65ab882aa784a9c02028"
}
],
"default_branch": "main",
"docs_refs": [],
"examples_refs": [],
"extracted_flags": [
"REMOTE_PLUGIN_ID",
"TEST_ALLOW_HTTP_REMOTE_PLUGIN_BUNDLE_DOWNLOADS",
"DEFAULT_TIMEOUT",
"JSONRPCR",
"GET",
"POST"
],
"files": [
{
"additions": 38,
"deletions": 11,
"patch_excerpt": "@@ -1519,7 +1519,7 @@ impl PluginRequestProcessor {\n // Cache first so a backend install cannot succeed when local materialization fails.\n // If this backend call fails, the cache entry is harmless because remote installed state\n // is still backend-gated.\n- codex_core_plugins::remote::install_remote_plugin(\n+ let install_result = codex_core_plugins::remote::install_remote_plugin(\n &remote_plugin_service_config,\n auth.as_ref(),\n &actual_remote_marketplace_name,\n@@ -1538,7 +1538,7 @@ impl PluginRequestProcessor {\n \n let mut plugin_metadata =\n plugin_telemetry_metadata_from_root(&result.plugin_id, &result.installed_path).await;\n- plugin_metadata.remote_plugin_id = Some(remote_plugin_id);\n+ plugin_metadata.remote_plugin_id = Some(remote_plugin_id.clone());\n self.analytics_even...",
"path": "codex-rs/app-server/src/request_processors/plugins.rs",
"status": "modified"
},
{
"additions": 102,
"deletions": 0,
"patch_excerpt": "@@ -288,6 +288,59 @@ async fn plugin_install_writes_remote_plugin_to_cloud_and_cache() -> Result<()>\n Ok(())\n }\n \n+#[tokio::test]\n+async fn plugin_install_uses_remote_apps_needing_auth_response() -> Result<()> {\n+ let codex_home = TempDir::new()?;\n+ let server = MockServer::start().await;\n+ let bundle_url = mount_remote_plugin_bundle(\n+ &server,\n+ /*status_code*/ 200,\n+ remote_plugin_bundle_tar_gz_bytes(\"linear\")?,\n+ )\n+ .await;\n+ configure_remote_plugin_with_apps_test(codex_home.path(), &server)?;\n+ mount_remote_plugin_detail(&server, REMOTE_PLUGIN_ID, \"1.2.3\", Some(&bundle_url)).await;\n+ mount_empty_remote_installed_plugins(&server).await;\n+ mount_remote_plugin_install_with_apps_needing_auth(&server, REMOTE_PLUGIN_ID, &[\"alpha\"]).await;\n+\n+ let mut mcp = TestAppServer::new_with_env(\n+ codex_home.path(),\n+ &[(TEST_ALLO...",
"path": "codex-rs/app-server/tests/suite/v2/plugin_install.rs",
"status": "modified"
},
{
"additions": 16,
"deletions": 3,
"patch_excerpt": "@@ -550,6 +550,12 @@ struct RemotePluginInstalledResponse {\n struct RemotePluginMutationResponse {\n id: String,\n enabled: bool,\n+ app_ids_needing_auth: Option<Vec<String>>,\n+}\n+\n+#[derive(Debug, Clone, PartialEq, Eq)]\n+pub struct RemotePluginInstallResult {\n+ pub app_ids_needing_auth: Option<Vec<String>>,\n }\n \n pub async fn fetch_remote_marketplaces(\n@@ -1071,15 +1077,20 @@ pub async fn install_remote_plugin(\n auth: Option<&CodexAuth>,\n _marketplace_name: &str,\n plugin_id: &str,\n-) -> Result<(), RemotePluginCatalogError> {\n+) -> Result<RemotePluginInstallResult, RemotePluginCatalogError> {\n let auth = ensure_chatgpt_auth(auth)?;\n // Remote plugin IDs uniquely identify remote plugins, so the caller-provided\n // marketplace name is not validated before sending the install mutation.\n \n let base_url = config.chatgpt_base_url.trim_end_matches('/');\n ...",
"path": "codex-rs/core-plugins/src/remote.rs",
"status": "modified"
}
],
"linked_issues": [],
"notes": [
"Built from GitHub pull-request, commits, files, and repo endpoints."
],
"primary_pr": {
"body": "## Summary\n- request `includeAppsNeedingAuth=true` when installing remote plugins\n- return backend-provided `app_ids_needing_auth` from the remote install client\n- use those app IDs to populate `appsNeedingAuth` without refetching accessible apps, with fallback for older responses\n\n## Testing\n- `just fmt`\n- `just test -p codex-app-server`\n- `just test -p codex-core-plugins`\n- real app-server install/uninstall check with Notion remote plugin\n- subagent review found no blocking issues\n",
"labels": [],
"merged_at": "2026-06-09T04:39:35Z",
"number": 27085,
"state": "merged",
"title": "Use server app auth requirements for remote plugin install",
"url": "https://github.com/openai/codex/pull/27085"
},
"repo": "openai/codex",
"schema": "github_change_bundle/v1"
}
Loading
Loading