fix: handle utf-8 in windows sandbox logs (#8647)

Currently `apply_patch` will fail on Windows if the file contents happen
to have a multi-byte character at the point where the `preview` function
truncates.

I've used the existing `take_bytes_at_char_boundary` helper and added a
regression test (that fails without the fix).

This is related to #4013 but doesn't fix it.
This commit is contained in:
David Gilbertson
2026-01-27 10:11:27 +11:00
committed by GitHub
parent 159ff06281
commit 313ee3003b
3 changed files with 21 additions and 1 deletions

1
codex-rs/Cargo.lock generated
View File

@@ -2006,6 +2006,7 @@ dependencies = [
"chrono",
"codex-protocol",
"codex-utils-absolute-path",
"codex-utils-string",
"dirs-next",
"dunce",
"pretty_assertions",

View File

@@ -25,6 +25,7 @@ chrono = { version = "0.4.42", default-features = false, features = [
"std",
] }
codex-utils-absolute-path = { workspace = true }
codex-utils-string = { workspace = true }
dunce = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View File

@@ -4,6 +4,8 @@ use std::path::Path;
use std::path::PathBuf;
use std::sync::OnceLock;
use codex_utils_string::take_bytes_at_char_boundary;
const LOG_COMMAND_PREVIEW_LIMIT: usize = 200;
pub const LOG_FILE_NAME: &str = "sandbox.log";
@@ -22,7 +24,7 @@ fn preview(command: &[String]) -> String {
if joined.len() <= LOG_COMMAND_PREVIEW_LIMIT {
joined
} else {
joined[..LOG_COMMAND_PREVIEW_LIMIT].to_string()
take_bytes_at_char_boundary(&joined, LOG_COMMAND_PREVIEW_LIMIT).to_string()
}
}
@@ -72,3 +74,19 @@ pub fn log_note(msg: &str, base_dir: Option<&Path>) {
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
append_line(&format!("[{ts} {}] {}", exe_label(), msg), base_dir);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn preview_does_not_panic_on_utf8_boundary() {
// Place a 4-byte emoji such that naive (byte-based) truncation would split it.
let prefix = "x".repeat(LOG_COMMAND_PREVIEW_LIMIT - 1);
let command = vec![format!("{prefix}😀")];
let result = std::panic::catch_unwind(|| preview(&command));
assert!(result.is_ok());
let previewed = result.unwrap();
assert!(previewed.len() <= LOG_COMMAND_PREVIEW_LIMIT);
}
}