diff --git a/scripts/release_control/format_staged_go.py b/scripts/release_control/format_staged_go.py index 1cc560940..8ca79a9d8 100644 --- a/scripts/release_control/format_staged_go.py +++ b/scripts/release_control/format_staged_go.py @@ -15,11 +15,13 @@ DEFAULT_REPO_ROOT = REPO_ROOT def git_env() -> dict[str, str]: env = os.environ.copy() - # Unit tests patch REPO_ROOT to a temporary repository. In that case, an - # inherited alternate index from the caller should not leak into the temp - # repo and point git plumbing at entries from a different repository. + # Unit tests patch REPO_ROOT to a temporary repository. In that case, the + # inherited hook environment (alternate index, or the absolute GIT_DIR a + # pre-commit run from a linked worktree exports) should not leak into the + # temp repo and point git plumbing at a different repository. if REPO_ROOT != DEFAULT_REPO_ROOT: - env.pop("GIT_INDEX_FILE", None) + for name in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR"): + env.pop(name, None) return env diff --git a/scripts/release_control/format_staged_go_test.py b/scripts/release_control/format_staged_go_test.py index 626fcd5a5..0e9273e41 100644 --- a/scripts/release_control/format_staged_go_test.py +++ b/scripts/release_control/format_staged_go_test.py @@ -11,7 +11,11 @@ from format_staged_go import format_staged_go_files class FormatStagedGoTest(unittest.TestCase): def git(self, repo_root: Path, *args: str) -> subprocess.CompletedProcess: env = os.environ.copy() - env.pop("GIT_INDEX_FILE", None) + # Scrub the full hook environment: with only GIT_INDEX_FILE removed, a + # pre-commit run from a linked worktree exports an absolute GIT_DIR and + # "git init" here re-initializes the REAL repository as bare. + for name in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR"): + env.pop(name, None) return subprocess.run( ["git", *args], cwd=repo_root, diff --git a/scripts/release_control/governance_stage_guard.py b/scripts/release_control/governance_stage_guard.py index c4b2cc2e8..8181da979 100644 --- a/scripts/release_control/governance_stage_guard.py +++ b/scripts/release_control/governance_stage_guard.py @@ -30,7 +30,12 @@ DEFAULT_REPO_ROOT = REPO_ROOT def git_env() -> dict[str, str]: env = os.environ.copy() if REPO_ROOT != DEFAULT_REPO_ROOT: - env.pop("GIT_INDEX_FILE", None) + # Unit tests patch REPO_ROOT to a temporary repository. Scrub the full + # inherited hook environment: a pre-commit run from a linked worktree + # exports an absolute GIT_DIR, which would silently point git at the + # real repository instead of the temp one. + for name in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR"): + env.pop(name, None) return env diff --git a/scripts/release_control/governance_stage_guard_test.py b/scripts/release_control/governance_stage_guard_test.py index fcf6c7c1e..0807879f3 100644 --- a/scripts/release_control/governance_stage_guard_test.py +++ b/scripts/release_control/governance_stage_guard_test.py @@ -15,7 +15,11 @@ from governance_stage_guard import ( class GovernanceStageGuardTest(unittest.TestCase): def git(self, repo_root: Path, *args: str) -> subprocess.CompletedProcess: env = os.environ.copy() - env.pop("GIT_INDEX_FILE", None) + # Scrub the full hook environment: with only GIT_INDEX_FILE removed, a + # pre-commit run from a linked worktree exports an absolute GIT_DIR and + # "git init" here re-initializes the REAL repository as bare. + for name in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR"): + env.pop(name, None) return subprocess.run( ["git", *args], cwd=repo_root, diff --git a/scripts/release_control/readiness_assertion_guard_test.py b/scripts/release_control/readiness_assertion_guard_test.py index d7c1ee1af..2c16b5bf8 100644 --- a/scripts/release_control/readiness_assertion_guard_test.py +++ b/scripts/release_control/readiness_assertion_guard_test.py @@ -36,7 +36,11 @@ def base_payload() -> dict: class ReadinessAssertionGuardTest(unittest.TestCase): def git(self, repo_root: Path, *args: str) -> subprocess.CompletedProcess: env = os.environ.copy() - env.pop("GIT_INDEX_FILE", None) + # Scrub the full hook environment: with only GIT_INDEX_FILE removed, a + # pre-commit run from a linked worktree exports an absolute GIT_DIR and + # "git init" here re-initializes the REAL repository as bare. + for name in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR"): + env.pop(name, None) return subprocess.run( ["git", *args], cwd=repo_root, diff --git a/scripts/release_control/subsystem_contracts.py b/scripts/release_control/subsystem_contracts.py index a3149dfe3..e68698f5f 100644 --- a/scripts/release_control/subsystem_contracts.py +++ b/scripts/release_control/subsystem_contracts.py @@ -52,7 +52,12 @@ PATH_SUFFIXES = ( def git_env() -> dict[str, str]: env = os.environ.copy() if REPO_ROOT != DEFAULT_REPO_ROOT: - env.pop("GIT_INDEX_FILE", None) + # Unit tests patch REPO_ROOT to a temporary repository. Scrub the full + # inherited hook environment: a pre-commit run from a linked worktree + # exports an absolute GIT_DIR, which would silently point git at the + # real repository instead of the temp one. + for name in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR"): + env.pop(name, None) return env diff --git a/scripts/release_control/subsystem_contracts_test.py b/scripts/release_control/subsystem_contracts_test.py index 9c4781e7e..cea26fef1 100644 --- a/scripts/release_control/subsystem_contracts_test.py +++ b/scripts/release_control/subsystem_contracts_test.py @@ -18,7 +18,11 @@ from subsystem_contracts import ( class SubsystemContractsTest(unittest.TestCase): def git(self, repo_root: Path, *args: str) -> subprocess.CompletedProcess: env = os.environ.copy() - env.pop("GIT_INDEX_FILE", None) + # Scrub the full hook environment: with only GIT_INDEX_FILE removed, a + # pre-commit run from a linked worktree exports an absolute GIT_DIR and + # "git init" here re-initializes the REAL repository as bare. + for name in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GIT_COMMON_DIR"): + env.pop(name, None) return subprocess.run( ["git", *args], cwd=repo_root,