Verify commit signatures using Auths identity keys. Ensures every commit in a PR or push is cryptographically signed by an authorized developer.
permissions:
contents: read # verification needs nothing more
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2" # pin the CLI — the action never resolves `latest`That's it. The action auto-detects the commit range from the GitHub event (PR or push), downloads the pinned auths CLI (SHA256-checksum verified — it fails closed if the release has no checksum), and verifies each commit with auths verify. Verification is KEL-native: the signer is read from each commit's Auths-Id/Auths-Device trailers and checked against its key history (KEL). For stateless CI, pass an identity bundle via the identity-bundle input.
Add this file to your repo to start enforcing signed commits on every PR:
# .github/workflows/verify.yml
name: Verify Commits
on: [pull_request]
permissions:
contents: read # least privilege — no id-token, no write
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2" # pin the CLI version (required)
fail-on-unsigned: truePin the CLI.
auths-versionmust be set to a released version that publishes a.sha256(e.g.0.1.2). The action refuses to resolvelatestand fails closed if the binary cannot be checksum-verified — supply-chain hardening for a tool whose entire job is trust. (Ifauthsis already onPATH, the version is not needed.)
That's it for verifying against the local identity store. For stateless CI (no ~/.auths on the runner), commit an identity bundle and point the identity-bundle input at it — see Identity Bundle below.
- KEL-native commit verification: reads the
Auths-Id/Auths-Devicetrailers and checks the signature against the signer's key history (KEL) - Stateless CI via identity bundles — no
~/.authsorssh-keygenneeded on the runner - Auto-detects commit range from pull request or push events
- Downloads and caches the
authsCLI automatically (with SHA256 checksum verification) - Skips merge commits by default
- Gracefully handles GPG-signed commits (skips rather than fails)
- Generates a GitHub Step Summary with per-commit results table and a "How to fix" section when verification fails
- Classifies failures (unsigned, unknown signer, corrupted signature) with copy-pasteable fix commands
- Optionally posts results directly to the PR as a comment (
post-pr-comment: true) - Pre-flight check: detects shallow clones
| Input | Description | Required | Default |
|---|---|---|---|
identity-bundle |
Identity bundle for stateless verification. Accepts: CI token JSON, identity bundle JSON, or a file path to a bundle. Empty → KEL-native verification against the local identity store | No | '' (KEL-native) |
commits |
Git commit range to verify (e.g. HEAD~5..HEAD) |
No | Auto-detected from event |
auths-version |
Auths CLI version to pin (e.g. 0.1.2). Required unless auths is on PATH; the action never resolves latest and fails closed without a verifiable .sha256 |
Yes (unless on PATH) | '' |
fail-on-unsigned |
Whether to fail the action if unsigned commits are found | No | true |
skip-merge-commits |
Whether to skip merge commits during verification | No | true |
post-pr-comment |
Post a PR comment with results and fix instructions (requires pull-requests: write) |
No | false |
github-token |
GitHub token for posting the PR comment (required when post-pr-comment: true) |
No | '' |
files |
Glob patterns for artifact files to verify, one per line | No | '' |
artifact-attestation-dir |
Directory containing .auths.json attestation files |
No | '' |
fail-on-unattested |
Fail the action if any artifact lacks a valid attestation | No | true |
The identity-bundle input auto-detects the format (bundle JSON, CI token JSON, or a file path to a bundle). When empty, verification is KEL-native against the local identity store. When only files is set with an identity bundle, commit verification is skipped automatically.
| Output | Description |
|---|---|
verified |
true if all commits passed verification |
results |
JSON array of per-commit verification results |
total |
Total number of commits checked |
passed |
Number of commits that passed verification |
failed |
Number of commits that failed verification |
artifacts-verified |
Whether all artifacts were verified (true/false) |
artifact-results |
JSON array of per-artifact verification results |
With an empty identity-bundle, the action runs auths verify against the local identity store. Each commit's Auths-Id/Auths-Device trailers identify the signer, and the signature is checked against the signer's key history (KEL). This works on a developer machine or any runner that has ~/.auths:
- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2" # pin the CLI (required on clean runners)CI runners don't have ~/.auths, so supply an identity bundle — a portable JSON file carrying the identity ID, public key, and authorization chain. Generate it once:
auths id export-bundle --alias main --output .auths/ci-bundle.json --max-age-secs 31536000Commit the bundle (it contains only public data) and reference the file:
- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2"
identity-bundle: '.auths/ci-bundle.json'Or store it as a GitHub secret and pass it inline — the action detects the JSON format automatically:
gh secret set AUTHS_IDENTITY_BUNDLE < .auths/ci-bundle.json- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2"
identity-bundle: ${{ secrets.AUTHS_IDENTITY_BUNDLE }}Bundles carry a freshness TTL (--max-age-secs); the action fails if a bundle is older than its TTL, so refresh it when it lapses or when keys rotate.
name: Verify Commits
on:
pull_request:
push:
branches: [main]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2"name: Verify Commits
on: [pull_request]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2"
identity-bundle: ${{ secrets.AUTHS_IDENTITY_BUNDLE }}- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2"
fail-on-unsigned: 'false'Post results (and a "How to fix" section) directly on the PR where contributors actually look:
jobs:
verify:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2"
post-pr-comment: 'true'
github-token: ${{ secrets.GITHUB_TOKEN }}- name: Verify commits
id: verify
uses: auths-dev/verify@v1
with:
auths-version: "0.1.2"
fail-on-unsigned: 'false'
- name: Gate a downstream step on verification
if: steps.verify.outputs.verified == 'true'
run: ./deploy.shStore in your org's .github repo at .github/workflows/auths-verify.yml:
name: Auths Verify
on:
workflow_call:
inputs:
mode:
description: 'warn or enforce'
type: string
default: 'enforce'
secrets:
AUTHS_IDENTITY_BUNDLE:
required: false
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: auths-dev/verify@v1
with:
auths-version: "0.1.2"
identity-bundle: ${{ secrets.AUTHS_IDENTITY_BUNDLE }}
fail-on-unsigned: ${{ inputs.mode == 'enforce' && 'true' || 'false' }}Then each repo opts in:
name: Verify
on: [pull_request]
jobs:
auths:
uses: your-org/.github/.github/workflows/auths-verify.yml@main
with:
mode: enforce
secrets: inheritfetch-depth: 0onactions/checkout(the action detects shallow clones and provides a fix message)- Commits must be signed with
auths sign(carryAuths-Id/Auths-Devicetrailers) - For stateless CI, an identity bundle (see Identity Bundle)
- Runs a pre-flight shallow-clone check
- Downloads and caches the
authsCLI binary (with SHA256 checksum verification) - Determines the commit range from the GitHub event context
- Runs
auths verify --json(KEL-native; adds--identity-bundlewhen a bundle is supplied) - Parses results, skipping merge commits and GPG-signed commits
- Writes a Markdown summary table to GitHub Step Summary
- Sets outputs and fails the workflow if unsigned commits are found (configurable)
Apache-2.0. See LICENSE.
- Auths - Decentralized identity for developers
- Auths CLI - Command-line tool
- Signing commits with Auths - Setup guide