mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Fix Windows running thread resume path normalization (#25509)
## Why Fixes #24944. On Windows, app-server resume could reject an active running thread when the requested session path used normal `C:\...` form and the already-running path used verbatim `\\?\C:\...` form. The paths point at the same JSONL file, but the resume stale-path guard compared raw `PathBuf`s, so desktop resume and heartbeat flows could fail with a mismatched-path error. ## What Changed - Compare requested and active rollout paths with `path_utils::paths_match_after_normalization`. - Extend the existing running-thread mismatched-path test with a Windows-only same-file resume case before the stale-path rejection. ## Verification - `just test -p codex-app-server thread_resume_rejects_mismatched_path_for_running_thread_id`
This commit is contained in:
committed by
GitHub
Unverified
parent
af18e92140
commit
ad355d4c96
@@ -2766,7 +2766,7 @@ impl ThreadRequestProcessor {
|
||||
.as_ref()
|
||||
.or(source_thread.rollout_path.as_ref());
|
||||
if let (Some(requested_path), Some(active_path)) = (params.path.as_ref(), active_path)
|
||||
&& requested_path != active_path
|
||||
&& !path_utils::paths_match_after_normalization(requested_path, active_path)
|
||||
{
|
||||
return Err(invalid_request(format!(
|
||||
"cannot resume running thread {existing_thread_id} with stale path: requested `{}`, active `{}`",
|
||||
|
||||
@@ -2410,6 +2410,36 @@ async fn thread_resume_rejects_mismatched_path_for_running_thread_id() -> Result
|
||||
)
|
||||
.await??;
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let active_path = thread.path.as_ref().expect("thread should have path");
|
||||
let active_path_display = active_path.as_os_str().to_string_lossy();
|
||||
let equivalent_path = if let Some(path) = active_path_display.strip_prefix(r"\\?\UNC\") {
|
||||
PathBuf::from(format!(r"\\{path}"))
|
||||
} else if let Some(path) = active_path_display.strip_prefix(r"\\?\") {
|
||||
PathBuf::from(path)
|
||||
} else if let Some(path) = active_path_display.strip_prefix(r"\\") {
|
||||
PathBuf::from(format!(r"\\?\UNC\{path}"))
|
||||
} else {
|
||||
PathBuf::from(format!(r"\\?\{active_path_display}"))
|
||||
};
|
||||
let normalized_resume_id = primary
|
||||
.send_thread_resume_request(ThreadResumeParams {
|
||||
thread_id: thread_id.clone(),
|
||||
path: Some(equivalent_path),
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
let normalized_resume_resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
primary.read_stream_until_response_message(RequestId::Integer(normalized_resume_id)),
|
||||
)
|
||||
.await??;
|
||||
let ThreadResumeResponse { thread, .. } =
|
||||
to_response::<ThreadResumeResponse>(normalized_resume_resp)?;
|
||||
assert_eq!(thread.id, thread_id);
|
||||
}
|
||||
|
||||
let stale_thread_id = Uuid::new_v4().to_string();
|
||||
let stale_path = rollout_path(codex_home.path(), "2025-01-01T00-00-00", &stale_thread_id);
|
||||
std::fs::create_dir_all(stale_path.parent().expect("stale path parent"))?;
|
||||
|
||||
Reference in New Issue
Block a user