修复仓库回退配置模板被读取通道私有化 ACL 锁定 #321
Reference in New Issue
Block a user
Delete Branch "fix/config_lock"
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?
问题
Windows 上
apps/ai-game-creator-shell/game-creator.config.json反复被"加锁":DACL 被剥成只剩一个陌生 SID,开发 agent 无法修改,cargo 因include_str!读不到文件无法编译;手动解锁后过一段时间又被锁。根因
无 AppHandle 的开发 CLI(
llm-status、agent-run、agc:test:chat等)经game_creator_config_paths()从 CWD /current_exe向上回溯 8 级探测到 worktree 内 git 跟踪的模板文件后,读取走了为 AppData 私密凭据设计的私有通道(open_project_private_regular_file→prepare_game_creator_private_path_for_read)。该函数名为 "for read",在 Windows 上却无条件把目标 DACL 收紧为"仅当前进程用户、禁止继承"。沙箱 agent 是其 checkout 文件的 owner,校验通过后被静默私有化,其他账号全部 Access Denied。修复
read_game_creator_config_file按路径归属分流:game_creator_runtime_config_dir()(AppData 托管目录)内的真实凭据:维持私有加固读取(设计本意);open_project_snapshot_regular_file非变异快照通道,读取绝不修改 owner / DACL。符合
open_project_private_regular_file注释中"非用户明确选择的文件用 snapshot 读"的既有原则。验证
fallback_template_read_stays_on_snapshot_channel_outside_runtime_dir与runtime_config_read_stays_on_private_channel_inside_runtime_dir通过;tests::configuration::全部 43 个测试通过;node scripts/check-config.mjs通过;npm run check:encoding与git diff --check通过;docs/project-memory/shared-memory/pitfalls.md。审查结论:修复方向正确,分流逻辑在当前所有真实调用路径下自洽,无阻塞性问题。
已验证:
tests::configuration::全部 43 个测试通过npm run check:encoding(4331 文件)与git diff --check通过pitfalls.md已按仓库规范同步更新game_creator_config_paths()、writable_game_creator_config_path()、overlays)均派生自同一game_creator_runtime_config_dir()存储值,starts_with分类在 GUI / CLI 两种模式下都与路径来源一致;open_project_snapshot_regular_file为只读打开 + 句柄身份复核,无 DACL 副作用确认的有意行为变更:CLI 模式(runtime dir 为
None)下仓库旁回退模板和game-creator.config.local.json的读取不再做 owner/DACL 校验与加固,与validate_game_creator_config_file_entry注释“读取必须保持只读,ACL 加固发生在创建或替换时”一致;写路径(write_game_creator_config_atomically)仍会加固,非安全回退。另已核实attempt_elevated_windows_acl_repair的触发前提是路径在 Managed scope 白名单内,普通 worktree 模板不在其内,修复是完整的。两条轻微意见见行内评论。
@@ -3644,0 +3646,4 @@/// that can be git-tracked; privatizing one on read silently locks the/// worktree template to whichever account happened to run the dev CLI, so/// they must go through the non-mutating snapshot channel instead.pub(crate) fn game_creator_config_path_is_runtime_managed(path: &Path) -> bool {(轻微,提示,本 PR 无需处理)
starts_with分类依赖传入路径与存储 runtime dir 的前缀一致性。存储值是 canonicalize 后的路径(Windows 上带\\?\前缀),当前所有调用方的路径都从该存储值直接join派生,所以一致;但若未来有新调用方传入未经同一来源构造的等价路径(大小写不同、8.3 短名、经 junction 的路径)指向 runtime dir 内的真实凭据文件,starts_with会失配,读取静默落到 snapshot 通道并跳过 owner 校验。后续若给read_game_creator_config_file增加外部传入路径的调用点,应先 canonicalize 再分类。@@ -1187,0 +1197,4 @@.expect("write fallback template");let _guard = clear_test_runtime_config_dir();// 仓库旁边的回退模板是共享输入,读取绝不能走会收紧 owner/DACL 的私有通道。(轻微)这个分类断言是平凡的:
clear_test_runtime_config_dir()把 runtime dir 置为None后,game_creator_config_path_is_runtime_managed内部的Option::is_some_and对任何路径都返回false,assert!(!...)恒真,不依赖模板路径本身。同时读取成功也无法证明走了 snapshot 通道——Windows 测试环境下私有通道对 temp 文件加固 DACL 同样会成功返回内容。因此若有人把None分支改回私有通道,此测试不会失败,与测试名 "stays_on_snapshot_channel" 的承诺不符。建议:把 runtime dir 设为一个与模板无关的另一目录(
use_test_runtime_config_dir(其他路径)),再断言模板不属于 managed——这样断言才真正覆盖“按路径归属”而非“按全局开关”的分类逻辑。当前实现下改成这样后read_game_creator_config_file(&template)依然走 snapshot 分支,行为不变,测试仍然有效。已处理评审意见(commit
89447ed43):clear_test_runtime_config_dir辅助。两个新增测试与tests::configuration::全部 43 个测试通过,cargo fmt --check通过。