use a version-specific suffix for command runner binary in .sandbox-bin (#19180)

we copy `codex-command-runner.exe` into `CODEX_HOME/.sandbox-bin/` so
that it can be executed by the sandbox user.
We also detect if that version is stale and copy a new one in if so.

This can fail when you are running multiple versions of the app - the
file in `.sandbox-bin` can look stale because it comes from another app
build.

This change allows us to have multiple versions in there for different
CLI versions, and it fallsback to a `size+mtime` hash in the filename
for dev builds that don't report a real CLI version.
This commit is contained in:
iceweasel-oai
2026-04-23 13:16:26 -07:00
committed by GitHub
Unverified
parent 0d6a90cd6b
commit d169bb541e
@@ -8,11 +8,13 @@ use std::path::Path;
use std::path::PathBuf;
use std::sync::Mutex;
use std::sync::OnceLock;
use std::time::UNIX_EPOCH;
use tempfile::NamedTempFile;
use crate::logging::log_note;
use crate::sandbox_bin_dir;
const DEV_BUILD_VERSION_SENTINEL: &str = "0.0.0";
const RESOURCES_DIRNAME: &str = "codex-resources";
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
@@ -134,7 +136,7 @@ pub(crate) fn copy_helper_if_needed(
}
let source = sibling_source_path(kind)?;
let destination = helper_bin_dir(codex_home).join(kind.file_name());
let destination = helper_destination_for_source(kind, codex_home, &source)?;
log_note(
&format!(
"helper copy: validating {} source={} destination={}",
@@ -197,6 +199,56 @@ fn source_path_for_exe(exe: &Path, file_name: &str) -> Option<PathBuf> {
resource_candidate.exists().then_some(resource_candidate)
}
fn helper_destination_for_source(
kind: HelperExecutable,
codex_home: &Path,
source: &Path,
) -> Result<PathBuf> {
let suffix = helper_version_suffix(source)?;
let file_name = materialized_file_name(kind, &suffix);
Ok(helper_bin_dir(codex_home).join(file_name))
}
fn materialized_file_name(kind: HelperExecutable, suffix: &str) -> String {
let source_name = kind.file_name();
let path = Path::new(source_name);
let stem = path
.file_stem()
.and_then(|stem| stem.to_str())
.unwrap_or(source_name);
let extension = path
.extension()
.and_then(|ext| ext.to_str())
.map(|ext| format!(".{ext}"))
.unwrap_or_default();
format!("{stem}-{suffix}{extension}")
}
fn helper_version_suffix(source: &Path) -> Result<String> {
let version = env!("CARGO_PKG_VERSION");
if version == DEV_BUILD_VERSION_SENTINEL {
dev_build_suffix(source)
} else {
Ok(version.to_string())
}
}
fn dev_build_suffix(source: &Path) -> Result<String> {
let metadata = fs::metadata(source)
.with_context(|| format!("read helper source metadata {}", source.display()))?;
let modified = metadata
.modified()
.with_context(|| format!("read helper source mtime {}", source.display()))?;
let duration = modified
.duration_since(UNIX_EPOCH)
.with_context(|| format!("convert helper source mtime {}", source.display()))?;
Ok(format!(
"{}-{:x}",
metadata.len(),
duration.as_secs(),
))
}
fn copy_from_source_if_needed(source: &Path, destination: &Path) -> Result<CopyOutcome> {
if destination_is_fresh(source, destination)? {
return Ok(CopyOutcome::Reused);
@@ -298,8 +350,13 @@ fn destination_is_fresh(source: &Path, destination: &Path) -> Result<bool> {
mod tests {
use super::copy_from_source_if_needed;
use super::CopyOutcome;
use super::dev_build_suffix;
use super::destination_is_fresh;
use super::helper_bin_dir;
use super::helper_version_suffix;
use super::materialized_file_name;
use super::HelperExecutable;
use super::DEV_BUILD_VERSION_SENTINEL;
use super::RESOURCES_DIRNAME;
use super::source_path_for_exe;
use pretty_assertions::assert_eq;
@@ -370,8 +427,10 @@ mod tests {
let source_dir = tmp.path().join("sibling-source");
fs::create_dir_all(&source_dir).expect("create source dir");
let runner_source = source_dir.join("codex-command-runner.exe");
let runner_destination = helper_bin_dir(&codex_home).join("codex-command-runner.exe");
fs::write(&runner_source, b"runner").expect("runner");
let runner_suffix = helper_version_suffix(&runner_source).expect("runner suffix");
let runner_destination = helper_bin_dir(&codex_home)
.join(materialized_file_name(HelperExecutable::CommandRunner, &runner_suffix));
let runner_outcome =
copy_from_source_if_needed(&runner_source, &runner_destination).expect("runner copy");
@@ -418,4 +477,25 @@ mod tests {
assert_eq!(resolved, sibling_helper);
}
#[test]
fn helper_version_suffix_uses_cli_version_or_dev_build_metadata() {
let tmp = TempDir::new().expect("tempdir");
let source = tmp.path().join("source.exe");
fs::write(&source, b"runner-v1").expect("write source");
let suffix = helper_version_suffix(&source).expect("suffix");
if env!("CARGO_PKG_VERSION") == DEV_BUILD_VERSION_SENTINEL {
assert_eq!(suffix, dev_build_suffix(&source).expect("dev build suffix"));
} else {
assert_eq!(suffix, env!("CARGO_PKG_VERSION"));
}
}
#[test]
fn materialized_file_name_adds_suffix_before_extension() {
let file_name = materialized_file_name(HelperExecutable::CommandRunner, "test-suffix");
assert_eq!(file_name, "codex-command-runner-test-suffix.exe");
}
}