Move installation ID resolution out of core startup (#21182)

## Summary

- resolve or inject the installation ID before core startup and pass it
through `ThreadManager`, `CodexSpawnArgs`, and `Session` as a plain
`String`
- keep child sessions on the parent installation ID instead of
rediscovering it inside core
- propagate installation ID startup failures in `mcp-server` instead of
panicking

## Why

Core was still touching the filesystem on the session startup path to
discover `installation_id`. This moves that work to the outer host
boundary so core no longer depends on `codex_home` reads during session
construction.

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
jif-oai
2026-05-06 10:48:54 +00:00
committed by GitHub
co-authored by Codex
parent 5d6f23a27b
commit 8f3bb355f4
20 changed files with 128 additions and 11 deletions
+52
View File
@@ -1,5 +1,6 @@
use super::*;
use crate::config::test_config;
use crate::installation_id::INSTALLATION_ID_FILENAME;
use crate::rollout::RolloutRecorder;
use crate::session::session::SessionSettingsUpdate;
use crate::session::tests::make_session_and_context;
@@ -26,6 +27,8 @@ use std::time::Duration;
use tempfile::tempdir;
use wiremock::MockServer;
const TEST_INSTALLATION_ID: &str = "11111111-1111-4111-8111-111111111111";
fn user_msg(text: &str) -> ResponseItem {
ResponseItem::Message {
id: None,
@@ -415,6 +418,7 @@ async fn resume_and_fork_do_not_restore_thread_environments_from_rollout() {
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let selected_cwd =
AbsolutePathBuf::try_from(config.cwd.as_path().join("selected")).expect("absolute path");
@@ -509,6 +513,46 @@ async fn resume_and_fork_do_not_restore_thread_environments_from_rollout() {
);
}
#[tokio::test]
async fn explicit_installation_id_skips_codex_home_file() {
let temp_dir = tempdir().expect("tempdir");
let mut config = test_config().await;
config.codex_home = temp_dir.path().join("codex-home").abs();
config.cwd = config.codex_home.abs();
std::fs::create_dir_all(&config.codex_home).expect("create codex home");
let auth_manager =
AuthManager::from_auth_for_testing(CodexAuth::create_dummy_chatgpt_auth_for_testing());
let installation_id = uuid::Uuid::new_v4().to_string();
let (state_db, thread_store, agent_graph_store) = state_backed_stores(&config).await;
let manager = ThreadManager::new(
&config,
auth_manager,
SessionSource::Exec,
Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()),
/*analytics_events_client*/ None,
state_db,
thread_store,
agent_graph_store,
installation_id.clone(),
);
let thread = manager
.start_thread(config.clone())
.await
.expect("start thread with explicit installation id");
assert!(!config.codex_home.join(INSTALLATION_ID_FILENAME).exists());
assert_eq!(thread.thread.codex.session.installation_id, installation_id);
thread
.thread
.shutdown_and_wait()
.await
.expect("shutdown thread");
let _ = manager.remove_thread(&thread.thread_id).await;
}
#[tokio::test]
async fn resume_active_thread_from_rollout_returns_running_thread() {
let temp_dir = tempdir().expect("tempdir");
@@ -529,6 +573,7 @@ async fn resume_active_thread_from_rollout_returns_running_thread() {
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let source = manager
@@ -585,6 +630,7 @@ async fn resume_stopped_thread_from_rollout_spawns_new_thread() {
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let source = manager
@@ -646,6 +692,7 @@ async fn resume_stopped_thread_from_rollout_preserves_thread_source() {
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let source = manager
@@ -731,6 +778,7 @@ async fn new_uses_active_provider_for_model_refresh() {
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let _ = manager.list_models(RefreshStrategy::Online).await;
@@ -945,6 +993,7 @@ async fn interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_histor
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let source = manager
@@ -1051,6 +1100,7 @@ async fn interrupted_fork_snapshot_preserves_explicit_turn_id() {
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let source = manager
@@ -1146,6 +1196,7 @@ async fn interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let source = manager
@@ -1287,6 +1338,7 @@ async fn resumed_thread_keeps_paused_goal_paused() -> anyhow::Result<()> {
state_db,
thread_store,
agent_graph_store,
TEST_INSTALLATION_ID.to_string(),
);
let source = manager