Skip to content

ci: fail pre-commit if commits contain generated trailers#1776

Open
leshy wants to merge 4 commits intodevfrom
ci/check-commit-message-trailers
Open

ci: fail pre-commit if commits contain generated trailers#1776
leshy wants to merge 4 commits intodevfrom
ci/check-commit-message-trailers

Conversation

@leshy
Copy link
Copy Markdown
Contributor

@leshy leshy commented Apr 11, 2026

Summary

we have a filter-commit-message hook that runs on commit-msg stage that rewrites commit msgs locally

added also check-commit-message that runs in a pre-commit stage that just fails you if the forbidden suffix is there. pre-commit stage is ran in CI so will block on CI level

Expand filter_commit_message.py with a --check mode that walks commits
in PRE_COMMIT_FROM_REF..PRE_COMMIT_TO_REF (HEAD locally) and exits
non-zero on any forbidden trailer. Wired as a pre-commit-stage hook so
CI catches contributors who lack the commit-msg hook.

Workflow now uses fetch-depth: 0 so the PR base SHA is reachable.
Copilot AI review requested due to automatic review settings April 11, 2026 03:53
@leshy leshy review requested due to automatic review settings April 11, 2026 03:54
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 11, 2026

Greptile Summary

This PR adds a --check mode to filter_commit_message.py that scans a commit range for forbidden AI-generated trailers (Generated with, Co-Authored-By), wires it as a pre-commit-stage hook, and bumps actions/checkout to fetch-depth: 0.

The core issue is that pre-commit/action@v3.0.1 runs with --all-files by default and does not invoke pre-commit with --from-ref/--to-ref, so PRE_COMMIT_FROM_REF and PRE_COMMIT_TO_REF are never set in CI. The range-scan code path is dead; CI will always fall back to inspecting only HEAD.

Confidence Score: 4/5

Mergeable but the stated CI range-check goal is not achieved without an extra_args fix in the workflow.

The P1 finding shows the primary design intent (scanning all PR commits in CI) is dead code — pre-commit/action@v3.0.1 uses --all-files by default and never sets PRE_COMMIT_FROM_REF/PRE_COMMIT_TO_REF, so CI always falls back to checking HEAD only. The hook is still incrementally useful, and all other code is clean and correct, but the stated goal requires a one-line extra_args fix in the workflow to activate.

bin/hooks/filter_commit_message.py (range-check code path) and .github/workflows/code-cleanup.yml (missing extra_args on the pre-commit action step)

Important Files Changed

Filename Overview
bin/hooks/filter_commit_message.py Adds commits_to_check() and check_commits() for --check mode; range scan relies on PRE_COMMIT_FROM_REF/PRE_COMMIT_TO_REF which are never set by the default CI action invocation, leaving the fallback (HEAD-only) as the de facto CI behavior.
.pre-commit-config.yaml Adds check-commit-message hook at pre-commit stage with always_run: true and pass_filenames: false; configuration is correct.
.github/workflows/code-cleanup.yml Bumps fetch-depth to 0 for full git history; the depth is needed for git rev-list from..to but that code path is unreachable without passing --from-ref/--to-ref to the pre-commit action.

Sequence Diagram

sequenceDiagram
    participant Dev as Developer
    participant PreCommit as pre-commit framework
    participant FilterHook as filter-commit-message
    participant CheckHook as check-commit-message
    participant CI as CI pre-commit/action
    participant Script as filter_commit_message.py

    Note over Dev,Script: Local commit with commit-msg hook installed
    Dev->>PreCommit: git commit
    PreCommit->>CheckHook: pre-commit stage checks HEAD only
    CheckHook->>Script: --check to commits_to_check to HEAD
    Script-->>CheckHook: OK
    PreCommit->>FilterHook: commit-msg stage
    FilterHook->>Script: rewrite_file COMMIT_EDITMSG
    Script-->>Dev: commit created clean

    Note over CI,Script: CI current no extra_args
    CI->>PreCommit: pre-commit run --all-files
    Note right of PreCommit: FROM_REF and TO_REF NOT set
    PreCommit->>CheckHook: always_run
    CheckHook->>Script: --check to HEAD only
    CheckHook-->>CI: passes or fails on HEAD only

    Note over CI,Script: Desired CI with extra_args
    CI->>PreCommit: pre-commit run --from-ref base --to-ref head
    Note right of PreCommit: FROM_REF and TO_REF ARE set
    PreCommit->>CheckHook: pre-commit stage
    CheckHook->>Script: --check to all PR commits
    CheckHook-->>CI: fails if any commit has forbidden trailer
Loading

Reviews (1): Last reviewed commit: "Merge branch 'dev' into ci/check-commit-..." | Re-trigger Greptile

pre-commit/action@v3.0.1 defaults extra_args to --all-files and never
injects from/to refs on its own, so PRE_COMMIT_FROM_REF / PRE_COMMIT_TO_REF
were never set in CI and the range walk always fell through to HEAD-only.
Pass the PR base/head explicitly via extra_args on both action steps.

Side effect: formatter hooks now run on changed files instead of all
files, which matches the intent of an auto-commit cleanup workflow.
Copilot AI review requested due to automatic review settings April 11, 2026 04:09
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the existing commit-msg hook that strips generated trailers from commit messages by adding a CI-enforced check that fails if any commits in the PR contain forbidden “generated” trailers.

Changes:

  • Refactored filter_commit_message.py into reusable functions and added a --check mode that scans commit messages in a commit range (CI) or HEAD (fallback).
  • Added a new local pre-commit hook (check-commit-message) to run the --check mode.
  • Updated the code-cleanup GitHub Actions workflow to fetch full history and run pre-commit over a base..head ref range.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
bin/hooks/filter_commit_message.py Adds --check mode to scan commits (range-aware in CI via env vars) and refactors filtering logic.
.pre-commit-config.yaml Adds check-commit-message hook at pre-commit stage to enforce the check.
.github/workflows/code-cleanup.yml Ensures full git history and passes --from-ref/--to-ref to pre-commit in CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- No-op the --check path when PRE_COMMIT_FROM_REF/TO_REF are unset, so
  the local pre-commit-stage hook can't block commits or amends on the
  state of an existing bad HEAD; locally the commit-msg hook is in
  charge. The check only fires meaningfully in CI where the workflow
  passes the explicit range.
- Wrap git rev-list / git log calls in try/except so a missing ref or
  shallow-clone failure surfaces as a one-line hook error instead of a
  Python traceback.
- Rename the hook to "Check commit messages for generated signatures"
  since it walks the full PR range, not just HEAD.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants