Compare commits

...

1 Commits

Author SHA1 Message Date
David Wiesen
b6b5ce9e53 fix(windows): avoid WindowsApps shell aliases in sandbox 2026-05-01 10:15:46 -07:00
2 changed files with 66 additions and 10 deletions

View File

@@ -162,6 +162,32 @@ fn file_exists(path: &PathBuf) -> Option<PathBuf> {
}
}
fn is_windowsapps_app_execution_alias(path: &std::path::Path) -> bool {
path.to_string_lossy()
.to_ascii_lowercase()
.contains(r#"\appdata\local\microsoft\windowsapps\"#)
}
fn first_existing_fallback_path(fallback_paths: &[&str]) -> Option<PathBuf> {
for path in fallback_paths {
if let Some(path) = file_exists(&PathBuf::from(path)) {
return Some(path);
}
}
None
}
fn prefer_real_windows_shell_path(path: PathBuf, fallback_paths: &[&str]) -> PathBuf {
if is_windowsapps_app_execution_alias(&path)
&& let Some(fallback) = first_existing_fallback_path(fallback_paths)
{
return fallback;
}
path
}
fn get_shell_path(
shell_type: ShellType,
provided_path: Option<&PathBuf>,
@@ -180,21 +206,17 @@ fn get_shell_path(
&& detect_shell_type(&default_shell_path) == Some(shell_type)
&& file_exists(&default_shell_path).is_some()
{
return Some(default_shell_path);
return Some(prefer_real_windows_shell_path(
default_shell_path,
fallback_paths,
));
}
if let Ok(path) = which::which(binary_name) {
return Some(path);
return Some(prefer_real_windows_shell_path(path, fallback_paths));
}
for path in fallback_paths {
//check exists
if let Some(path) = file_exists(&PathBuf::from(path)) {
return Some(path);
}
}
None
first_existing_fallback_path(fallback_paths)
}
const ZSH_FALLBACK_PATHS: &[&str] = &["/bin/zsh"];

View File

@@ -1,6 +1,7 @@
use super::*;
use std::path::PathBuf;
use std::process::Command;
use tempfile::tempdir;
#[test]
#[cfg(target_os = "macos")]
@@ -190,3 +191,36 @@ fn finds_powershell() {
assert!(shell_path.ends_with("pwsh.exe") || shell_path.ends_with("powershell.exe"));
}
#[test]
fn detects_windowsapps_app_execution_alias() {
assert!(is_windowsapps_app_execution_alias(&PathBuf::from(
r#"C:\Users\alice\AppData\Local\Microsoft\WindowsApps\pwsh.exe"#
)));
assert!(!is_windowsapps_app_execution_alias(&PathBuf::from(
r#"C:\Program Files\PowerShell\7\pwsh.exe"#
)));
}
#[test]
fn prefers_real_shell_binary_over_windowsapps_alias() {
let temp = tempdir().unwrap();
let fallback = temp.path().join("pwsh.exe");
std::fs::write(&fallback, b"").unwrap();
let selected = prefer_real_windows_shell_path(
PathBuf::from(r#"C:\Users\alice\AppData\Local\Microsoft\WindowsApps\pwsh.exe"#),
&[fallback.to_str().unwrap()],
);
assert_eq!(selected, fallback);
}
#[test]
fn keeps_windowsapps_alias_when_no_real_shell_exists() {
let alias = PathBuf::from(r#"C:\Users\alice\AppData\Local\Microsoft\WindowsApps\pwsh.exe"#);
let selected = prefer_real_windows_shell_path(alias.clone(), &[]);
assert_eq!(selected, alias);
}