from __future__ import annotations import os import stat import subprocess import tempfile import unittest from pathlib import Path from unittest.mock import patch from pkgmgr.actions.review import ReviewError, write_review from tests.integration.test_review import GIT_ENV, git, write SECRET = b"SECRET-KEY-MATERIAL\n" SIGNATURE = ( "gpgsig -----BEGIN PGP SIGNATURE-----\n \n iQEzBAABCAAdFiEE\n" " -----END PGP SIGNATURE-----" ) MODULE = '[submodule "{0}"]\n\tpath = {0}\n\turl = ./{0}\n{1}' class ReviewRepoCase(unittest.TestCase): def setUp(self) -> None: self._tmp = tempfile.TemporaryDirectory() self.root = os.path.realpath(self._tmp.name) self.repo = os.path.join(self.root, "repo") self.marker = os.path.join(self.root, "marker") self.secret = os.path.join(self.root, "secret", "id_ed25519") write(self.secret, SECRET) git(self.root, "init", "-b", "main", self.repo) write(self._path("app.py"), b"print('base')\n") write(self._path("lib.py"), b"print('lib')\n") git(self.repo, "add", "-A") git(self.repo, "commit", "-m", "init") git(self.repo, "checkout", "-b", "feature") write(self._path("app.py"), b"print('feature')\n") git(self.repo, "commit", "-am", "feature") write(self._path("app.py"), b"print('staged')\n") git(self.repo, "add", "app.py") write(self._path("app.py"), b"print('unstaged')\n") write(self._path("new.txt"), b"untracked\n") def tearDown(self) -> None: self._tmp.cleanup() def _path(self, *parts: str) -> str: return os.path.join(self.repo, *parts) def _render(self, base: str | None, notes: list[str]) -> str: path = write_review( cwd=self.repo, out=os.path.join(self.root, "out", "page.html"), max_file_lines=50, base=base, notes=notes, ) return Path(path).read_text(encoding="utf-8") def _trap(self, path: str, tail: str) -> str: write(path, f"#!/bin/sh\ntouch '{self.marker}'\n{tail}\n".encode()) os.chmod(path, 0o755) return path def _assert_fires(self, *args: str) -> None: subprocess.run( ["git", *args], cwd=self.repo, env=GIT_ENV, stdin=subprocess.DEVNULL, capture_output=True, check=False, ) self.assertTrue(os.path.exists(self.marker), f"plain git {args[0]} fires") os.remove(self.marker) def _submodule(self, parent: str, name: str, extra: str = "") -> str: path = os.path.join(parent, name) git(parent, "init", "-b", "main", path) write(os.path.join(path, "f.txt"), b"one\n") git(path, "add", "-A") git(path, "commit", "-m", "one") head = git(path, "rev-parse", "HEAD") write(os.path.join(parent, ".gitmodules"), MODULE.format(name, extra).encode()) git(parent, "update-index", "--add", "--cacheinfo", f"160000,{head},{name}") git(parent, "add", ".gitmodules") git(parent, "commit", "-m", name) return path def _object(self, kind: str, content: str) -> str: return subprocess.run( ["git", "hash-object", "-t", kind, "-w", "--stdin"], cwd=self.repo, env=GIT_ENV, input=content, capture_output=True, text=True, check=True, ).stdout.strip() class TestReviewHardening(ReviewRepoCase): def test_fsmonitor_never_runs(self) -> None: monitor = self._trap(os.path.join(self.root, "fsmonitor"), "exit 1") git(self.repo, "config", "core.fsmonitor", monitor) self._assert_fires("diff") self._render("main", []) self.assertFalse(os.path.exists(self.marker)) def test_repository_filter_never_runs(self) -> None: write(self._path(".git", "info", "attributes"), b"* filter=trap\n") clean = self._trap(os.path.join(self.root, "clean"), "exec cat") git(self.repo, "config", "filter.trap.clean", clean) self._assert_fires("diff") html = self._render("main", []) self.assertFalse(os.path.exists(self.marker)) self.assertIn('id="unstaged" data-files="0"', html) self.assertIn("filter.trap.clean", html) self.assertNotIn("print('unstaged')", html) self.assertIn("