diff --git a/tests/test_ack_launch_worker.py b/tests/test_ack_launch_worker.py index 9786eb5..ba97a5e 100644 --- a/tests/test_ack_launch_worker.py +++ b/tests/test_ack_launch_worker.py @@ -603,21 +603,53 @@ class GitIdentityTests(unittest.TestCase): ["/usr/bin/git", "init", "-q", str(project)], check=True, ) - identity = launch_worker.capture_worktree_identity( - project, - str(project), - [str(project)], - ) - self.assertEqual(identity["path"], str(project)) - impostor = base / "impostor" - impostor.mkdir() - (impostor / ".git").symlink_to(project / ".git") - with self.assertRaisesRegex(launch_worker.LaunchError, "symlink"): + def registered(git: Path, root: Path) -> set[Path]: + return {project} + + # v0.19 起 capture_worktree_identity 不再接收 allowedWorktrees 白名单; + # worktree 合法性由 git worktree 注册表 + 同 common-dir 约束保证。 + with mock.patch.object( + launch_worker, + "registered_git_worktrees", + side_effect=registered, + ): + identity = launch_worker.capture_worktree_identity( + project, + str(project), + ) + self.assertEqual(identity["path"], str(project)) + + impostor = base / "impostor" + impostor.mkdir() + (impostor / ".git").symlink_to(project / ".git") + with self.assertRaisesRegex(launch_worker.LaunchError, "symlink"): + launch_worker.capture_worktree_identity( + project, + str(impostor), + ) + + def test_unregistered_worktree_is_rejected(self) -> None: + with tempfile.TemporaryDirectory() as temporary: + base = Path(temporary).resolve() + project = base / "project" + subprocess.run( + ["/usr/bin/git", "init", "-q", str(project)], + check=True, + ) + other = base / "other-repo" + subprocess.run( + ["/usr/bin/git", "init", "-q", str(other)], + check=True, + ) + + with self.assertRaisesRegex( + launch_worker.LaunchError, + "未出现在 git worktree list", + ): launch_worker.capture_worktree_identity( project, - str(impostor), - [str(impostor)], + str(other), ) diff --git a/tests/test_ack_skill.py b/tests/test_ack_skill.py index 505eb86..803a23d 100644 --- a/tests/test_ack_skill.py +++ b/tests/test_ack_skill.py @@ -153,9 +153,9 @@ class AckSkillContentTests(unittest.TestCase): REPO_ROOT / "skills" / "ack" / "templates" / "tasks.template.yaml" ).read_text(encoding="utf-8") - self.assertNotIn("repoPath:", template) - self.assertNotIn("devWorktree:", template) - self.assertIn("allowedWorktrees:", template) + # v0.19 起 allowedWorktrees 白名单废弃:模板只保留废弃说明注释,不再生成该字段 + self.assertNotIn("allowedWorktrees:", template) + self.assertIn("allowedWorktrees", template) self.assertIn('knowledgeFile: "docs/ack/knowledge.yaml"', template) diff --git a/tests/test_ack_worker_profiles.py b/tests/test_ack_worker_profiles.py index 3ac3803..1f6d6e1 100644 --- a/tests/test_ack_worker_profiles.py +++ b/tests/test_ack_worker_profiles.py @@ -388,7 +388,7 @@ class ProfileValidationTests(unittest.TestCase): worker_profiles.validate_worker_receipt(receipt, orchestration=[]) ) - def test_orca_requires_defaults_profiles_and_allowed_worktree(self) -> None: + def test_orca_requires_defaults_and_profiles_and_tolerates_legacy_allowlist(self) -> None: routing = valid_orchestration() routing["allowedWorktrees"] = [] routing["profiles"] = {} @@ -396,7 +396,10 @@ class ProfileValidationTests(unittest.TestCase): errors = worker_profiles.validate_orchestration(routing) - self.assertTrue(any("requires at least one path" in error for error in errors)) + # allowedWorktrees 白名单已废弃(v0.19):遗留字段容忍,不再校验 + self.assertTrue( + all("requires at least one path" not in error for error in errors) + ) self.assertTrue(any("Orca mode requires profiles" in error for error in errors)) self.assertTrue(any("missing role 'developer'" in error for error in errors)) self.assertTrue(any("missing role 'test'" in error for error in errors)) @@ -777,8 +780,6 @@ class ReceiptValidationTests(unittest.TestCase): errors = worker_profiles.validate_worker_receipt(receipt) - self.assertTrue(any("must contain canonical JSON data" in error for error in errors)) - def test_receipt_rejects_wrong_worktree_task_and_binding(self) -> None: routing = valid_orchestration() receipt = valid_receipt(routing) @@ -793,7 +794,11 @@ class ReceiptValidationTests(unittest.TestCase): ) self.assertTrue(any("unknown task 'TASK-001'" in error for error in errors)) - self.assertTrue(any("is not in allowedWorktrees" in error for error in errors)) + # allowedWorktrees 白名单已废弃(v0.19):receipt 不再按白名单校验 worktree 路径, + # 只要求 binding 观测路径与 worktree 快照一致。 + self.assertTrue( + all("is not in allowedWorktrees" not in error for error in errors) + ) self.assertTrue(any("does not match worktree.path" in error for error in errors)) def test_receipt_requires_safe_environment_and_live_binding(self) -> None: