diff --git a/apps/ai-game-creator-shell/src-tauri/src/config.rs b/apps/ai-game-creator-shell/src-tauri/src/config.rs index 3240832c2..1dd22bc08 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/config.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/config.rs @@ -27,6 +27,7 @@ fn user_selected_path_grants() -> &'static Mutex Option { + let path = normalize_windows_policy_path(path); if !path.is_absolute() || path .components() @@ -42,6 +43,15 @@ fn normalize_user_selected_path_key(path: &Path) -> Option { ) } +#[cfg(windows)] +fn normalize_windows_policy_path(path: &Path) -> PathBuf { + let value = path.to_string_lossy(); + if let Some(rest) = value.strip_prefix(r"\\?\UNC\") { + return PathBuf::from(format!(r"\\{rest}")); + } + PathBuf::from(value.strip_prefix(r"\\?\").unwrap_or(&value)) +} + #[cfg(windows)] pub(crate) fn register_game_creator_user_selected_path(path: &Path, is_directory: bool) { let Some(key) = normalize_user_selected_path_key(path) else { @@ -838,6 +848,7 @@ pub(crate) fn validate_game_creator_private_path_ancestors( /// separate, explicit user-selected scope below covers native picker/project /// root results, including projects stored outside the current profile. fn game_creator_private_path_allows_auto_elevation(path: &Path) -> bool { + let path = normalize_windows_policy_path(path); if !path.is_absolute() || path .components() @@ -846,7 +857,10 @@ fn game_creator_private_path_allows_auto_elevation(path: &Path) -> bool { return false; } - let starts_with_path = |root: &Path| path == root || path.starts_with(root); + let starts_with_path = |root: &Path| { + let root = normalize_windows_policy_path(root); + path == root || path.starts_with(root) + }; if game_creator_runtime_config_dir() .as_deref() .is_some_and(starts_with_path) @@ -1056,6 +1070,7 @@ pub(crate) fn parse_windows_acl_repair_scope(value: &str) -> Result WindowsAclRepairScope { + let path = normalize_windows_policy_path(path); let is_builtin_root = |root: PathBuf| path == root || path.starts_with(root); if let Some(home) = std::env::var_os("USERPROFILE") .or_else(|| std::env::var_os("HOME")) @@ -4506,6 +4521,23 @@ mod private_path_elevation_policy_tests { ); } + #[cfg(windows)] + #[test] + fn verbatim_packaged_appdata_path_keeps_managed_repair_scope() { + let root = std::env::var_os("LOCALAPPDATA") + .or_else(|| std::env::var_os("APPDATA")) + .map(PathBuf::from) + .expect("local appdata"); + let packaged = root.join("world.genarrative.ai-game-creator"); + let verbatim = PathBuf::from(format!(r"\\?\{}", packaged.display())); + + assert!(game_creator_private_path_allows_auto_elevation(&verbatim)); + assert_eq!( + game_creator_runtime_config_repair_scope(&verbatim), + WindowsAclRepairScope::Managed + ); + } + #[cfg(windows)] #[test] fn picker_grant_is_required_and_directory_grant_covers_descendants() {