ci: isolate Ubuntu sources and select Git Bash for Windows tests
Launcher checks / check (push) Waiting to run

This commit is contained in:
Emil
2026-09-09 20:41:07 +03:00
parent daefc3f5e7
commit cacd1cd2bd
6 changed files with 95 additions and 15 deletions
+63 -6
View File
@@ -2,10 +2,12 @@
import os
import re
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
ROOT = Path(os.environ.get("RELEASE_TEST_ROOT", Path(__file__).resolve().parents[1]))
@@ -13,6 +15,32 @@ WORKFLOWS = [ROOT / ".github/workflows" / name for name in ("release.yml", "rele
GATE = " - name: Resolve tag using trusted workflow Git commands\n"
def gate_bash(windows=os.name == "nt"):
# Native CreateProcess can resolve bare bash to the System32 WSL launcher
# before Git Bash. Bind tests to the Bash installed with the Git we use.
if windows:
git = shutil.which("git")
if git:
directory = Path(git).resolve().parent
candidates = (
directory / "bash.exe", # Git/bin/git.exe
directory.parent / "bin/bash.exe", # Git/cmd/git.exe
directory.parent.parent / "bin/bash.exe", # Git/mingw64/bin/git.exe
)
for candidate in candidates:
if candidate.is_file():
return str(candidate.resolve())
raise RuntimeError("Git for Windows Bash was not found beside the installed Git")
bash = shutil.which("bash")
if not bash:
raise RuntimeError("Bash is required to execute the release workflow gate")
return str(Path(bash).resolve())
def gate_diagnostic(result):
return f"command={result.args!r}\nstdout={result.stdout!r}\nstderr={result.stderr!r}"
def workflow_gate(workflow):
after = workflow.read_text().split(GATE, 1)[1]
lines = after.split(" run: |\n", 1)[1].splitlines()
@@ -60,23 +88,52 @@ class ReleaseGateTests(unittest.TestCase):
def run_gate(self, workflow, tag):
output = self.directory / (workflow.stem + "-output")
output.unlink(missing_ok=True)
result = subprocess.run(["bash", "-c", workflow_gate(workflow)], cwd=self.directory,
result = subprocess.run([gate_bash(), "--noprofile", "--norc", "-c", workflow_gate(workflow)], cwd=self.directory,
env=dict(self.environment, RELEASE_TAG=tag, GITHUB_OUTPUT=str(output)),
capture_output=True, text=True, check=False)
return result, output.read_text() if output.exists() else ""
def test_windows_gate_uses_git_bash_even_when_path_contains_wsl_launcher(self):
git_root = self.directory / "Git with spaces"
bash = git_root / "bin/bash.exe"
bash.parent.mkdir(parents=True)
bash.touch()
wsl = self.directory / "System32/bash.exe"
wsl.parent.mkdir()
wsl.touch()
for layout in ("bin", "cmd", "mingw64/bin"):
with self.subTest(layout=layout):
git = git_root / layout / "git.exe"
git.parent.mkdir(parents=True, exist_ok=True)
git.touch()
with patch.object(shutil, "which", side_effect=lambda name: str(git if name == "git" else wsl)) as lookup:
self.assertEqual(gate_bash(windows=True), str(bash.resolve()))
lookup.assert_called_once_with("git")
def test_windows_gate_never_falls_back_to_unrelated_bash(self):
git = self.directory / "Git/cmd/git.exe"
git.parent.mkdir(parents=True)
git.touch()
wsl = self.directory / "System32/bash.exe"
wsl.parent.mkdir()
wsl.touch()
with patch.object(shutil, "which", side_effect=lambda name: str(git if name == "git" else wsl)) as lookup:
with self.assertRaisesRegex(RuntimeError, "Git for Windows Bash"):
gate_bash(windows=True)
lookup.assert_called_once_with("git")
def test_main_tag_emits_immutable_commit(self):
for workflow in WORKFLOWS:
with self.subTest(workflow=workflow.name):
result, output = self.run_gate(workflow, "v0.2.0")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.returncode, 0, gate_diagnostic(result))
self.assertEqual(output, f"commit={self.good}\n")
def test_unreviewed_tag_cannot_replace_its_own_ancestry_validator(self):
for workflow in WORKFLOWS:
with self.subTest(workflow=workflow.name):
result, output = self.run_gate(workflow, "v9.9.9")
self.assertNotEqual(result.returncode, 0)
self.assertNotEqual(result.returncode, 0, gate_diagnostic(result))
self.assertEqual(output, "")
self.assertFalse((self.directory / "untrusted-code-ran").exists())
@@ -84,15 +141,15 @@ class ReleaseGateTests(unittest.TestCase):
for workflow in WORKFLOWS:
with self.subTest(workflow=workflow.name):
result, output = self.run_gate(workflow, "v8.8.8")
self.assertNotEqual(result.returncode, 0)
self.assertNotEqual(result.returncode, 0, gate_diagnostic(result))
self.assertEqual(output, "")
self.git("tag", "-f", "v0.2.0", self.good)
result, output = self.run_gate(workflow, "v0.2.0")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.returncode, 0, gate_diagnostic(result))
self.git("tag", "-f", "v0.2.0", self.bad)
self.assertEqual(output, f"commit={self.good}\n")
result, fresh_output = self.run_gate(workflow, "v0.2.0")
self.assertNotEqual(result.returncode, 0)
self.assertNotEqual(result.returncode, 0, gate_diagnostic(result))
self.assertEqual(fresh_output, "")
def test_workflows_execute_candidate_code_only_after_gate_and_checkout_sha(self):