From 901cdb96efaea06277cf659f1291327b08e859c6 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Tue, 1 Sep 2026 19:13:38 +0800 Subject: [PATCH] fix(rectification): expand quality-gate pytest globs before argv subprocess.run does not shell-expand tests/test_rectification_*.py, so a string pin could stay green while the suite never ran. Expand glob targets to real files and fail closed on zero matches. Co-authored-by: Cursor --- scripts/run_quality_gate.py | 27 ++++++++++++++++++- ...test_rectification_diagnostics_clusters.py | 15 ++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/scripts/run_quality_gate.py b/scripts/run_quality_gate.py index 95652cb7..1b6a1ada 100644 --- a/scripts/run_quality_gate.py +++ b/scripts/run_quality_gate.py @@ -75,6 +75,31 @@ RUNTIME_TRUTH_PYTEST_TARGETS = [ "tests/test_final_jhora_evidence_packet_acceptance.py", ] + +def _expand_pytest_targets(targets: list[str]) -> list[str]: + """Expand glob entries so pytest argv never depends on a shell. + + `subprocess.run` is invoked without `shell=True`. A literal + `tests/test_rectification_*.py` is then a filename pytest may ignore, + so a pin that only checks the string is present can stay green while + the suite never runs. + """ + expanded: list[str] = [] + for target in targets: + if any(mark in target for mark in "*?["): + matches = sorted( + path.relative_to(ROOT).as_posix() + for path in ROOT.glob(target) + if path.is_file() + ) + if not matches: + raise SystemExit(f"pytest glob {target!r} matched no files under {ROOT}") + expanded.extend(matches) + continue + expanded.append(target) + return expanded + + RELEASE_CRITICAL_UNTRACKED_PATHS = [ "docs/research/desktop_packaging_spike_2026_06_23.md", "docs/research/ephemeris_abstraction_feasibility_2026_06_23.md", @@ -515,7 +540,7 @@ def main() -> int: pytest_targets = RUNTIME_TRUTH_PYTEST_TARGETS else: pytest_targets = CORE_PYTEST_TARGETS - run([PYTHON, "-m", "pytest", *pytest_targets]) + run([PYTHON, "-m", "pytest", *_expand_pytest_targets(pytest_targets)]) if not profile["skip_frontend_runtime"]: run(["npm", "test"], optional=False, cwd=APP) run(["npm", "run", "lint"], optional=False, cwd=APP) diff --git a/tests/test_rectification_diagnostics_clusters.py b/tests/test_rectification_diagnostics_clusters.py index c6a32e19..b290c6dd 100644 --- a/tests/test_rectification_diagnostics_clusters.py +++ b/tests/test_rectification_diagnostics_clusters.py @@ -132,8 +132,21 @@ class RectificationDiagnosticsClustersTest(unittest.TestCase): def test_staging_quick_gate_runs_rectification_python_suite(self) -> None: from pathlib import Path + + from scripts.run_quality_gate import CORE_PYTEST_TARGETS, _expand_pytest_targets + + glob_target = "tests/test_rectification_*.py" text = Path("scripts/run_quality_gate.py").read_text(encoding="utf-8") - self.assertIn('"tests/test_rectification_*.py"', text) + self.assertIn(f'"{glob_target}"', text) + self.assertIn(glob_target, CORE_PYTEST_TARGETS) + expanded = _expand_pytest_targets([glob_target]) + self.assertGreaterEqual(len(expanded), 6) + self.assertTrue(all( + item.startswith("tests/test_rectification_") and item.endswith(".py") + for item in expanded + )) + with self.assertRaises(SystemExit): + _expand_pytest_targets(["tests/no_such_rectification_glob_*.py"]) if __name__ == "__main__":