From 4bf6c50a563115627ab4fa4d3d66971613b7607d Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Thu, 20 Aug 2026 14:11:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DAGC=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E8=80=85=E5=87=AD=E6=8D=AE=E7=9B=AE=E5=BD=95=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 允许客户端自动收紧当前用户持有目录的继承 ACL 保留 foreign owner 与异常路径的失败关闭边界 补充 Windows 回归测试并同步实施决策文档 --- .../src-tauri/src/assets.rs | 34 +++++++++++++++++-- ...计划】AGC直连Codex Runtime迁移-2026-08-15.md | 2 +- .../shared-memory/decision-log.md | 6 ++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/assets.rs b/apps/ai-game-creator-shell/src-tauri/src/assets.rs index a7097a6ce..e6cc8ef2b 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/assets.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/assets.rs @@ -189,8 +189,9 @@ fn ensure_plain_private_external_editor_directory( } /// Prepares the exact private directory before a one-time remote developer key -/// is requested. Existing directories are verified, not adopted; only the -/// directory created by this invocation may have its Windows owner initialized. +/// is requested. Existing directories must already belong to the current user, +/// but their DACL may be tightened locally; only a directory created by this +/// invocation may have its Windows owner initialized. fn prepare_private_external_editor_api_credentials_parent_dir_at( path: &Path, ) -> Result<(), String> { @@ -206,7 +207,7 @@ fn prepare_private_external_editor_api_credentials_parent_dir_at( if parent_created { initialize_windows_game_creator_directory_owner_for_current_user(parent)?; } else { - secure_windows_game_creator_path_for_current_user(parent, true, false)?; + secure_windows_game_creator_path_for_current_user(parent, true, true)?; } #[cfg(unix)] if parent_created { @@ -1737,6 +1738,33 @@ mod tests { .expect("new credential directory must be owned by TokenUser"); } + #[cfg(windows)] + #[test] + fn existing_current_user_credential_directory_is_tightened_before_remote_creation() { + let root = tempfile::tempdir().expect("temp dir"); + let parent = root.path().join("config").join("genarrative"); + fs::create_dir_all(&parent).expect("create existing credential directory"); + initialize_windows_game_creator_directory_owner_for_current_user(&parent) + .expect("initialize current-user owner before inherited ACL fixture"); + + let status = std::process::Command::new("icacls.exe") + .arg(&parent) + .arg("/inheritance:e") + .status() + .expect("run inherited ACL fixture command"); + assert!(status.success(), "enable inherited ACL fixture"); + assert!( + secure_windows_game_creator_path_for_current_user(&parent, true, false).is_err(), + "fixture must reproduce the inherited ACL rejection" + ); + + let path = parent.join("external-editor-api-test.json"); + prepare_private_external_editor_api_credentials_parent_dir_at(&path) + .expect("current-user directory should be tightened locally before remote creation"); + secure_windows_game_creator_path_for_current_user(&parent, true, false) + .expect("prepared existing directory must be private"); + } + #[tokio::test] async fn direct_runtime_private_credentials_force_external_v1_routes_without_session_copy() { let credentials = ExternalEditorApiCredentials { diff --git a/docs/project-memory/plans/【实施计划】AGC直连Codex Runtime迁移-2026-08-15.md b/docs/project-memory/plans/【实施计划】AGC直连Codex Runtime迁移-2026-08-15.md index d205aa1cc..4e871f892 100644 --- a/docs/project-memory/plans/【实施计划】AGC直连Codex Runtime迁移-2026-08-15.md +++ b/docs/project-memory/plans/【实施计划】AGC直连Codex Runtime迁移-2026-08-15.md @@ -241,7 +241,7 @@ 首次真实客户端验收表明,失败不是 GUI 登录态未同步:首次本机开发者凭据创建已经拿到远端响应,但 Windows 新建的私有目录 owner 是 `Administrators`,随后 TokenUser 私有 DACL 校验拒绝落盘。一次性显示的远端凭据无法恢复,旧顺序会留下孤儿凭据,因此不能用刷新登录态或自动重放掩盖。 -1. 缺失本机开发者凭据时,客户端必须先准备并验证精确的私有存储目录,再请求远端创建凭据。仅当该精确目录由当前调用以原子创建成功时,才允许初始化 owner 和私有 DACL 为当前 TokenUser;已有目录一律按严格 owner/DACL 校验,owner 不匹配时失败关闭,不自动接管、改 ACL、覆盖或删除。 +1. 缺失本机开发者凭据时,客户端必须先准备并验证精确的私有存储目录,再请求远端创建凭据。仅当该精确目录由当前调用以原子创建成功时,才允许初始化 owner 为当前 TokenUser;已有目录必须先严格核对 owner,owner 匹配当前 TokenUser 时由客户端自动收紧为禁止继承且仅当前用户 Full Control,owner 不匹配时仍失败关闭,不自动接管、改 ACL、覆盖或删除。 2. 若本机目录预检失败,客户端返回稳定的“本机开发者凭据存储目录未安全初始化;未创建远端凭据”分类,不请求远端创建接口、不发起美术生成、不写 operation 或账本,也不刷新登录态或自动重试。 3. 远端响应后原子写入仍可能因并发或磁盘故障失败;该极窄路径必须单独分类为“凭据已创建但未能安全保存”,提示用户在账户开发者凭据页面撤销后再试,不能自动创建第二把凭据。诊断和正式 UI 只展示上述安全摘要与恢复建议,不包含 access token、开发者凭据、响应正文、绝对路径或签名 URL。 4. 验收先在当前失败项目上恢复:对遗留的空且 owner 不匹配目录做可恢复隔离后,再复用同一项目发送“继续完成此前三消游戏”。成功标准包括本机私钥存在但不读取其内容、平台素材与版本登记完成、desktop/mobile Chromium 试玩证据和隔离进程恢复;此前已创建但无法恢复的远端孤儿凭据作为明确剩余风险,绝不自动撤销。 diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 88ba1980e..80a79b78a 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -14271,3 +14271,9 @@ - 验证:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml canvas_generation_tests:: -- --test-threads=1`。 - 2026-08-19 追加:同一默认认证切换也覆盖资源编辑和 autonomous main-loop fixture。`resource_editor` 的 External Editor 视频提交/轮询/服务身份恢复测试同样使用 task-local 凭据;平台账号语义测试使用隔离测试会话。main-loop 的视觉任务配置测试不再通过旧 `editorApi` 文件伪造登录态。所有 loopback listener 在 accept 时设有 5 秒 deadline,并把 accepted stream 恢复为 blocking,避免 Windows `WouldBlock(10035)` 或请求未发出时无限等待。 - 定向验证:`project::asset_canvas::generation::tests::` 14/14、`project::resource_editor::tests::` 36/36、`agent::runtime_driver::main_loop_tests::` 48/48、`agent::runtime_protocol::autonomous_completion_contract_tests::` 107/107 通过。此前一次 Windows 全量 Native Rust 为 1811 passed、108 failed、15 ignored;失败集合仍包含 Provider/mock 调度与既有专业链断言。HEAD 基线独立复现 `tests::project::generate_platform_art_asset_downloads_and_registers_external_image` 的同一登录态缺失,故不能把全量结果伪报为本次 fixture 修复引入;本次新增认证/accept deadline 相关用例均已隔离通过,最后两个 autonomous completion fixture 的认证迁移已单独通过,完整套件未在该两行测试改动后重新执行。 + +## 2026-08-20 AGC 本机开发者凭据目录 ACL 自动收紧 + +- 缺失当前服务器对应的本机开发者凭据时,客户端仍必须在请求远端创建 Key 前完成私有目录准备。既有 `~/.config/genarrative` 若 owner 已严格匹配当前进程 `TokenUser`,客户端自动把 DACL 收紧为禁止继承且仅当前用户 Full Control,用户不再需要手工执行 PowerShell ACL 修复。 +- 自动收紧不等于接管:owner 不匹配、链接、reparse point、非目录或无法安全写入 DACL 时继续在远端请求前失败关闭;客户端不得删除、移动、覆盖或读取旧凭据内容,也不得因收紧失败自动创建远端 Key。 +- Windows 回归测试必须构造“owner 为当前用户但仍继承 ACL”的既有目录,先证明严格校验失败,再通过正式目录准备入口收紧并复核私有 DACL。