CI integration

attest verify is built to gate CI and agent loops: it exits non-zero when a commit lacks the trust a policy demands. This guide covers running it on macOS and Linux, the bundled attest-verify composite action, the augur to attest trust pipeline, and exporting an audit trail for compliance.

Platform. attest supports macOS and Linux. The composite action runs on any runner with a Swift 6 toolchain (macos-latest, or a Linux swift:6.0 container). Windows is out of scope.

Running the binary directly

The simplest integration is to build attest and run verify against your range:

jobs:
  trust:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0          # need history for the range
      - run: git fetch origin "refs/notes/*:refs/notes/*"   # pull attestation notes
      - run: swift build -c release
      - run: .build/release/attest verify --range origin/main..HEAD --policy .attest.json

Two details matter:

  • Fetch the notes. Attestations live in refs/notes/attest. They are not fetched by a plain checkout, so pull them explicitly with git fetch origin "refs/notes/*:refs/notes/*" (and push them on the producing side with git push origin "refs/notes/*").
  • Enough history. A range like origin/main..HEAD needs the commits on both sides, so set fetch-depth: 0 (or a depth large enough for the PR).

The attest-verify action

The repository ships a GitHub Action (action.yml) you can drop into any repo. It installs a prebuilt attest for the runner (macOS universal or Linux x86_64) from the matching release, then runs attest verify against your checkout — no Swift toolchain required. On other platforms it falls back to building attest from its own source:

jobs:
  trust:
    runs-on: ubuntu-latest        # or macos-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }   # range needs history
      - uses: CorvidLabs/attest@v0   # pin to the major tag, not @main
        with:
          range: origin/main..HEAD   # default
          policy: .attest.json       # default
          working-directory: .       # default
InputDefaultDescription
rangeorigin/main..HEADgit range to verify (needs full history).
policy.attest.jsonpolicy file path, relative to working-directory.
working-directory.directory to run attest verify in.
version(action ref)attest release to install (v0.3.0 or latest); defaults to the pinned tag, else latest.

The single output is binary (path to the attest used); the gate’s contract is the exit code. A policy violation propagates attest’s non-zero exit and fails the job. Prebuilt binaries cover GitHub-hosted macOS and Linux x86_64 runners; other runners need a Swift toolchain.

Honest scope. The action builds attest from its own checkout with swift build -c release. Cross-repo packaging (shipping a prebuilt binary and installing it into other repos without a Swift toolchain) is a deferred later step.

The augur → attest trust pipeline

augur scores diff risk and emits a verdict (proceed / review / block) with a risk score. That verdict is ephemeral; attest makes it durable. They compose over a pipe; attest never links augur:

# An agent scores the diff, records the verdict as an attestation, then gates on the policy:
augur check --range main..HEAD --json \
  | attest sign --commit HEAD --reviewer agent:claude --from-augur - --tests-passed

attest verify --commit HEAD || echo "trust policy not satisfied, escalating to a human"

--from-augur copies augur’s verdict and maps its riskScore (0…100) to confidence = 1 − riskScore/100. In an agent loop this turns a risk score into a recorded, optionally-signed trust artifact that the next step, or a human, can verify. A typical loop:

  1. augur check --json scores the change.
  2. attest sign --from-augur - records the verdict + confidence as an attestation (signed if the agent holds a key).
  3. attest verify gates: a review/block verdict under a policy with requireHumanApprovalWhenVerdictAtLeast exits non-zero until a human files a separate --human-approved sign-off, so the agent escalates instead of merging blind.

Pair the policy with maxAgeDays (see Policy reference) so a stale verdict from a previous run cannot keep clearing today’s commit.

Exporting an audit trail for compliance

attest export produces a single, stable JSON document covering the complete provenance trail across a range: every commit, every attestation, each record’s cryptographic verification status, and (with --policy) a per-commit pass/fail. It is deterministic (sorted keys; commits oldest-first), so it diffs cleanly and is suitable for archival.

A natural CI step archives the trust trail alongside the build artifacts:

      - run: |
          .build/release/attest export \
            --range origin/main..HEAD \
            --policy .attest.json \
            --no-pretty > audit.json
      - uses: actions/upload-artifact@v4
        with:
          name: attest-audit
          path: audit.json

export folds in verify’s policy verdict and the per-record signature checks, across the full range, in one machine-stable file: the durable record an auditor keeps. See CLI reference for the document shape and examples/05-audit-export.sh for an end-to-end run.