Files
computer-playbook/scripts/git/assert_merge_signed.sh
T
kevinveenbirkenbachandClaude Opus 4.8 bc047de312 feat(git): gate merges on signed incoming commits
A merge commit bypassed every signature check: test-signed only inspects
HEAD and the pre-commit hook does not run for merge commits. Add
scripts/git/assert_merge_signed.sh, which fails when any commit the merge
brings in (HEAD..MERGE_HEAD) reports %G? status N, wire it up as
make test-merge-signed, and register it as a pre-merge-commit hook so
pre-commit install now also installs that hook type.

Fast-forward merges create no commit and skip the hook (use --no-ff to
gate them); conflicted merges fall back to the regular pre-commit and
pre-push gates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 03:26:12 +02:00

24 lines
876 B
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Pre-merge-commit gate: every commit the merge brings in (HEAD..MERGE_HEAD)
# must carry a signature. `git log %G?` yields N for unsigned; any other
# status counts as signed, matching the test-signed HEAD gate.
git_dir="$(git rev-parse --git-dir)"
if [ ! -f "${git_dir}/MERGE_HEAD" ]; then
echo "❌ No merge in progress (MERGE_HEAD missing); this gate runs during git merge." >&2
exit 1
fi
unsigned="$(git log --pretty='%H %G? %s' HEAD..MERGE_HEAD | awk '$2 == "N"')"
if [ -n "${unsigned}" ]; then
echo "❌ Unsigned commit(s) coming in from the merged branch:" >&2
printf '%s\n' "${unsigned}" >&2
echo "Sign them (git rebase --exec 'git commit --amend --no-edit -S' or git-sign-push) and retry the merge." >&2
exit 1
fi
count="$(git rev-list --count HEAD..MERGE_HEAD)"
echo "✅ All ${count} incoming commit(s) are signed."