Integrating GitHub Actions

Wire Verdifax into a CI workflow so every model evaluation, every staging deployment, and every release artifact ships with a sealed manifest hash attached.

Pattern

The Verdifax orchestrator is reachable from the workflow runner over the network. You publish your manifest hash as a workflow output, attach it to a release, or post it to your model registry.

Example workflow

name: Attest model release

on:
  release:
    types: [created]

jobs:
  attest:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install verdifax
        run: pip install verdifax

      - name: Run model evaluation
        id: eval
        run: |
          python eval.py > /tmp/eval-output.txt
          echo "output_path=/tmp/eval-output.txt" >> $GITHUB_OUTPUT

      - name: Attest the evaluation
        id: attest
        env:
          VERDIFAX_API_URL: ${{ secrets.VERDIFAX_API_URL }}
          VERDIFAX_API_KEY: ${{ secrets.VERDIFAX_API_KEY }}
        run: |
          HASH=$(python -c "
          import verdifax
          with open('${{ steps.eval.outputs.output_path }}') as f:
              receipt = verdifax.attest(
                  payload=f.read(),
                  program_id='${{ vars.VERDIFAX_PROGRAM_ID }}',
                  route_id='ci-release',
                  registry_record_hash='${{ vars.VERDIFAX_REGISTRY_RECORD_HASH }}',
              )
              print(receipt.manifest_hash)
          ")
          echo "manifest_hash=$HASH" >> $GITHUB_OUTPUT
          echo "::notice title=Verdifax seal::$HASH"

      - name: Attach hash to release
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.repos.updateRelease({
              owner: context.repo.owner,
              repo: context.repo.repo,
              release_id: context.payload.release.id,
              body: context.payload.release.body +
                    "\n\n**Verdifax seal:** `${{ steps.attest.outputs.manifest_hash }}`"
            });

Secrets and vars to set

WhereNameWhat
Repository secretVERDIFAX_API_URLURL of your orchestrator
Repository secretVERDIFAX_API_KEYAPI key issued for CI use
Repository varVERDIFAX_PROGRAM_ID64-char hex program identifier
Repository varVERDIFAX_REGISTRY_RECORD_HASH64-char hex registry record hash

What you get

Every release ships with a manifest hash glued into its description. Anyone holding the run's audit bundle can check it with the open-source verifier, which recomputes every section hash from the bundle's own fields and confirms every section is bound to that manifest hash, showing the sealed evaluation result was not edited after the fact. Re-running the same evaluation produces a new run with a different hash, because each run seals its own admission clock and per-run nonce.

Continue