"""Regression tests for the global pre-push security hook fail-closed behavior.""" from __future__ import annotations import os import subprocess from pathlib import Path import pytest REPO_ROOT = Path(__file__).resolve().parents[1] PRE_PUSH = REPO_ROOT / "hooks" / "pre-push" @pytest.fixture def temp_git_repo(tmp_path: Path) -> Path: """Minimal git repo so the hook's git rev-parse succeeds.""" repo = tmp_path / "repo" repo.mkdir() subprocess.run(["git", "init"], cwd=repo, check=True, capture_output=True) subprocess.run( ["git", "config", "user.email", "test@example.com"], cwd=repo, check=True, capture_output=True, ) subprocess.run( ["git", "config", "user.name", "Test"], cwd=repo, check=True, capture_output=True, ) (repo / "README").write_text("x\n", encoding="utf-8") subprocess.run(["git", "add", "README"], cwd=repo, check=True, capture_output=True) subprocess.run( ["git", "commit", "-m", "init"], cwd=repo, check=True, capture_output=True, ) return repo def _run_hook( repo: Path, review_sh: str | Path, *, env_extra: dict[str, str] | None = None ) -> subprocess.CompletedProcess[str]: env = os.environ.copy() env["SH_REVIEW_SH"] = str(review_sh) if env_extra: env.update(env_extra) return subprocess.run( ["bash", str(PRE_PUSH)], cwd=repo, env=env, capture_output=True, text=True, check=False, ) def test_missing_scanner_fails_closed(temp_git_repo: Path, tmp_path: Path) -> None: missing = tmp_path / "no-such-review.sh" result = _run_hook(temp_git_repo, missing) assert result.returncode == 1 assert str(missing) in result.stderr assert "missing or not executable" in result.stderr assert "install-hooks.sh --global" in result.stderr def test_non_executable_scanner_fails_closed( temp_git_repo: Path, tmp_path: Path ) -> None: stub = tmp_path / "review.sh" stub.write_text("#!/usr/bin/env bash\nexit 0\n", encoding="utf-8") stub.chmod(0o644) result = _run_hook(temp_git_repo, stub) assert result.returncode == 1 assert str(stub) in result.stderr assert "missing or not executable" in result.stderr assert "install-hooks.sh --global" in result.stderr def test_scanner_success_allows_push(temp_git_repo: Path, tmp_path: Path) -> None: stub = tmp_path / "review.sh" stub.write_text("#!/usr/bin/env bash\nexit 0\n", encoding="utf-8") stub.chmod(0o755) result = _run_hook(temp_git_repo, stub) assert result.returncode == 0 assert "BLOCKED" not in result.stderr assert "missing or not executable" not in result.stderr def test_scanner_block_blocks_push(temp_git_repo: Path, tmp_path: Path) -> None: stub = tmp_path / "review.sh" stub.write_text("#!/usr/bin/env bash\nexit 1\n", encoding="utf-8") stub.chmod(0o755) result = _run_hook(temp_git_repo, stub) assert result.returncode == 1 assert "BLOCKED" in result.stderr