Use a compatible PowerShell fallback for the Windows MXC sandbox (#49019)

## Why

Microsoft Store PowerShell cannot run under MXC. The existing fallback to an unpackaged PowerShell executable only applied to the elevated Windows sandbox.

## What changed

Extend local PowerShell fallback discovery to MXC in `unified_exec`, using the executor's Windows sandbox selection. Keep discovery local and automatic `-NoProfile` insertion specific to the elevated sandbox. Skip this preparation for non-Windows target paths.

## Testing

Extend command-preparation tests to cover MXC and add a Windows integration test that replaces a Store PowerShell path before launch, writes a file successfully, and verifies `windows_mxc` sandbox metadata.

GitOrigin-RevId: 6c581396525a8fec7e1fb538b3e63b0de2ddb926
This commit is contained in:
iceweasel-oai
2026-09-28 15:58:17 +00:00
committed by copyberry
parent 69f7140559
commit 4fd5745e84
5 changed files with 211 additions and 71 deletions
+14 -14
View File
@@ -132,7 +132,7 @@ fn file_exists(path: &std::path::Path) -> Option<PathBuf> {
}
}
// Store PowerShell can be inaccessible to the elevated sandbox account;
// Store PowerShell cannot run under MXC and can be inaccessible to the elevated sandbox account;
// WindowsApps also contains valid Codex frameworks.
fn is_inaccessible_windows_apps_powershell_path(path: &std::path::Path) -> bool {
path.as_os_str()
@@ -156,7 +156,7 @@ fn targets_inaccessible_windows_apps_powershell(path: &std::path::Path) -> bool
.is_some_and(|resolved| is_inaccessible_windows_apps_powershell_path(&resolved))
}
fn is_elevated_sandbox_compatible_powershell_path(path: &std::path::Path) -> bool {
fn is_windows_sandbox_compatible_powershell_path(path: &std::path::Path) -> bool {
if !path
.extension()
.is_some_and(|extension| extension.eq_ignore_ascii_case("exe"))
@@ -167,19 +167,19 @@ fn is_elevated_sandbox_compatible_powershell_path(path: &std::path::Path) -> boo
!targets_inaccessible_windows_apps_powershell(path)
}
fn get_elevated_sandbox_compatible_powershell_path(
fn get_windows_sandbox_compatible_powershell_path(
binary_name: &str,
fallback_paths: &[&str],
) -> Option<PathBuf> {
if let Ok(mut paths) = which::which_all(binary_name)
&& let Some(path) = paths.find(|path| is_elevated_sandbox_compatible_powershell_path(path))
&& let Some(path) = paths.find(|path| is_windows_sandbox_compatible_powershell_path(path))
{
return Some(path);
}
for path in fallback_paths {
let path = std::path::Path::new(path);
if is_elevated_sandbox_compatible_powershell_path(path)
if is_windows_sandbox_compatible_powershell_path(path)
&& let Some(path) = file_exists(path)
{
return Some(path);
@@ -281,21 +281,21 @@ fn get_powershell_shell() -> Option<DetectedShell> {
}
/// Returns a replacement only when shell_path targets Store PowerShell and
/// an elevated sandbox-compatible PowerShell executable can be discovered.
/// an unpackaged PowerShell executable can be discovered.
///
/// The caller owns the elevated-sandbox policy decision. Normal shell discovery
/// The caller decides whether the sandbox backend requires a fallback. Normal shell discovery
/// intentionally keeps the user's ordered PATH selection unchanged.
pub fn fallback_powershell_shell_for_elevated_windows_sandbox(
pub fn fallback_powershell_shell_for_windows_sandbox(
shell_path: &std::path::Path,
) -> Option<DetectedShell> {
if !cfg!(windows) || !targets_inaccessible_windows_apps_powershell(shell_path) {
return None;
}
let shell_path = get_elevated_sandbox_compatible_powershell_path("pwsh", PWSH_FALLBACK_PATHS)
let shell_path = get_windows_sandbox_compatible_powershell_path("pwsh", PWSH_FALLBACK_PATHS)
.or_else(|| {
get_elevated_sandbox_compatible_powershell_path("powershell", POWERSHELL_FALLBACK_PATHS)
})?;
get_windows_sandbox_compatible_powershell_path("powershell", POWERSHELL_FALLBACK_PATHS)
})?;
Some(DetectedShell {
shell_type: ShellType::PowerShell,
@@ -385,7 +385,7 @@ mod tests {
r"C:\PROGRAM FILES\WINDOWSAPPS\MICROSOFT.POWERSHELL\PWSH.EXE",
r"C:\portable\pwsh.cmd",
] {
assert!(!is_elevated_sandbox_compatible_powershell_path(
assert!(!is_windows_sandbox_compatible_powershell_path(
std::path::Path::new(path)
));
}
@@ -400,7 +400,7 @@ mod tests {
r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe",
r"C:\portable\NotWindowsApps\pwsh.EXE",
] {
assert!(is_elevated_sandbox_compatible_powershell_path(
assert!(is_windows_sandbox_compatible_powershell_path(
std::path::Path::new(path)
));
}
@@ -421,7 +421,7 @@ mod tests {
PathBuf::from(r"C:\Program Files\PowerShell\7\pwsh.exe"),
]
.into_iter()
.find(|path| is_elevated_sandbox_compatible_powershell_path(path));
.find(|path| is_windows_sandbox_compatible_powershell_path(path));
assert_eq!(found, Some(portable));
}