diff options
| author | 2026-06-17 15:47:38 +0100 | |
|---|---|---|
| committer | 2026-06-17 15:47:38 +0100 | |
| commit | 21cf68aa34b9b6515c4a2668f656fc5b767ec9c1 (patch) | |
| tree | f4f2f197bc615dd49803c24748c95a646860e795 | |
| parent | e86e1a2e2471613169d0f016abf87f264de69003 (diff) | |
| download | dotfiles-21cf68aa34b9b6515c4a2668f656fc5b767ec9c1.tar.gz dotfiles-21cf68aa34b9b6515c4a2668f656fc5b767ec9c1.tar.bz2 dotfiles-21cf68aa34b9b6515c4a2668f656fc5b767ec9c1.zip | |
Relax AI committer push check
| -rw-r--r-- | README.md | 2 | ||||
| -rwxr-xr-x | dot_config/git/hooks/executable_pre-push | 32 |
2 files changed, 11 insertions, 23 deletions
@@ -143,7 +143,7 @@ Projects opt in by just dropping a file at `.githooks/<name>` — no `core.hooks - `pre-commit` → repo's `.githooks/pre-commit` (if any). No global logic. In this repo: `just check`. - `commit-msg` → repo's `.githooks/commit-msg` (if any), then strips any `Co-authored-by:` whose identity matches an AI agent (Copilot/Claude/Codex/…) so they don't trip the push gate. -- `pre-push` → repo's `.githooks/pre-push` (if any), then rejects pushes that contain unsigned commits, commits with a foreign committer, or commits authored/co-authored by an AI agent. +- `pre-push` → repo's `.githooks/pre-push` (if any), then rejects pushes that contain unsigned commits or commits whose author/committer/coauthor looks like an AI agent. - `post-commit` → repo's `.githooks/post-commit` (if any). No global logic. In this repo: `chezmoi apply`. Bypass any of these with `--no-verify` on `commit`/`push`. diff --git a/dot_config/git/hooks/executable_pre-push b/dot_config/git/hooks/executable_pre-push index b0915bf..0d4a154 100755 --- a/dot_config/git/hooks/executable_pre-push +++ b/dot_config/git/hooks/executable_pre-push @@ -1,11 +1,11 @@ #!/usr/bin/env dash # Reject pushes that include commits which: # * lack a good signature, or -# * have a committer different from this repo's user.name / user.email, or -# * have an author that looks like a coding agent (Copilot, Claude, -# Codex, ChatGPT, Cursor, Aider, Devin, ...) -- I want my name on -# anything I push, even when an agent helped write it. Use -# `git commit --amend --reset-author` after agent-assisted work. +# * have an author, committer, or coauthor that looks like a coding +# agent (Copilot, Claude, Codex, ChatGPT, Cursor, Aider, Devin, ...). +# I want human names on anything I push, even when an agent helped +# write it. Use `git commit --amend --reset-author` after +# agent-authored work. # # Activated via core.hooksPath in ~/.config/git/config so it applies to # every repo unless that repo overrides hooksPath itself (this dotfiles @@ -26,14 +26,6 @@ dispatch_repo_hook pre-push "$@" <"$_stdin_buf" zero=$(git hash-object --stdin </dev/null | tr '0-9a-f' '0') -expected_name=$(git config user.name || true) -expected_email=$(git config user.email || true) - -if [ -z "$expected_name" ] || [ -z "$expected_email" ]; then - printf 'pre-push: user.name or user.email is unset; refusing.\n' >&2 - exit 1 -fi - # %G? signature status codes from git-log: # G good signature # U good, unknown validity (e.g. trust level not set) @@ -46,7 +38,7 @@ fi # We accept G/U/X/Y and reject anything else. ok='G U X Y' -# Case-insensitive substrings that disqualify an author. Matched against +# Case-insensitive substrings that disqualify an identity. Matched against # "<name> <email>" lowercased. Plain substring matching (index()) is # used in the awk below to dodge regex-escaping pitfalls. Keep this list # narrow on purpose: false positives are worse than misses (a slipped @@ -76,8 +68,6 @@ while read -r _local_ref local_sha remote_ref remote_sha; do --no-commit-header "$@" | awk -F'\t' \ -v ok="$ok" \ - -v en="$expected_name" \ - -v ee="$expected_email" \ -v agent_subs="$agent_subs" ' BEGIN { split(ok, a, " "); for (i in a) good[a[i]] = 1 @@ -90,8 +80,8 @@ while read -r _local_ref local_sha remote_ref remote_sha; do { reasons = "" if (!($2 in good)) reasons = reasons " [sig=" $2 "]" - if ($3 != en || $4 != ee) { - reasons = reasons " [committer=" $3 " <" $4 ">]" + if (is_agent(tolower($3 " " $4))) { + reasons = reasons " [agent-committer=" $3 " <" $4 ">]" } if (is_agent(tolower($5 " " $6))) { reasons = reasons " [agent-author=" $5 " <" $6 ">]" @@ -111,8 +101,6 @@ while read -r _local_ref local_sha remote_ref remote_sha; do if [ -n "$bad" ]; then if [ "$fail" -eq 0 ]; then printf '\nrefusing to push: bad commits found\n' >&2 - printf '(expected committer: %s <%s>)\n' \ - "$expected_name" "$expected_email" >&2 fi printf '\non %s:\n%s\n' "$remote_ref" "$bad" >&2 fail=1 @@ -120,9 +108,9 @@ while read -r _local_ref local_sha remote_ref remote_sha; do done <"$_stdin_buf" if [ "$fail" -ne 0 ]; then - printf '\nfix sig + committer:\n' >&2 + printf '\nfix signature:\n' >&2 printf ' git rebase --exec "git commit --amend --no-edit -S" <base>\n' >&2 - printf 'fix author (re-stamp yourself as author, keep agent out):\n' >&2 + printf 'fix AI identity (re-stamp yourself as author/committer, keep agent out):\n' >&2 printf ' git rebase --exec "git commit --amend --no-edit --reset-author -S" <base>\n' >&2 printf 'bypass:\n git push --no-verify\n\n' >&2 exit 1 |
