Skip to content

feat(audit): weekly cross-org unsigned-commit canary with Slack alert#305

Closed
JacobPEvans wants to merge 1 commit into
mainfrom
feat/audit-unsigned-commits
Closed

feat(audit): weekly cross-org unsigned-commit canary with Slack alert#305
JacobPEvans wants to merge 1 commit into
mainfrom
feat/audit-unsigned-commits

Conversation

@JacobPEvans
Copy link
Copy Markdown
Owner

Summary

  • New audit-unsigned-commits.yml runs Monday 13:17 UTC; sweeps default branches + JacobPEvans/JacobPEvans output branch across JacobPEvans + dryvist for verified:false commits in the last 7 days
  • Posts to #github-ci-failures and fails the workflow when offenders are found
  • Reuses existing GH_SLACK_WEBHOOK_URL_GITHUB_CI_FAILURES secret (already distributed)

Why this layer

Defense-in-depth canary behind:

  1. Repository Rulesets required_signatures — push-time rejection
  2. _signed-commits-check.yml — PR-time rejection
  3. no-runner-git-commit pre-commit hook — author-time rejection

If any one of those silently regresses, this catches it within 7 days and pages via Slack.

Test plan

Companions in initiative

Plan: ~/.claude/plans/you-are-opus-on-breezy-valiant.md

Assisted-by: Claude noreply@anthropic.com

Adds a Monday-morning sweep of both JacobPEvans + dryvist that lists
every default-branch (and JacobPEvans/JacobPEvans output) commit from
the last 7 days whose GitHub signature isn't verified. Any hits get
posted to #github-ci-failures and fail the workflow run.

This is the final canary behind the other three defense layers:
  1. Repository Rulesets with required_signatures — push-time rejection
  2. _signed-commits-check.yml in shared _ci-gate — PR-time rejection
  3. no-runner-git-commit pre-commit hook — author-time rejection
If any of those silently regress, this audit catches it within at
most window_days.

The script is intentionally tolerant of 404 (branch doesn't exist on
this repo) and 409 (empty repo) — neither is an audit failure, just
a no-op. Both expected when the EXTRA_BRANCHES list includes a branch
that lives on only one of the swept repos.

Reuses GH_SLACK_WEBHOOK_URL_GITHUB_CI_FAILURES, already distributed
to this repo via secrets-sync.

Part 7 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>
Copilot AI review requested due to automatic review settings May 12, 2026 21:51
@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 introduces a defense-in-depth security measure by implementing a weekly automated audit of commit signatures across specified organizations. By scanning default and designated branches for unsigned commits, the new workflow provides a critical safety net to catch any regressions in existing commit-signing enforcement policies, alerting the team via Slack and failing the CI job if non-compliant commits are identified.

Highlights

  • Automated Audit Script: Added a new JavaScript audit script to scan repositories for unsigned commits within a configurable lookback window.
  • Slack Integration: Implemented Slack alerting to notify the team via a webhook when unsigned commits are detected.
  • CI Workflow Enforcement: Configured the script to fail the GitHub Actions workflow upon discovery of unsigned commits, ensuring visibility and immediate action.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/audit-unsigned-commits.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.


A script to watch the code we write, / To keep our commits signed and bright. / If unsigned work should slip the gate, / We'll know it fast and seal its fate.

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 a scheduled “canary” workflow to audit recent commits across multiple orgs/repos for verified:false signatures, alerting Slack and failing the run when offenders are detected. This fits the repo’s broader “defense-in-depth” approach to preventing unsigned automated commits.

Changes:

  • New scheduled + manually-dispatchable workflow to run the audit weekly (with configurable org list and lookback window).
  • New actions/github-script-invoked Node script that enumerates repos/branches, collects unsigned commits, posts a Slack alert, and writes an Actions job summary.

Reviewed changes

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

File Description
.github/workflows/audit-unsigned-commits.yml Adds the scheduled workflow that checks out and runs the audit script with Slack alerting.
.github/scripts/audit-unsigned-commits/run.js Implements the cross-org repo/branch sweep, summary output, Slack post, and failure behavior.

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

EXTRA_BRANCHES: '{"JacobPEvans/JacobPEvans": ["output"]}'
SLACK_WEBHOOK_URL: ${{ secrets.GH_SLACK_WEBHOOK_URL_GITHUB_CI_FAILURES }}
SLACK_CHANNEL_NAME: '#github-ci-failures'
with:
Comment on lines +40 to +50
async function listUnsignedCommitsOnBranch(github, owner, repo, branch, since) {
let commits;
try {
commits = await github.paginate(github.rest.repos.listCommits, {
owner, repo, sha: branch, since, per_page: 100,
});
} catch (err) {
if (err.status === 404 || err.status === 409) {
// 404: branch doesn't exist on this repo. 409: empty repo.
return [];
}

const ORGS = (process.env.ORGS || 'JacobPEvans,dryvist')
.split(',').map((s) => s.trim()).filter(Boolean);
const AUDIT_WINDOW_DAYS = Number.parseInt(process.env.AUDIT_WINDOW_DAYS || '7', 10);
Comment on lines +29 to +37
try {
return await github.paginate(github.rest.repos.listForUser, {
username: owner, per_page: 100, type: 'owner',
}).then((repos) => repos.filter((r) => !r.archived));
} catch {
return await github.paginate(github.rest.repos.listForOrg, {
org: owner, per_page: 100,
}).then((repos) => repos.filter((r) => !r.archived));
}
.addRaw(`<p>Scanned ${ORGS.join(', ')}, window since ${since}.</p>`);

if (offenders.length === 0) {
summary.addRaw('<p><strong>No unsigned commits found.</strong> All automated and human commits in the window are GitHub-verified.</p>').write();
@JacobPEvans
Copy link
Copy Markdown
Owner Author

This is a terrible solution. GitHub does all of this natively with a couple checkboxes.

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