From 3efd9abc11c21c36fa345e437598af1dc837054a Mon Sep 17 00:00:00 2001 From: csh Date: Mon, 13 Jul 2026 11:23:06 +0800 Subject: [PATCH] :bug: fix(test): pin REPO_DIR in sync integration test env run_sync copied os.environ but never set REPO_DIR. In CI, test.yml exports REPO_DIR (the real checkout) via GITHUB_ENV, so the inherited value made the sync operate on the real CI checkout instead of the temp fixture, deleting dirs later tests need. Pin REPO_DIR to the passed repo and add a regression test proving an inherited REPO_DIR does not leak. Co-Authored-By: Claude Fable 5 --- test/test_build_tsl_playbook.py | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/test_build_tsl_playbook.py b/test/test_build_tsl_playbook.py index fc3b93ba..c0e0e53d 100644 --- a/test/test_build_tsl_playbook.py +++ b/test/test_build_tsl_playbook.py @@ -242,6 +242,42 @@ class BuildTslPlaybookTests(unittest.TestCase): ) self.assertNotEqual(result.returncode, 0, msg=f"{path} leaked") + def test_sync_ignores_inherited_repo_dir_from_environment(self): + if shutil.which("bash") is None: + self.skipTest("bash is required to run sync workflow script") + + with tempfile.TemporaryDirectory() as tmp_dir: + tmp = Path(tmp_dir) + repo = create_source_repo(tmp) + + # Simulate the CI environment exporting REPO_DIR pointing at the + # real checkout. The sync must operate on the repo passed to + # run_sync, never the inherited value. + decoy = tmp / "decoy-checkout" + decoy.mkdir() + sentinel = decoy / "sentinel.txt" + sentinel.write_text("untouched\n", encoding="utf-8", newline="\n") + + previous = os.environ.get("REPO_DIR") + os.environ["REPO_DIR"] = str(decoy) + try: + run_sync(repo) + finally: + if previous is None: + os.environ.pop("REPO_DIR", None) + else: + os.environ["REPO_DIR"] = previous + + # The decoy must be left completely alone. + self.assertEqual( + sorted(item.name for item in decoy.iterdir()), + ["sentinel.txt"], + ) + self.assertEqual(sentinel.read_text(encoding="utf-8"), "untouched\n") + + # And the intended repo must actually have been published. + git(repo, "cat-file", "-e", "HEAD:AGENTS.md") + def create_source_repo(tmp: Path) -> Path: repo = tmp / "repo" @@ -265,6 +301,7 @@ def run_sync(repo: Path) -> None: env = os.environ.copy() env.update( { + "REPO_DIR": str(repo), "TARGET_BRANCH": "tsl-playbook", "COMMIT_AUTHOR_NAME": "test", "COMMIT_AUTHOR_EMAIL": "test@example.invalid",