aboutsummaryrefslogtreecommitdiff
path: root/hooks/tests
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-28 12:24:59 -0400
committerCraig Jennings <c@cjennings.net>2026-06-28 12:24:59 -0400
commit92dfc355d2292c6d6c17a51cf2f83b8ba033596a (patch)
treef21e1e1bc6a207fe74911888d0d0ad53a1e95777 /hooks/tests
parent797c4267022699527a5e7c51f67be52e6fac1409 (diff)
downloadrulesets-92dfc355d2292c6d6c17a51cf2f83b8ba033596a.tar.gz
rulesets-92dfc355d2292c6d6c17a51cf2f83b8ba033596a.zip
feat(hooks): block bundled test+commit, require full suite before commit
I tightened the before-committing rule in verification.md and commits.md from "run tests" to "run the full suite as its own step and commit only on zero failures." A PreToolUse hook now backs it: it denies a test runner chained into git commit through an ungated connector, and lets the gated && form pass. I added a respond_deny helper. Tests cover the connector cases.
Diffstat (limited to 'hooks/tests')
-rw-r--r--hooks/tests/test_git_commit_confirm.py58
1 files changed, 58 insertions, 0 deletions
diff --git a/hooks/tests/test_git_commit_confirm.py b/hooks/tests/test_git_commit_confirm.py
index 83519ad..4bf95cf 100644
--- a/hooks/tests/test_git_commit_confirm.py
+++ b/hooks/tests/test_git_commit_confirm.py
@@ -95,3 +95,61 @@ def test_oversized_file_falls_through_and_hook_asks(tmp_path, monkeypatch):
# And the hook would ask, because UNPARSEABLE_MESSAGE is a flagged issue.
issues = hook.collect_issues(msg, staged=["a.py"], author="Dev <d@e.com>")
assert any("not parseable" in i for i in issues)
+
+
+# --- bundled test-run + commit: the hard gate ------------------------------
+
+def test_bundle_semicolon_make_test_is_flagged():
+ assert hook.detect_bundled_test_run('make test; git commit -m "x"')
+
+
+def test_bundle_ampersand_gated_is_allowed():
+ # `&&` runs the commit only on a green suite — safe, not flagged.
+ assert hook.detect_bundled_test_run('make test && git commit -m "x"') is None
+
+
+def test_bundle_pytest_semicolon_is_flagged():
+ assert hook.detect_bundled_test_run('pytest ; git commit -m "x"')
+
+
+def test_bundle_npm_test_is_flagged():
+ assert hook.detect_bundled_test_run('npm test; git commit -m "x"')
+
+
+def test_bundle_go_test_is_flagged():
+ assert hook.detect_bundled_test_run('go test ./...; git commit -m "x"')
+
+
+def test_bundle_cargo_test_is_flagged():
+ assert hook.detect_bundled_test_run('cargo test ; git commit -m "x"')
+
+
+def test_bundle_bats_is_flagged():
+ assert hook.detect_bundled_test_run('bats tests/ ; git commit -m "x"')
+
+
+def test_bundle_pipe_masks_exit_is_flagged():
+ # `make test | tee log` exits with tee's status, so && gates on tee, not
+ # the suite — a red suite would still commit. Flag it.
+ assert hook.detect_bundled_test_run('make test | tee log && git commit -m "x"')
+
+
+def test_bundle_or_connector_is_flagged():
+ assert hook.detect_bundled_test_run('make test || git commit -m "x"')
+
+
+def test_runner_only_in_message_is_not_flagged():
+ # "make test" inside the commit message must not trip the detector.
+ assert hook.detect_bundled_test_run('git commit -m "remember to make test"') is None
+
+
+def test_plain_commit_is_not_flagged():
+ assert hook.detect_bundled_test_run('git commit -m "fix: thing"') is None
+
+
+def test_gated_chain_before_commit_is_allowed():
+ assert hook.detect_bundled_test_run('cd proj && pytest && git commit -m "x"') is None
+
+
+def test_empty_command_is_not_flagged():
+ assert hook.detect_bundled_test_run("") is None