Skip to content

ci: harden email-guard — scan message trailers + run on push #1

ci: harden email-guard — scan message trailers + run on push

ci: harden email-guard — scan message trailers + run on push #1

Workflow file for this run

name: Email Guard
# Privacy guard: every commit's author AND committer must be the maintainer's GitHub
# no-reply, and no commit message may carry a personal-provider email (e.g. a
# `Co-authored-by:` trailer). Runs on pull requests AND on direct pushes to main.
# Make the "Commit email privacy" check a required status check on main.
on:
pull_request:
push:
branches: [main]
jobs:
email-guard:
name: Commit email privacy
runs-on: ubuntu-latest
env:
# Exact account only ("only my account"):
ALLOWED_EMAIL_PATTERN: '^32437578\+bntvllnt@users\.noreply\.github\.com$'
# Personal mail providers that must never appear in a commit message/trailer:
PERSONAL_PROVIDER_RE: '@(icloud|gmail|googlemail|hotmail|outlook|live|yahoo|ymail|proton|protonmail|aol|gmx|zoho|fastmail)\.'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Scan commit identities + message trailers for leaked emails
run: |
set -euo pipefail
# On a pull_request build, HEAD is GitHub's synthetic merge commit; the
# base..head range checks just the pushed commits. On push, before..sha.
if [ "${{ github.event_name }}" = "pull_request" ]; then
LOGARGS='${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}'
else
BEFORE='${{ github.event.before }}'
if [ -n "$BEFORE" ] && [ "$BEFORE" != "0000000000000000000000000000000000000000" ] && git rev-parse -q --verify "$BEFORE^{commit}" >/dev/null 2>&1; then
LOGARGS="$BEFORE..${{ github.sha }}"
else
LOGARGS="-1 ${{ github.sha }}"
fi
fi
echo "Scanning: git log $LOGARGS"
fail=0
# 1) author + committer must be the owner no-reply
ids=$(git log --format='%ae%n%ce' $LOGARGS | sort -u | grep -v '^$' || true)
echo "Identities:"; echo "$ids" | sed 's/^/ /'
while IFS= read -r e; do
[ -z "$e" ] && continue
if ! printf '%s' "$e" | grep -qE "$ALLOWED_EMAIL_PATTERN"; then
echo "::error::Disallowed author/committer email: $e (use your GitHub no-reply)"; fail=1
fi
done <<< "$ids"
# 2) no personal-provider email anywhere in the message bodies (e.g. Co-authored-by)
msgmails=$(git log --format='%B' $LOGARGS | grep -aoiE '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' | sort -u || true)
while IFS= read -r e; do
[ -z "$e" ] && continue
if printf '%s' "$e" | grep -qiE "$PERSONAL_PROVIDER_RE"; then
echo "::error::Personal email in a commit message/trailer: $e (strip Co-authored-by trailers)"; fail=1
fi
done <<< "$msgmails"
if [ "$fail" -ne 0 ]; then exit 1; fi
echo "OK — commit identities are the no-reply and no personal emails in messages."