Files
kandev/scripts/pr-walkthrough-read-file.test.py
T
2026-08-22 21:46:57 +01:00

113 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""Tests for immutable, regular-file reads from an untrusted PR commit."""
from pathlib import Path
import os
import subprocess
import sys
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[1]
SCRIPT = ROOT / "scripts" / "pr-walkthrough-read-file"
class PRWalkthroughReadFileTest(unittest.TestCase):
def setUp(self) -> None:
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.repo = Path(self.temp.name) / "repo"
self.repo.mkdir()
self.git("init")
self.git("config", "user.name", "Walkthrough Test")
self.git("config", "user.email", "walkthrough@example.invalid")
(self.repo / "src").mkdir()
(self.repo / "src" / "regular.txt").write_text("trusted commit bytes\n", encoding="utf-8")
(self.repo / "executable.sh").write_text("#!/bin/sh\n", encoding="utf-8")
os.chmod(self.repo / "executable.sh", 0o755)
(self.repo / "binary.dat").write_bytes(b"\xff\xfe")
(self.repo / "large.txt").write_text("x" * (512 * 1024 + 1), encoding="utf-8")
os.symlink("/etc/passwd", self.repo / "outside-link")
self.git("add", ".")
self.git("commit", "-m", "test fixture")
self.head = self.git("rev-parse", "HEAD").stdout.strip()
def git(self, *args: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["git", *args],
cwd=self.repo,
text=True,
capture_output=True,
check=True,
)
def read(self, path: str, *, head: str | None = None) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[
sys.executable,
str(SCRIPT),
"--repo",
str(self.repo),
"--head-sha",
head or self.head,
"--path",
path,
],
text=True,
capture_output=True,
check=False,
)
def test_reads_regular_file_from_exact_commit_not_worktree(self) -> None:
(self.repo / "src" / "regular.txt").write_text("changed worktree bytes\n", encoding="utf-8")
result = self.read("src/regular.txt")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.stdout, "trusted commit bytes\n")
def test_reads_executable_regular_file(self) -> None:
result = self.read("executable.sh")
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.stdout, "#!/bin/sh\n")
def test_rejects_traversal_absolute_and_pathspec_paths(self) -> None:
for path in ("../outside", "/etc/passwd", "src//regular.txt", ":(glob)**"):
with self.subTest(path=path):
result = self.read(path)
self.assertNotEqual(result.returncode, 0)
self.assertIn("invalid repository-relative path", result.stderr)
def test_rejects_symlink(self) -> None:
result = self.read("outside-link")
self.assertNotEqual(result.returncode, 0)
self.assertIn("regular file", result.stderr)
def test_rejects_binary_file(self) -> None:
result = self.read("binary.dat")
self.assertNotEqual(result.returncode, 0)
self.assertIn("UTF-8 text", result.stderr)
def test_rejects_oversized_file(self) -> None:
result = self.read("large.txt")
self.assertNotEqual(result.returncode, 0)
self.assertIn("exceeds 524288 bytes", result.stderr)
def test_rejects_missing_file_and_invalid_sha(self) -> None:
missing = self.read("missing.txt")
invalid_sha = self.read("src/regular.txt", head="main")
self.assertNotEqual(missing.returncode, 0)
self.assertIn("not a regular file", missing.stderr)
self.assertNotEqual(invalid_sha.returncode, 0)
self.assertIn("40 lowercase hexadecimal", invalid_sha.stderr)
if __name__ == "__main__":
unittest.main()