From 4ecab19429a10060ef0bf0ceecf88ece0e53645b Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Thu, 10 Sep 2026 16:52:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20CI=20=E6=9D=83=E9=99=90?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=E5=9C=A8=20root=20=E5=AE=B9=E5=99=A8?= =?UTF-8?q?=E4=B8=8B=E7=9A=84=E5=89=8D=E6=8F=90=E5=B9=B6=E8=A1=A5=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E6=97=A0=E5=85=B3=E7=9A=84=E5=88=86=E7=B1=BB=E5=88=A4?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - project_write_lock_does_not_project_permission_denial_as_contention 不再用 expect_err 断言“只读目录必须挡住取锁”:CI 容器以 root 运行,0o500 不生效,取锁会正常成功;此时跳过端到端前提 - 新增平台无关用例 project_write_lock_classifies_by_whether_the_target_exists:目标存在才是争用、目标不存在却创建失败是权限拒绝、NotFound 归其它 - 让权限分类判据在不依赖 ACL 环境的条件下也有回归护栏,避免只靠会被 root 绕过的端到端用例 --- .../src-tauri/src/project/filesystem.rs | 27 +++++++++++++++++++ .../src/tests/project_lock_recovery.rs | 9 +++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs b/apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs index 3b3837176..80014ff44 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs @@ -485,6 +485,33 @@ fn project_write_lock_reports_acl_denial_without_an_existing_target() { ); } +/// 分类判据本身与平台无关,两个平台都要盯住:目标存在才是争用,目标不存在却创建失败 +/// 是权限拒绝。这条用例不依赖 ACL 环境,因此在 CI 容器以 root 运行时仍然有效。 +#[test] +fn project_write_lock_classifies_by_whether_the_target_exists() { + assert_eq!( + project_write_lock_classify_open_error( + &std::io::Error::from(std::io::ErrorKind::AlreadyExists), + true + ), + ProjectWriteLockOpenFailure::Contention + ); + assert_eq!( + project_write_lock_classify_open_error( + &std::io::Error::from(std::io::ErrorKind::PermissionDenied), + false + ), + ProjectWriteLockOpenFailure::Permission + ); + assert_eq!( + project_write_lock_classify_open_error( + &std::io::Error::from(std::io::ErrorKind::NotFound), + false + ), + ProjectWriteLockOpenFailure::Other + ); +} + #[cfg(all(test, windows))] #[test] fn project_write_lock_hardens_space_containing_path_in_process() { diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/project_lock_recovery.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/project_lock_recovery.rs index ef40e1a95..f7de9d54e 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/project_lock_recovery.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/project_lock_recovery.rs @@ -426,10 +426,15 @@ fn project_write_lock_does_not_project_permission_denial_as_contention() { fs::set_permissions(&agent_directory, fs::Permissions::from_mode(0o500)) .expect("去掉控制目录写权限"); - let error = - acquire_project_write_lock(&root, "file.write").expect_err("只读控制目录必须挡住取锁"); + let outcome = acquire_project_write_lock(&root, "file.write"); fs::set_permissions(&agent_directory, original).expect("恢复控制目录权限"); + // CI 容器以 root 运行,0o500 目录照样可以创建文件;此时本用例的前提不成立, + // 直接跳过。分类判据本身另有不依赖 ACL 环境的纯函数用例覆盖。 + let Err(error) = outcome else { + return; + }; + assert!( !error.starts_with("项目正在被其他写操作占用:"), "权限拒绝不得投影成写锁争用:{error}"