Skip to content

CI build attestation

Attest every CI build artifact automatically — GitHub Actions, CircleCI, GitLab CI, generic shell.

CI build attestation

This guide wires Vitrified into a CI pipeline so every build artifact you ship is automatically attested. The pattern is the same across CI vendors; the syntax varies.

The goal: for each release artifact your CI produces, your pipeline ends with a Vitrified proof bundle attached alongside it, so downstream consumers (your customers, your security team, future auditors) can verify the artifact independently against the public trust infrastructure.

GitHub Actions — the easy path

Use the official Vitrified Action. See GitHub Action for the full reference.

- uses: banchelabs/vitrified-action@v1
  with:
    api-key: ${{ secrets.VITRIFIED_API_KEY }}
    artifact: ./dist/release.tar.gz
    schema: slsa.provenance.v1

Generic — any CI runner

If your CI vendor isn't covered by an official action, use the CLI directly. The CLI is a single static binary:

# Install (cache in your CI runner image)
curl -L https://github.com/banchelabs/vitrified.glass/releases/latest/download/vitrified-linux-amd64 \
  -o /usr/local/bin/vitrified
chmod +x /usr/local/bin/vitrified

# Attest
vitrified attest ./dist/release.tar.gz \
  --schema slsa.provenance.v1 \
  --metadata @./slsa-provenance.json \
  --api-key "$VITRIFIED_API_KEY" \
  --output ./vitrified-bundle.json

# Verify what we just produced (defensive — fail the build if the bundle doesn't verify)
vitrified verify ./vitrified-bundle.json --output json | jq -e '.isVerified'

CircleCI

version: 2.1

jobs:
  release:
    docker:
      - image: cimg/base:current
    steps:
      - checkout
      - run:
          name: Build
          command: ./scripts/build.sh
      - run:
          name: Install vitrified CLI
          command: |
            curl -L https://github.com/banchelabs/vitrified.glass/releases/latest/download/vitrified-linux-amd64 \
              -o /usr/local/bin/vitrified
            chmod +x /usr/local/bin/vitrified
      - run:
          name: Attest release
          command: |
            vitrified attest ./dist/release.tar.gz \
              --schema slsa.provenance.v1 \
              --metadata @./slsa-provenance.json \
              --api-key "$VITRIFIED_API_KEY" \
              --output ./vitrified-bundle.json
      - store_artifacts:
          path: ./vitrified-bundle.json

GitLab CI

release:
  stage: release
  script:
    - ./scripts/build.sh
    - vitrified attest ./dist/release.tar.gz
      --schema slsa.provenance.v1
      --metadata @./slsa-provenance.json
      --api-key "$VITRIFIED_API_KEY"
      --output ./vitrified-bundle.json
  artifacts:
    paths:
      - ./vitrified-bundle.json
      - ./dist/release.tar.gz

Attaching the bundle to the artifact

For releases shipped to GitHub Releases, npm, PyPI, container registries, or anywhere else:

  • GitHub Release: attach vitrified-bundle.json alongside the artifact archive. Downstream users run vitrified verify ./vitrified-bundle.json to confirm.
  • OCI artifact: push the bundle as a referrer using oras or cosign attach. Downstream tools that follow OCI referrers automatically discover the attestation.
  • npm / PyPI: include the bundle filename in your release notes; consumers fetch and verify out-of-band.
  • Continuous sync (recommended): configure a Vitrified export so every attestation is mirrored to your own S3 / GCS / git destination as it's witnessed — no per-CI-job upload step needed.

Failing the build on weak attestation

vitrified verify ./vitrified-bundle.json --output json \
  | jq -e '.isVerified and (.mechanisms | to_entries | all(.value.status == "verified"))'

This fails the build unless every mechanism verified cleanly. Tune the predicate to match your policy (e.g., require eidas for regulated releases).

See also

Was this page helpful?