Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions scripts/diagnostics/windows-version-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ authentication values, and an ephemeral loopback listener. It is configured
with no real credentials and one unavailable loopback provider. Other network
egress is not blocked or audited.

The controller captures the original home before replacing the child
environment and arms the test-home guard (`OCX_TEST_HOME_GUARD`,
`OCX_REAL_HOME`) with that protected identity. Rewriting fixture `HOME` and
`USERPROFILE` does not redefine the protected OpenCodex and Codex homes.
The module contracts exercise the same setup with a synthetic original home.

```powershell
cargo test --locked --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --test async_contracts -- --test-threads=4
cargo clippy --locked --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --all-targets -- -D warnings
Expand Down
12 changes: 10 additions & 2 deletions scripts/diagnostics/windows-version-control/src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,12 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
{
return Err("all paths must be absolute".into());
}
let original_home = env::var_os("OCX_REAL_HOME")
.or_else(|| env::var_os("USERPROFILE"))
.or_else(|| env::var_os("HOME"))
.map(PathBuf::from)
.filter(|path| path.is_absolute())
.ok_or("missing absolute original home")?;
fs::create_dir(&root)?;
let home = root.join("opencodex");
let codex = root.join("codex");
Expand Down Expand Up @@ -346,8 +352,10 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
)?;
let system = env::var_os("SystemRoot").ok_or("missing SystemRoot")?;
let path = env::join_paths([bin.clone(), Path::new(&system).join("System32")])?;
let child = Command::new(&args[0])
.env_clear()
let mut command = Command::new(&args[0]);
command.env_clear();
crate::fixture_env::arm_test_home_guard(&mut command, &original_home)?;
let child = command
.env("SystemRoot", &system)
.env("WINDIR", &system)
.env("PATH", path)
Expand Down
15 changes: 15 additions & 0 deletions scripts/diagnostics/windows-version-control/src/fixture_env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use std::{io, path::Path, process::Command};

/// Preserve the guard's protected home across fixture environment replacement.
pub fn arm_test_home_guard(command: &mut Command, original_home: &Path) -> io::Result<()> {
if !original_home.is_absolute() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"the original home must be absolute",
));
}
command
.env("OCX_TEST_HOME_GUARD", "1")
.env("OCX_REAL_HOME", original_home);
Ok(())
}
2 changes: 2 additions & 0 deletions scripts/diagnostics/windows-version-control/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#[cfg(windows)]
mod control;
#[cfg(windows)]
mod fixture_env;

fn main() {
#[cfg(windows)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use serde_json::Value;
use std::{env, fs, path::PathBuf, process::Command};

#[path = "../src/fixture_env.rs"]
mod fixture_env;

#[test]
fn eager_eof_releases_upstream_abort_listeners_and_reader() {
let result = contract(
Expand Down Expand Up @@ -251,6 +254,7 @@ console.log('@@catalog-contract@@'+JSON.stringify(answer));
);
let mut command = hidden(Command::new(bun));
command.env_clear();
fixture_env::arm_test_home_guard(&mut command, &root.join("original-home")).unwrap();
if let Some(system) = env::var_os("SystemRoot") {
command.env("SystemRoot", &system).env("WINDIR", &system);
}
Expand Down Expand Up @@ -625,3 +629,38 @@ return answers;
assert_eq!(answer["reaped"], true);
}
}

#[test]
fn home_guard_survives_fixture_home_replacement() {
let result = contract(
"home-guard",
r#"
const guard = await import(pathToFileURL(join(process.env.CONTRACT_REPO, 'src/lib/test-home-guard.ts')).href);
const original = process.env.OCX_REAL_HOME;
let homeRefused = false, codexRefused = false;
try { guard.assertNotRealHomeUnderTest(join(original, '.opencodex')); } catch { homeRefused = true; }
try { guard.assertNotRealCodexHomeUnderTest(join(original, '.codex')); } catch { codexRefused = true; }
guard.assertNotRealHomeUnderTest(root);
guard.assertNotRealCodexHomeUnderTest(root);
return {
armed: process.env.OCX_TEST_HOME_GUARD === '1',
rewritten: process.env.HOME !== original && process.env.USERPROFILE !== original,
homeRefused, codexRefused, fixtureAllowed: true
};
"#,
);
assert_eq!(result["armed"], true);
assert_eq!(result["rewritten"], true);
assert_eq!(result["homeRefused"], true);
assert_eq!(result["codexRefused"], true);
assert_eq!(result["fixtureAllowed"], true);
}

#[test]
fn home_guard_requires_an_absolute_protected_home() {
let mut command = Command::new("unused-fixture");
let error =
fixture_env::arm_test_home_guard(&mut command, std::path::Path::new("relative-home"))
.unwrap_err();
assert_eq!(error.kind(), std::io::ErrorKind::InvalidInput);
}
Loading