Skip to content

feat(ci): fail PRs containing unsigned commits via shared CI gate#302

Closed
JacobPEvans wants to merge 2 commits into
mainfrom
feat/signed-commits-ci-gate
Closed

feat(ci): fail PRs containing unsigned commits via shared CI gate#302
JacobPEvans wants to merge 2 commits into
mainfrom
feat/signed-commits-ci-gate

Conversation

@JacobPEvans
Copy link
Copy Markdown
Owner

Summary

  • New reusable workflow _signed-commits-check.yml fails any PR where a commit is verified:false
  • Wired into shared _ci-gate.yml so every downstream consumer gets it automatically
  • This is the PR-level regression backstop — layered behind branch-protection rulesets (PR Add reusable workflows for common CI/CD patterns #4 of the initiative)

Four-tier search log (no-scripts rule)

  • Tier 1 (Native CLIs): gh api repos/.../pulls/<n>/commits works, but pagination + JSON parsing + per-commit filter in bash exceeds the 10-line inline gate and is fragile.
  • Tier 2 (Ecosystem primitives): no off-the-shelf marketplace action exists for "fail PR on any unsigned commit". Closest match — actions/github-script@v9 — IS first-party GitHub and is what this workflow uses.
  • Tier 3 (Third-party packaged tools): none found.
  • Tier 4 (Popular community solutions): none found.

Script extracted to .github/scripts/signed-commits-check.js per the no-scripts rule (logic exceeds the 10-line inline limit; allowed .github/scripts/ directory).

Implementation notes

  • Failure path: core.setFailed with multi-line message listing each offending short-SHA, author, and verification.reason. core.summary also writes a markdown table to the job summary so failures are browsable in the GitHub UI.
  • Success path: core.info confirms N commits verified, summary writes a one-line confirmation.
  • Safe in non-PR contexts: script no-ops cleanly when context.payload.pull_request is absent.
  • The signed-commits job in _ci-gate.yml is gated on github.event_name == 'pull_request' and listed as an allowed-skip in re-actors/alls-green.

Verification (after merge)

  • Open a sacrificial PR with an intentionally unsigned commit (e.g. git commit --no-gpg-sign -m test) on a consumer repo
  • Confirm _ci-gate.yml fails with a clear message listing the offending SHA
  • Sign and force-push; confirm CI passes

Part of the 8-PR "eliminate unsigned automated commits" initiative.
Plan: ~/.claude/plans/you-are-opus-on-breezy-valiant.md

Assisted-by: Claude noreply@anthropic.com

Adds a new reusable workflow `_signed-commits-check.yml` that walks every
commit in the active pull request via `pulls.listCommits` and fails the
job if any commit returns `verification.verified === false`. Failures
emit a clear multi-line `core.setFailed` message plus a markdown table
in the GitHub-UI job summary listing each offending SHA, author, and
verification reason.

Wired into `_ci-gate.yml` as an always-on `signed-commits` job (gated
on `github.event_name == 'pull_request'`, listed as an allowed-skip in
`re-actors/alls-green` so non-PR runs aren't blocked).

This is PR #5 of the 8-PR "eliminate unsigned automated commits"
initiative — the PR-level regression backstop sitting behind the
`required_signatures` branch-protection rulesets (PR #4). Even if a
ruleset is bypassed (admin override, future ruleset edit), the PR can't
get a green Merge Gate without signed commits.

Four-tier search log (no-scripts rule):
- Tier 1 (Native CLIs): `gh api repos/.../pulls/<n>/commits` works but
  walking the response + paginating + parsing in bash is fragile and
  exceeds the 10-line inline gate.
- Tier 2 (Ecosystem primitives): no marketplace action exists for
  "fail PR on any unsigned commit"; closest match (`actions/github-script`)
  IS first-party GitHub and is what this workflow uses.
- Tier 3 (Third-party packaged tools): none found.
- Tier 4 (Popular community solutions): none found.

Script extracted to `.github/scripts/signed-commits-check.js` per the
no-scripts rule — exceeds the 10-line inline limit and lives in the
allowed `.github/scripts/` directory.

Assisted-by: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 21:38
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request implements a new security gate to enforce commit signing across the repository. By leveraging a reusable workflow and a custom script, it ensures that all commits within a pull request are cryptographically verified by GitHub. This change serves as a critical backstop for the ongoing initiative to eliminate unsigned automated commits, providing immediate feedback in the CI pipeline when non-compliant commits are detected.

Highlights

  • Automated Signature Enforcement: Introduced a new reusable workflow that validates all commits in a pull request are verified by GitHub (GPG, S/MIME, or SSH).
  • CI Integration: Integrated the signature check into the shared CI gate, ensuring all downstream consumers automatically inherit this security requirement.
  • Diagnostic Reporting: Implemented detailed failure reporting using GitHub Actions job summaries, providing a clear table of offending commits, authors, and verification reasons.
Ignored Files
  • Ignored by pattern: .github/workflows/** (2)
    • .github/workflows/_ci-gate.yml
    • .github/workflows/_signed-commits-check.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.


The commits must be signed and true, To pass the gate we built for you. If unsigned code should dare appear, The build will fail and make it clear.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

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

Adds an organization-wide CI backstop that fails pull requests containing any GitHub-unverified commits, ensuring downstream repos that use the shared merge gate can’t go green with unsigned commits.

Changes:

  • Introduced a reusable workflow (_signed-commits-check.yml) that runs a signed-commit verification gate for PRs.
  • Added a Node script (.github/scripts/signed-commits-check.js) executed via actions/github-script to paginate PR commits, detect verified:false, and emit clear failure output + job summary.
  • Wired the new check into _ci-gate.yml (and into Merge Gate aggregation) so all consumers inherit it automatically.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
.github/workflows/_signed-commits-check.yml New reusable workflow that checks PR commits’ verification status via actions/github-script.
.github/workflows/_ci-gate.yml Adds a new always-on signed-commits job (PR-only) and includes it in the merge gate aggregation/allowed skips.
.github/scripts/signed-commits-check.js Implements PR commit pagination + verification filtering and formats failure output in both logs and job summary.

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

Comment thread .github/scripts/signed-commits-check.js Outdated
…se-checkout path

The reusable workflow sparse-checks this script out of JacobPEvans/.github@main
into ./.gh-shared/.github/scripts/, so the require() path the YAML actually
uses includes that prefix. The header comment showed the in-tree path only,
which would mislead a future maintainer trying to copy the example. Document
both paths and which context each fits.

Addresses Copilot review thread on PR #302.

Assisted-by: Claude <noreply@anthropic.com>
@JacobPEvans
Copy link
Copy Markdown
Owner Author

This is not the right way to handle this. This can be done 100% natively by GitHub itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants