diff --git a/codex-rs/app-server/tests/suite/v2/external_agent_config.rs b/codex-rs/app-server/tests/suite/v2/external_agent_config.rs index 70d923ec8c..cf84e53e16 100644 --- a/codex-rs/app-server/tests/suite/v2/external_agent_config.rs +++ b/codex-rs/app-server/tests/suite/v2/external_agent_config.rs @@ -1563,7 +1563,7 @@ async fn external_agent_config_import_creates_session_rollouts() -> Result<()> { "type": "assistant", "cwd": &project_root, "timestamp": source_updated_at_text, - "attributionMcpServer": "gmail-server", + "attributionMcpServer": "gmail", "message": { "content": "first answer" }, }) .to_string(), diff --git a/codex-rs/external-agent-migration/src/detect/sessions/connectors_cla.rs b/codex-rs/external-agent-migration/src/detect/sessions/connectors_cla.rs index 60002897ad..ee5ff8ac46 100644 --- a/codex-rs/external-agent-migration/src/detect/sessions/connectors_cla.rs +++ b/codex-rs/external-agent-migration/src/detect/sessions/connectors_cla.rs @@ -65,17 +65,23 @@ pub fn detect_imported_cla_session_connectors( let connector_names = connector_names_by_session.entry(session_id).or_default(); for server in manifest.remote_mcp_servers_config { - let Some(uuid) = server.uuid else { - continue; - }; - if !attributed_server_ids.contains(&uuid) { - continue; - } let Some(name) = crate::sessions::normalized_connector_display_name(server.name.as_deref()) else { continue; }; + // Depending on the source client, attributionMcpServer contains either the + // manifest UUID or its configured server name. + let matches_uuid = server + .uuid + .as_deref() + .is_some_and(|uuid| attributed_server_ids.contains(uuid)); + let matches_name = attributed_server_ids + .iter() + .any(|server_id| server_id.eq_ignore_ascii_case(&name)); + if !matches_uuid && !matches_name { + continue; + } connector_names.entry(name.to_lowercase()).or_insert(name); } } @@ -114,3 +120,7 @@ fn json_files_recursively(root: &Path) -> Vec { } files } + +#[cfg(test)] +#[path = "connectors_cla_tests.rs"] +mod tests; diff --git a/codex-rs/external-agent-migration/src/detect/sessions/connectors_cla_tests.rs b/codex-rs/external-agent-migration/src/detect/sessions/connectors_cla_tests.rs new file mode 100644 index 0000000000..aa61cde80f --- /dev/null +++ b/codex-rs/external-agent-migration/src/detect/sessions/connectors_cla_tests.rs @@ -0,0 +1,74 @@ +use super::*; +use pretty_assertions::assert_eq; +use std::collections::BTreeSet; +use tempfile::TempDir; + +#[test] +fn resolves_attributed_server_name_from_session_manifest() { + let metadata_root = TempDir::new().expect("tempdir"); + let manifests_root = metadata_root.path().join(SESSION_MANIFESTS_DIR); + std::fs::create_dir_all(&manifests_root).expect("manifest directory"); + std::fs::write( + manifests_root.join("session.json"), + serde_json::json!({ + "cliSessionId": "session-1", + "remoteMcpServersConfig": [ + { + "uuid": "c58ac595-58b5-48f8-ac77-d8d01523dede", + "name": "Figma", + }, + ], + }) + .to_string(), + ) + .expect("manifest"); + let attributions = vec![ImportedSessionConnectorAttribution { + session_id: "session-1".to_string(), + server_ids: BTreeSet::from(["figma".to_string()]), + }]; + + let connector_names = detect_imported_cla_session_connectors( + &attributions, + &[metadata_root.path().to_path_buf()], + ); + + assert_eq!( + connector_names, + BTreeMap::from([("session-1".to_string(), vec!["Figma".to_string()])]) + ); +} + +#[test] +fn still_resolves_attributed_server_uuid_from_session_manifest() { + let metadata_root = TempDir::new().expect("tempdir"); + let manifests_root = metadata_root.path().join(SESSION_MANIFESTS_DIR); + std::fs::create_dir_all(&manifests_root).expect("manifest directory"); + std::fs::write( + manifests_root.join("session.json"), + serde_json::json!({ + "cliSessionId": "session-1", + "remoteMcpServersConfig": [ + { + "uuid": "c58ac595-58b5-48f8-ac77-d8d01523dede", + "name": "Figma", + }, + ], + }) + .to_string(), + ) + .expect("manifest"); + let attributions = vec![ImportedSessionConnectorAttribution { + session_id: "session-1".to_string(), + server_ids: BTreeSet::from(["c58ac595-58b5-48f8-ac77-d8d01523dede".to_string()]), + }]; + + let connector_names = detect_imported_cla_session_connectors( + &attributions, + &[metadata_root.path().to_path_buf()], + ); + + assert_eq!( + connector_names, + BTreeMap::from([("session-1".to_string(), vec!["Figma".to_string()])]) + ); +}