diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index cec9d56862e..95a6e3ad259 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -4803,7 +4803,6 @@ dependencies = [ name = "codex-utils-cargo-bin" version = "0.0.0" dependencies = [ - "assert_cmd", "runfiles", "thiserror 2.0.20", ] diff --git a/codex-rs/utils/cargo-bin/Cargo.toml b/codex-rs/utils/cargo-bin/Cargo.toml index a56e5758306..d7788d79c0a 100644 --- a/codex-rs/utils/cargo-bin/Cargo.toml +++ b/codex-rs/utils/cargo-bin/Cargo.toml @@ -8,7 +8,6 @@ license.workspace = true workspace = true [dependencies] -assert_cmd = { workspace = true } runfiles = { workspace = true } thiserror = { workspace = true } diff --git a/codex-rs/utils/cargo-bin/README.md b/codex-rs/utils/cargo-bin/README.md index 05af2f34bf0..7537ebdf493 100644 --- a/codex-rs/utils/cargo-bin/README.md +++ b/codex-rs/utils/cargo-bin/README.md @@ -9,8 +9,9 @@ behavior consistent in local and remote builds on all platforms. Bazel sets Function behavior: - `cargo_bin`: reads `CARGO_BIN_EXE_*` environment variables (set by Cargo or Bazel) and resolves them via the runfiles manifest when `RUNFILES_MANIFEST_FILE` - is present. When not under runfiles, it only accepts absolute paths from - `CARGO_BIN_EXE_*` and returns an error otherwise. + is present. Outside Bazel, it accepts absolute paths from `CARGO_BIN_EXE_*`, + then checks the current Cargo target directory for an already-built binary. + Missing binaries return `CargoBinError::NotFound` rather than panicking. - `find_resource!`: used by tests to locate fixtures. It chooses the Bazel runfiles resolution path when `RUNFILES_MANIFEST_FILE` is set, otherwise it falls back to a `CARGO_MANIFEST_DIR`-relative path for Cargo runs. diff --git a/codex-rs/utils/cargo-bin/src/lib.rs b/codex-rs/utils/cargo-bin/src/lib.rs index 2cb25a6b17d..881bba9aa12 100644 --- a/codex-rs/utils/cargo-bin/src/lib.rs +++ b/codex-rs/utils/cargo-bin/src/lib.rs @@ -35,7 +35,6 @@ pub enum CargoBinError { /// In `cargo test`, `CARGO_BIN_EXE_*` env vars are absolute. /// In `bazel test`, `CARGO_BIN_EXE_*` env vars are rlocationpaths, intended to be consumed by `rlocation`. /// This helper allows callers to transparently support both. -#[allow(deprecated)] pub fn cargo_bin(name: &str) -> Result { let env_keys = cargo_bin_env_keys(name); for key in &env_keys { @@ -43,28 +42,22 @@ pub fn cargo_bin(name: &str) -> Result { return resolve_bin_from_env(key, value); } } - match assert_cmd::Command::cargo_bin(name) { - Ok(cmd) => { - let mut path = PathBuf::from(cmd.get_program()); - if !path.is_absolute() { - path = std::env::current_dir() - .map_err(|source| CargoBinError::CurrentDir { source })? - .join(path); - } - if path.exists() { - Ok(path) - } else { - Err(CargoBinError::ResolvedPathDoesNotExist { - key: "assert_cmd::Command::cargo_bin".to_owned(), - path, - }) - } - } - Err(err) => Err(CargoBinError::NotFound { + + let mut fallback_path = + std::env::current_exe().map_err(|source| CargoBinError::CurrentExe { source })?; + fallback_path.pop(); + if fallback_path.ends_with("deps") { + fallback_path.pop(); + } + fallback_path.push(format!("{name}{}", std::env::consts::EXE_SUFFIX)); + if fallback_path.is_file() { + Ok(fallback_path) + } else { + Err(CargoBinError::NotFound { name: name.to_owned(), env_keys, - fallback: format!("assert_cmd fallback failed: {err}"), - }), + fallback: format!("target-directory fallback {fallback_path:?} does not exist"), + }) } } diff --git a/codex-rs/utils/cargo-bin/tests/cargo_bin.rs b/codex-rs/utils/cargo-bin/tests/cargo_bin.rs new file mode 100644 index 00000000000..6a5836954dc --- /dev/null +++ b/codex-rs/utils/cargo-bin/tests/cargo_bin.rs @@ -0,0 +1,48 @@ +use codex_utils_cargo_bin::CargoBinError; +use std::path::PathBuf; + +struct RemoveFileOnDrop(PathBuf); + +impl Drop for RemoveFileOnDrop { + fn drop(&mut self) { + let _ = std::fs::remove_file(&self.0); + } +} + +#[test] +fn missing_binary_returns_not_found_error() { + let missing_name = "codex-utils-cargo-bin-missing-test-binary"; + + let error = codex_utils_cargo_bin::cargo_bin(missing_name) + .expect_err("missing binary lookup should return an error"); + + assert!( + matches!(&error, CargoBinError::NotFound { name, .. } if name == missing_name), + "unexpected error: {error:?}" + ); +} + +#[test] +fn target_directory_fallback_finds_existing_binary() { + if codex_utils_cargo_bin::runfiles_available() { + return; + } + + let binary_name = format!("codex-utils-cargo-bin-fallback-test-{}", std::process::id()); + let mut fallback_path = std::env::current_exe().expect("test executable should be available"); + fallback_path.pop(); + if fallback_path.ends_with("deps") { + fallback_path.pop(); + } + fallback_path.push(format!("{binary_name}{}", std::env::consts::EXE_SUFFIX)); + std::fs::write(&fallback_path, []).expect("fallback test binary should be created"); + let _cleanup = RemoveFileOnDrop(fallback_path.clone()); + + let resolved = codex_utils_cargo_bin::cargo_bin(&binary_name) + .expect("target-directory fallback should resolve the test binary"); + + assert!( + resolved == fallback_path, + "expected {fallback_path:?}, got {resolved:?}" + ); +} diff --git a/upstream/convergence-guard.json b/upstream/convergence-guard.json index 82c639484d0..ed9a7a7f491 100644 --- a/upstream/convergence-guard.json +++ b/upstream/convergence-guard.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "repository": "openai/codex", - "ownershipBaseline": {"base": "b89ce9a2bcedcfddf3a48f387b7912d602d6d87c", "current": "0d05076a80ff5a2dbc5e73311396a080af118b12", "local": "8add494682f7c0674672e8dc5b38a4565cd7629b", "upstream": "4462b9deef211723b781b426f5e5d36a5777115f"}, + "ownershipBaseline": {"base": "b89ce9a2bcedcfddf3a48f387b7912d602d6d87c", "current": "81753998638d1deb183370c8dfda2bcdaaf23a85", "local": "8add494682f7c0674672e8dc5b38a4565cd7629b", "upstream": "4462b9deef211723b781b426f5e5d36a5777115f"}, "policy": {"guardedLanes": ["intentionally_owned", "red_manual_review"], "rule": "An owned path may not be absent from the candidate, and may not match the recorded upstream blob, without an explicit waiver.", "sources": {"current_tree": "Owned path in the candidate tree, so owned work created or restored after the baseline is guarded without hand-editing.", "ownership_baseline": "Owned path that already differed from upstream at the pre-anchor local baseline."}}, "summary": {"guardedLaneCounts": {"intentionally_owned": 446, "red_manual_review": 27}, "guardedPaths": 473, "guardedSourceCounts": {"current_tree": 198, "ownership_baseline": 275}}, "guardedPaths": [ @@ -457,7 +457,7 @@ {"baselineBlob": "e63b1a1152a7ace26aff0dba9d731112f5090044", "contracts": ["GOVERNANCE-1"], "lane": "intentionally_owned", "path": "upstream/README.md", "reason": "upstream convergence policy, evidence, and enforcement", "source": "current_tree", "upstreamBlob": null}, {"baselineBlob": "2c71fc065155f1717f54f2bdcea58537d6cc7712", "contracts": ["GOVERNANCE-1"], "lane": "intentionally_owned", "path": "upstream/convergence-contracts.md", "reason": "upstream convergence policy, evidence, and enforcement", "source": "current_tree", "upstreamBlob": null}, {"baselineBlob": "0b72481f41865505ab1e658c385ab1495f38e7dd", "contracts": ["GOVERNANCE-1"], "lane": "intentionally_owned", "path": "upstream/convergence-gates.json", "reason": "upstream convergence policy, evidence, and enforcement", "source": "current_tree", "upstreamBlob": null}, - {"baselineBlob": "8b091a1eb3cbbc7c14d3d39120433a95bbd1154b", "contracts": ["GOVERNANCE-1"], "lane": "intentionally_owned", "path": "upstream/convergence-guard.json", "reason": "upstream convergence policy, evidence, and enforcement", "source": "current_tree", "upstreamBlob": null}, + {"baselineBlob": "6bbdc7ca94054c5f86957d55ffa091fb8c246009", "contracts": ["GOVERNANCE-1"], "lane": "intentionally_owned", "path": "upstream/convergence-guard.json", "reason": "upstream convergence policy, evidence, and enforcement", "source": "current_tree", "upstreamBlob": null}, {"baselineBlob": "ccccfceeff6dc30fde1cdcadca634579b000b159", "contracts": ["GOVERNANCE-1"], "lane": "intentionally_owned", "path": "upstream/convergence-policy.json", "reason": "upstream convergence policy, evidence, and enforcement", "source": "current_tree", "upstreamBlob": null}, {"baselineBlob": "b7066513dca4a330546014704193c02ee2ff7cd9", "contracts": ["GOVERNANCE-1"], "lane": "intentionally_owned", "path": "upstream/convergence-waivers.json", "reason": "upstream convergence policy, evidence, and enforcement", "source": "current_tree", "upstreamBlob": null}, {"baselineBlob": "9860ec7791782b1723ea65ebba041232a6d50146", "contracts": ["GOVERNANCE-1"], "lane": "intentionally_owned", "path": "upstream/openai-codex/20dafe20-62fd4103/inventory.json", "reason": "upstream convergence policy, evidence, and enforcement", "source": "current_tree", "upstreamBlob": null},