aboutsummaryrefslogtreecommitdiff
path: root/hooks/git-commit-confirm.py
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-04-19 17:14:54 -0500
committerCraig Jennings <c@cjennings.net>2026-04-19 17:14:54 -0500
commit208a079f4230edd520f5aa92288ae48247340910 (patch)
tree236db8e21cd7369c7d0b741c673524464ba9af36 /hooks/git-commit-confirm.py
parent4957c60c9ee985628ad59344e593d20a18ca8fdb (diff)
downloadrulesets-208a079f4230edd520f5aa92288ae48247340910.tar.gz
rulesets-208a079f4230edd520f5aa92288ae48247340910.zip
feat(hooks): shared _common.py helpers + systemMessage AI-attribution warning
Consolidates stdin-parse and response-emit across the two confirm hooks into `hooks/_common.py` (stdlib-only, sibling symlinked alongside the hooks it serves). Net ~28 lines less duplication. Adds a `systemMessage` banner alongside the confirmation modal when the commit message or PR title/body contains AI-attribution patterns: - Co-Authored-By: Claude|Anthropic|GPT|AI trailers - 🤖 robot emoji - "Generated with Claude Code" / similar footers - "Created with …" / "Assisted by …" variants Scanning targets structural leak patterns only — bare mentions of "Claude" or "Anthropic" in diff context don't fire, so discussing the tools themselves in a commit message doesn't false-positive. Clean-room synthesis from GowayLee/cchooks (MIT) — specifically, the systemMessage-alongside-reason pattern and event-aware stdin helpers.
Diffstat (limited to 'hooks/git-commit-confirm.py')
-rwxr-xr-xhooks/git-commit-confirm.py25
1 files changed, 11 insertions, 14 deletions
diff --git a/hooks/git-commit-confirm.py b/hooks/git-commit-confirm.py
index bea6410..ad2dd66 100755
--- a/hooks/git-commit-confirm.py
+++ b/hooks/git-commit-confirm.py
@@ -28,22 +28,19 @@ Wire in ~/.claude/settings.json (or per-project .claude/settings.json):
}
"""
-import json
import re
import subprocess
import sys
+from _common import read_payload, respond_ask, scan_attribution
+
MAX_FILES_SHOWN = 25
MAX_MESSAGE_LINES = 30
def main() -> int:
- try:
- payload = json.loads(sys.stdin.read())
- except (json.JSONDecodeError, ValueError):
- return 0 # malformed; don't block
-
+ payload = read_payload()
if payload.get("tool_name") != "Bash":
return 0
@@ -58,14 +55,14 @@ def main() -> int:
reason = format_confirmation(message, staged, stats, author)
- output = {
- "hookSpecificOutput": {
- "hookEventName": "PreToolUse",
- "permissionDecision": "ask",
- "permissionDecisionReason": reason,
- }
- }
- print(json.dumps(output))
+ hits = scan_attribution(message)
+ system_message = (
+ f"WARNING — commit message contains AI-attribution patterns: "
+ f"{'; '.join(hits)}. Policy forbids AI credit in commits."
+ if hits else None
+ )
+
+ respond_ask(reason, system_message=system_message)
return 0