Windows ACL 提权按 target 做 single-flight + 失败记忆,避免并发重复弹 UAC #498
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
背景
PR #492 的评审发现(高):Windows ACL 自动提权路径会并发、重复触发
Start-Process -Verb RunAs -Wait。前端已在该 PR 收口(提权类失败不重试、不驱动整表重查、用户主动操作前跳过),但闸门在调用方一侧,任何并发调用方都会各自启动一次提权。为什么必须按「目标」做 single-flight(并发去重)
windows_acl_repair_target(apps/ai-game-creator-shell/src-tauri/src/config.rs:2539-2567)对 Managed 作用域不是返回叶路径,而是从根往叶走、返回第一个读取被拒的祖先:⇒ 同一祖先下的多个项目会解析到同一个 repair target。而调用链上没有任何跨调用记忆(唯一闸门
attempted_targets是secure_windows_game_creator_path_for_current_user_with_auto_elevation_scoped内的局部 Vec,config.rs:2330-2352,函数返回即消失),于是:useRecentProjects上限 8)→ 同一 target 被并发启动 N 次powershell -Verb RunAs,用户看到叠在一起的 UAC 弹窗;-Wait没有超时(config.rs:2824),每个被拒/被忽略的弹窗都会长期占住一条线程。期望(按优先级)
(normalize(windows_acl_repair_target(path, scope)), scope)为 key。leader 执行提权修复,follower 等待并使用同一个结果(成功或错误都要复用,不能只做「跳过」)。调用方可能位于 blocking 线程(inspect_local_project_directory走spawn_blocking)或同步派发线程,所以原语要阻塞友好(std::sync::{Mutex, Condvar}的 leader/follower,而不是要求 async 的 tokio 原语)。powershellexit 1223)→ 冷却期内直接返回类型化错误、不再启动提权;成功 → 复用成功结果。冷却窗口与「用户主动操作可再试一次」的语义要和 PR #492 前端的跳过策略一致。AGC ACL 提权修复未成功(exit code Some(...)))。验收
关联
config.rs:2330-2352、config.rs:2539-2567、config.rs:2824、config.rs:910-1041)。/api/runtime/frontend-config、/api/llm/models、/api/profile/recharge-center走 WebView → Rust 的plugin:http(reqwest),与本地 ACL 提权不同层;只有「WebView 主线程 / IPC 回传」整体停摆时两者才会落在同一时间窗。判别方法记录在 issue #490 的采证探针里。Windows ACL 提权加进程级 per-target 冷却:避免任何调用方重复触发 UACto Windows ACL 提权按 target 做 single-flight + 失败记忆,避免并发重复弹 UAC