feat(audit): weekly cross-org unsigned-commit canary with Slack alert#305
feat(audit): weekly cross-org unsigned-commit canary with Slack alert#305JacobPEvans wants to merge 1 commit into
Conversation
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>
Summary of ChangesHello, 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
Ignored Files
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this comment.
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: |
| 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); |
| 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(); |
|
This is a terrible solution. GitHub does all of this natively with a couple checkboxes. |
Summary
audit-unsigned-commits.ymlruns Monday 13:17 UTC; sweeps default branches +JacobPEvans/JacobPEvansoutputbranch across JacobPEvans + dryvist forverified:falsecommits in the last 7 days#github-ci-failuresand fails the workflow when offenders are foundGH_SLACK_WEBHOOK_URL_GITHUB_CI_FAILURESsecret (already distributed)Why this layer
Defense-in-depth canary behind:
required_signatures— push-time rejection_signed-commits-check.yml— PR-time rejectionno-runner-git-commitpre-commit hook — author-time rejectionIf any one of those silently regresses, this catches it within 7 days and pages via Slack.
Test plan
window_days=30to catch historical snake/3d-contrib unsigned commits → expect Slack post + red Actions run (proves alert path works)Companions in initiative
Plan:
~/.claude/plans/you-are-opus-on-breezy-valiant.mdAssisted-by: Claude noreply@anthropic.com