Fix Windows Bazel app-server trust tests (#16711)

## Why

Extracted from [#16528](https://github.com/openai/codex/pull/16528) so
the Windows Bazel app-server test failures can be reviewed independently
from the rest of that PR.

This PR targets:

-
`suite::v2::thread_shell_command::thread_shell_command_runs_as_standalone_turn_and_persists_history`
-
`suite::v2::thread_start::thread_start_with_elevated_sandbox_trusts_project_and_followup_loads_project_config`
-
`suite::v2::thread_start::thread_start_with_nested_git_cwd_trusts_repo_root`

There were two Windows-specific assumptions baked into those tests and
the underlying trust lookup:

- project trust keys were persisted and looked up using raw path
strings, but Bazel's Windows test environment can surface canonicalized
paths with `\\?\` / UNC prefixes or normalized symlink/junction targets,
so follow-up `thread/start` requests no longer matched the project entry
that had just been written
- `item/commandExecution/outputDelta` assertions compared exact trailing
line endings even though shell output chunk boundaries and CRLF handling
can differ on Windows, and Bazel made that timing-sensitive mismatch
visible

There was also one behavior bug separate from the assertion cleanup:
`thread/start` decided whether to persist trust from the final resolved
sandbox policy, but on Windows an explicit `workspace-write` request may
be downgraded to `read-only`. That incorrectly skipped writing trust
even though the request had asked to elevate the project, so the new
logic also keys off the requested sandbox mode.

## What

- Canonicalize project trust keys when persisting/loading `[projects]`
entries, while still accepting legacy raw keys for existing configs.
- Persist project trust when `thread/start` explicitly requests
`workspace-write` or `danger-full-access`, even if the resolved policy
is later downgraded on Windows.
- Make the Windows app-server tests compare persisted trust paths and
command output deltas in a path/newline-normalized way.

## Verification

- Existing app-server v2 tests cover the three failing Windows Bazel
cases above.
This commit is contained in:
Michael Bolin
2026-04-03 14:41:25 -07:00
committed by GitHub
parent 567d2603b8
commit a70aee1a1e
5 changed files with 77 additions and 24 deletions

View File

@@ -95,7 +95,10 @@ async fn thread_shell_command_runs_as_standalone_turn_and_persists_history() ->
assert_eq!(status, &CommandExecutionStatus::InProgress);
let delta = wait_for_command_execution_output_delta(&mut mcp, &command_id).await?;
assert_eq!(delta.delta, expected_output);
assert_eq!(
delta.delta.trim_end_matches(['\r', '\n']),
expected_output.trim_end_matches(['\r', '\n'])
);
let completed = wait_for_command_execution_completed(&mut mcp, Some(&command_id)).await?;
let ThreadItem::CommandExecution {

View File

@@ -644,7 +644,7 @@ model_reasoning_effort = "high"
let config_toml = std::fs::read_to_string(codex_home.path().join("config.toml"))?;
let trusted_root = resolve_root_git_project_for_trust(workspace.path())
.unwrap_or_else(|| workspace.path().to_path_buf());
assert!(config_toml.contains(&trusted_root.display().to_string()));
assert!(config_toml.contains(&persisted_trust_path(&trusted_root)));
assert!(config_toml.contains("trust_level = \"trusted\""));
Ok(())
@@ -681,8 +681,8 @@ async fn thread_start_with_nested_git_cwd_trusts_repo_root() -> Result<()> {
let config_toml = std::fs::read_to_string(codex_home.path().join("config.toml"))?;
let trusted_root =
resolve_root_git_project_for_trust(&nested).expect("git root should resolve");
assert!(config_toml.contains(&trusted_root.display().to_string()));
assert!(!config_toml.contains(&nested.display().to_string()));
assert!(config_toml.contains(&persisted_trust_path(&trusted_root)));
assert!(!config_toml.contains(&persisted_trust_path(&nested)));
Ok(())
}
@@ -776,6 +776,21 @@ fn create_config_toml_without_approval_policy(
)
}
fn persisted_trust_path(project_path: &Path) -> String {
let project_path =
std::fs::canonicalize(project_path).unwrap_or_else(|_| project_path.to_path_buf());
let project_path = project_path.display().to_string();
if let Some(project_path) = project_path.strip_prefix(r"\\?\UNC\") {
return format!(r"\\{project_path}");
}
project_path
.strip_prefix(r"\\?\")
.unwrap_or(&project_path)
.to_string()
}
fn create_config_toml_with_optional_approval_policy(
codex_home: &Path,
server_uri: &str,