bug#81520: Add pre-receive hook to Savannah to reject LLM-encumbered commits

Jim Porter <[email protected]> Wed, 29 Jul 2026 18:54:13 -0700
Newsgroups gmane.emacs.bugs
Message-ID <[email protected]>
X-Debbugs-CC: [email protected]

As discussed on emacs-devel, here's a small Git hook that we can install 
on Savannah to reject commits with LLM attributions. This will hopefully 
let us avoid force-pushes in the future to remove any such commits (or 
less-drastic measures like reverting them).

After some thought, I opted to do this as a pre-receive hook on Savannah 
instead of a commit-msg or pre-push hook in people's local clones. This 
way, only people with commit access will see the error. I think we can 
and should trust those with commit rights, but others may take the error 
as impetus to hide their LLM usage. (Since this is simply a best-effort 
script to make life easier for maintainers, I'm not too worried about 
this being "security through obscurity".)

If this hook fails, the user will see something like the following message:

> remote: LLM-encumbered commits found in 'refs/heads/some-branch'
> remote: Please remove the following commits and try again:
> remote:   01ac47fe Some commit message
> remote:   ca40f33f Another commit message
> To [email protected]:/srv/git/emacs.git
>  ! [remote rejected] some-branch -> some-branch (pre-receive hook declined)
> error: failed to push some refs to '[email protected]:/srv/git/emacs.git'

I've lightly tested this with some local repositories pointing to each 
other, and everything seems to work. However, a bit more testing/review 
from the resident Git experts would probably be wise before we install this.
pre-receive (text/plain, 3.1 KB)
#!/bin/bash
# Check the incoming commits to reject LLM-encumbered changes.

# Copyright 2026 Free Software Foundation, Inc.

# This file is part of GNU Emacs.

# GNU Emacs is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# GNU Emacs is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.

### Commentary:

# This hook runs before receiving commits from a client and checks that
# none of the commits contain any LLM attributions. Specifically, this
# checks that none of the author, committer, or the Co-Authored-By or
# Co-Developed-By fields contain an email address associated with an
# LLM. Additionally, it rejects all commits with Assisted-By or
# AI-Assisted fields.

### Code:

# A list of LLM-associated email addresses to reject.
BAD_EMAILS="\
[email protected]
[email protected]
[email protected]"

NULL_REF="0000000000000000000000000000000000000000"

set -e

# Prefer gawk if available, as it handles NUL bytes properly.
if type gawk >/dev/null 2>&1; then
  awk="gawk"
else
  awk="awk"
fi

while read old_oid new_oid ref_name; do
  if [ "$new_oid" = "$NULL_REF" ]; then # Deleted the ref.
    continue
  fi

  # Get a list of all the SHAs not reachable from some already-present
  # commit and validate them.
  git rev-list $new_oid --not --all | \
    awk -v bad_emails="$BAD_EMAILS" -v ref="$ref_name" $'
      function check_email(email_line) {
        # Returns non-zero if the line contains a bad email address.
        for (i in BAD_EMAILS) {
          if (index(email_line, BAD_EMAILS[i]))
            return 1
        }
        return 0
      }

      function check_commit(commit_sha,    header) {
        # Returns non-zero if the commit contains any LLM attributions.
        cmd = ("git show -s --format=\'Author: %ae%nCommitter: %ce%n%B\' " \
               commit_sha)
        while ((cmd | getline) > 0) {
          header = tolower($1)
          if (header ~ /^(author|committer|co-(authored|developed)-by):$/ &&
              check_email($0)) {
            return 1
          }
          else if(header ~ /^(assisted-by|ai-assisted):$/) {
            return 1
          }
        }
        close(cmd)
        return 0
      }

      BEGIN {
        status = 0
        split(bad_emails, BAD_EMAILS, "\\n")
      }

      /^[a-z0-9]{40}$/ {
        commit = $0
        if (check_commit(commit)) {
          if (status == 0) {
            print("LLM-encumbered commits found in \'" ref "\'")
            print("Please remove the following commits and try again:")
          }
          system("git show -s --format=\'  %C(yellow)%h%Creset %s\' " commit)
          status = 1
        }
      }

      END {
        exit status
      }'
done