From 0fa07452b8a4c3cfb8665ac2b01239c37f99813e Mon Sep 17 00:00:00 2001 From: Leon <131140291+LeonCode2025@users.noreply.github.com> Date: Tue, 19 May 2026 20:24:50 +0800 Subject: [PATCH] Add large-stdin regression test for generated hook command --- code_review_graph/skills.py | 4 ++++ tests/test_skills.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/code_review_graph/skills.py b/code_review_graph/skills.py index aba22dc8..ef1874e4 100644 --- a/code_review_graph/skills.py +++ b/code_review_graph/skills.py @@ -560,6 +560,7 @@ def generate_hooks_config(repo_root: Path) -> dict[str, Any]: { "type": "command", "command": ( + "cat >/dev/null || true; " "git rev-parse --git-dir >/dev/null 2>&1" f" && code-review-graph update --skip-flows" f" --repo {repo_arg}" @@ -577,6 +578,7 @@ def generate_hooks_config(repo_root: Path) -> dict[str, Any]: { "type": "command", "command": ( + "cat >/dev/null || true; " "git rev-parse --git-dir >/dev/null 2>&1" f" && code-review-graph status --repo {repo_arg}" " || echo 'Not a git repo, skipping'" @@ -601,6 +603,7 @@ def generate_codex_hooks_config(repo_root: Path) -> dict[str, Any]: { "type": "command", "command": ( + "cat >/dev/null || true; " "git rev-parse --git-dir >/dev/null 2>&1" " && code-review-graph update --skip-flows" " || true" @@ -618,6 +621,7 @@ def generate_codex_hooks_config(repo_root: Path) -> dict[str, Any]: { "type": "command", "command": ( + "cat >/dev/null || true; " "git rev-parse --git-dir >/dev/null 2>&1" " && code-review-graph status" " || echo 'Not a git repo, skipping'" diff --git a/tests/test_skills.py b/tests/test_skills.py index 73fe8fe1..f6892e2c 100644 --- a/tests/test_skills.py +++ b/tests/test_skills.py @@ -2,6 +2,7 @@ import json import os +import subprocess import stat import sys from pathlib import Path @@ -121,6 +122,7 @@ def test_has_post_tool_use(self): inner = entry["hooks"][0] assert inner["type"] == "command" assert "update" in inner["command"] + assert inner["command"].startswith("cat >/dev/null || true; ") assert 0 < inner["timeout"] <= 600 def test_has_session_start(self): @@ -131,6 +133,7 @@ def test_has_session_start(self): inner = entry["hooks"][0] assert inner["type"] == "command" assert "status" in inner["command"] + assert inner["command"].startswith("cat >/dev/null || true; ") assert 0 < inner["timeout"] <= 600 def test_does_not_emit_invalid_pre_commit_hook(self): @@ -278,6 +281,7 @@ def test_has_post_tool_use(self, tmp_path): inner = entry["hooks"][0] assert inner["type"] == "command" assert "update" in inner["command"] + assert inner["command"].startswith("cat >/dev/null || true; ") assert inner["statusMessage"] == "Updating code-review-graph" def test_has_session_start(self, tmp_path): @@ -288,8 +292,37 @@ def test_has_session_start(self, tmp_path): inner = entry["hooks"][0] assert inner["type"] == "command" assert "status" in inner["command"] + assert inner["command"].startswith("cat >/dev/null || true; ") assert inner["statusMessage"] == "Checking code-review-graph status" + + def test_post_tool_use_command_handles_large_stdin_payload(self, tmp_path): + config = generate_codex_hooks_config(tmp_path) + cmd = config["hooks"]["PostToolUse"][0]["hooks"][0]["command"] + + payload = ("x" * 1024 + "\n") * 20000 + proc = subprocess.Popen( + ["bash", "-lc", cmd], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + cwd=tmp_path, + ) + + broken_pipe = None + try: + assert proc.stdin is not None + proc.stdin.write(payload) + proc.stdin.close() + except BrokenPipeError as exc: # pragma: no cover - regression guard + broken_pipe = exc + + proc.stdin = None + stdout, stderr = proc.communicate() + assert broken_pipe is None, f"hook command raised BrokenPipeError: {stderr}" + assert proc.returncode == 0, stderr + def test_commands_do_not_pin_a_specific_repo_path(self, tmp_path): config = generate_codex_hooks_config(tmp_path / "repo with spaces") post_cmd = config["hooks"]["PostToolUse"][0]["hooks"][0]["command"]