CI/CD integration

Generate, verify, analyze, and upload an SBOM in a GitHub Actions workflow, failing the build on fail-build violations.

This tutorial adds Observer CLI to a GitHub Actions workflow. On every run, the workflow generates an SBOM, checks it against your namespace's policies, and uploads it. A violation with the fail-build action fails the build, and the SBOM is not uploaded.

The same four CLI commands work on any CI/CD platform that can run the observer binary. GitHub Actions is the worked example here.

Pipeline steps

Generate SBOMobserver fs
Verify structureobserver verify
fail-build violation?observer analyze --fail
Build failsnon-zero exit code
Upload to SBOM Observerobserver upload

Setup

Create an access token

Sign in to SBOM Observer, open the user menu in the lower-left corner, select Access Tokens, and create a token. Store it as a repository secret named OBSERVER_TOKEN. If the namespace isn't called default, also add a repository variable OBSERVER_NAMESPACE with its name, the part of the app URL after /workspace/. See Access tokens.

Add the workflow

Save the workflow below as .github/workflows/sbom-observer.yml. It downloads the latest Observer CLI release on each run, so the runner needs nothing preinstalled.

Push and check the run

Push a commit. In the run log, the Analyze SBOM against policies step prints the vulnerabilities and policy violations it found. The uploaded SBOM appears on the Attestations page in SBOM Observer.

GitHub Actions workflow

.github/workflows/sbom-observer.yml
name: SBOM Observer

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  sbom:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download Observer CLI
        run: |
          curl -fsSL https://github.com/sbom-observer/observer-cli/releases/latest/download/observer_Linux_x86_64.tar.gz | tar xz observer

      - name: Generate SBOM
        run: ./observer fs -o sbom.cdx.json .

      - name: Verify SBOM
        run: ./observer verify sbom.cdx.json

      - name: Analyze SBOM against policies
        env:
          OBSERVER_TOKEN: ${{ secrets.OBSERVER_TOKEN }}
          OBSERVER_NAMESPACE: ${{ vars.OBSERVER_NAMESPACE }}
        run: ./observer analyze --fail sbom.cdx.json

      - name: Upload SBOM to Observer
        if: success()
        env:
          OBSERVER_TOKEN: ${{ secrets.OBSERVER_TOKEN }}
          OBSERVER_NAMESPACE: ${{ vars.OBSERVER_NAMESPACE }}
        run: ./observer upload sbom.cdx.json

The workflow runs on pushes to main and develop and on pull requests to main.

  • analyze --fail exits with code 1 when a policy violation has the fail-build action, which fails the job. Violations without that action are printed, and the job continues.
  • if: success() skips the upload when an earlier step failed, so the namespace only holds SBOMs from builds that passed.
  • Both steps that talk to SBOM Observer read the token from secrets.OBSERVER_TOKEN and the namespace from vars.OBSERVER_NAMESPACE. An unset variable is empty, and the CLI then uses default.

Next steps