codex: auto-unarchive archived sessions safely on resume

Preserve the auto-unarchive-on-resume behavior while keeping archived-session lookup safe. This carries the rollout lookup hardening, the resume path updates, and the cross-platform guardian/TUI test fixes needed for current CI.
This commit is contained in:
Friel
2026-03-28 11:35:15 -07:00
parent 65f631c3d6
commit 328706da37
8 changed files with 242 additions and 9 deletions
+2 -2
View File
@@ -339,8 +339,8 @@ fn guardian_assessment_action_value_redacts_apply_patch_patch_text() {
guardian_assessment_action_value(&action),
serde_json::json!({
"tool": "apply_patch",
"cwd": cwd,
"files": [file],
"cwd": cwd.display().to_string(),
"files": [file.display().to_string()],
"change_count": 1,
})
);
+1
View File
@@ -168,6 +168,7 @@ pub use rollout::append_thread_name;
pub use rollout::find_archived_thread_path_by_id_str;
#[deprecated(note = "use find_thread_path_by_id_str")]
pub use rollout::find_conversation_path_by_id_str;
pub use rollout::find_or_unarchive_thread_path_by_id_str;
pub use rollout::find_thread_name_by_id;
pub use rollout::find_thread_path_by_id_str;
pub use rollout::find_thread_path_by_name_str;
@@ -9,6 +9,7 @@ use codex_core::RolloutRecorder;
use codex_core::RolloutRecorderParams;
use codex_core::config::ConfigBuilder;
use codex_core::find_archived_thread_path_by_id_str;
use codex_core::find_or_unarchive_thread_path_by_id_str;
use codex_core::find_thread_path_by_id_str;
use codex_core::find_thread_path_by_name_str;
use codex_protocol::ThreadId;
@@ -219,3 +220,74 @@ async fn find_archived_locates_rollout_file_by_id() {
assert_eq!(found, Some(expected));
}
#[tokio::test]
async fn find_thread_path_by_id_str_does_not_unarchive_archived_rollout() {
let home = TempDir::new().unwrap();
let id = Uuid::new_v4();
let archived = write_minimal_rollout_with_id_in_subdir(home.path(), "archived_sessions", id);
let found = find_thread_path_by_id_str(home.path(), &id.to_string())
.await
.unwrap();
assert_eq!(found, None);
assert!(archived.exists());
}
#[tokio::test]
async fn find_or_unarchive_restores_archived_rollout_file_by_id() {
let home = TempDir::new().unwrap();
let id = Uuid::new_v4();
let archived = write_minimal_rollout_with_id_in_subdir(home.path(), "archived_sessions", id);
let file_name = archived.file_name().unwrap().to_owned();
let expected_restored = home.path().join("sessions/2024/01/01").join(file_name);
let found = find_or_unarchive_thread_path_by_id_str(home.path(), &id.to_string())
.await
.unwrap();
assert_eq!(found, Some(expected_restored.clone()));
assert!(expected_restored.exists());
assert!(!archived.exists());
let archived_found = find_archived_thread_path_by_id_str(home.path(), &id.to_string())
.await
.unwrap();
assert_eq!(archived_found, None);
}
#[tokio::test]
async fn find_does_not_move_unrelated_file_for_stale_archived_db_path() {
let home = TempDir::new().unwrap();
let requested_id = Uuid::new_v4();
let requested_thread_id = ThreadId::from_string(&requested_id.to_string()).unwrap();
let unrelated_id = Uuid::new_v4();
let unrelated_active_path = write_minimal_rollout_with_id(home.path(), unrelated_id);
upsert_thread_metadata(
home.path(),
requested_thread_id,
unrelated_active_path.clone(),
)
.await;
let runtime = StateRuntime::init(home.path().to_path_buf(), "test-provider".to_string())
.await
.unwrap();
runtime.mark_backfill_complete(None).await.unwrap();
runtime
.mark_archived(
requested_thread_id,
unrelated_active_path.as_path(),
Utc::now(),
)
.await
.unwrap();
let found = find_or_unarchive_thread_path_by_id_str(home.path(), &requested_id.to_string())
.await
.unwrap();
assert_eq!(found, None);
assert!(unrelated_active_path.exists());
}