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 moresteps:
- uses: actions/checkout@v4with:
fetch-depth: 0
- uses: auths-dev/verify@v1with:
auths-version: "0.1.3"# 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 pinnedauths 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.ymlname: Verify Commitson: [pull_request]permissions:
contents: read # least privilege — no id-token, no writejobs:
verify:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4with:
fetch-depth: 0
- uses: auths-dev/verify@v1with:
auths-version: "0.1.3"# 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.3). 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.3). 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@v1with:
auths-version: "0.1.3"# 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@v1with:
auths-version: "0.1.3"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@v1with:
auths-version: "0.1.3"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 Commitson:
pull_request:
push:
branches: [main]jobs:
verify:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4with:
fetch-depth: 0
- uses: auths-dev/verify@v1with:
auths-version: "0.1.3"name: Verify Commitson: [pull_request]jobs:
verify:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4with:
fetch-depth: 0
- uses: auths-dev/verify@v1with:
auths-version: "0.1.3"identity-bundle: ${{ secrets.AUTHS_IDENTITY_BUNDLE }}- uses: auths-dev/verify@v1with:
auths-version: "0.1.3"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-latestpermissions:
contents: readpull-requests: writesteps:
- uses: actions/checkout@v4with:
fetch-depth: 0
- uses: auths-dev/verify@v1with:
auths-version: "0.1.3"post-pr-comment: 'true'github-token: ${{ secrets.GITHUB_TOKEN }}- name: Verify commitsid: verifyuses: auths-dev/verify@v1with:
auths-version: "0.1.3"fail-on-unsigned: 'false'
- name: Gate a downstream step on verificationif: steps.verify.outputs.verified == 'true'run: ./deploy.shStore in your org's .github repo at .github/workflows/auths-verify.yml:
name: Auths Verifyon:
workflow_call:
inputs:
mode:
description: 'warn or enforce'type: stringdefault: 'enforce'secrets:
AUTHS_IDENTITY_BUNDLE:
required: falsejobs:
verify:
runs-on: ubuntu-lateststeps:
- uses: actions/checkout@v4with:
fetch-depth: 0
- uses: auths-dev/verify@v1with:
auths-version: "0.1.3"identity-bundle: ${{ secrets.AUTHS_IDENTITY_BUNDLE }}fail-on-unsigned: ${{ inputs.mode == 'enforce' && 'true' || 'false' }}Then each repo opts in:
name: Verifyon: [pull_request]jobs:
auths:
uses: your-org/.github/.github/workflows/auths-verify.yml@mainwith:
mode: enforcesecrets: 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