GitHub Actions

Integrate ScanRook into your GitHub Actions CI pipeline to scan container images on every push or pull request. Gate deployments on critical CVEs and upload reports as build artifacts.

Complete workflow

Copy this workflow to .github/workflows/scanrook.yml in your repository.

.github/workflows/scanrook.yml
name: ScanRook Vulnerability Scan

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

permissions:
  contents: read
  security-events: write

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

      - name: Install ScanRook
        run: curl -fsSL https://scanrook.sh/install | bash

      - name: Build container image
        run: |
          docker build -t myapp:ci .
          docker save myapp:ci -o myapp.tar

      - name: Pre-warm vulnerability cache
        run: scanrook db update --source all
        env:
          NVD_API_KEY: ${{ secrets.NVD_API_KEY }}

      - name: Scan container image
        run: |
          scanrook scan \
            --file ./myapp.tar \
            --mode deep \
            --format json \
            --out report.json
        env:
          NVD_API_KEY: ${{ secrets.NVD_API_KEY }}

      - name: Upload scan report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: scanrook-report
          path: report.json

      - name: Fail on critical or high CVEs
        run: |
          CRITICAL=$(jq '.summary.critical // 0' report.json)
          HIGH=$(jq '.summary.high // 0' report.json)
          echo "Critical: $CRITICAL, High: $HIGH"
          if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
            echo "::error::Found $CRITICAL critical and $HIGH high severity vulnerabilities"
            jq '.findings[] | select(.severity == "CRITICAL" or .severity == "HIGH") | {cve, package: .package.name, version: .package.version, severity, confidence}' report.json
            exit 1
          fi

Step breakdown

What each step does and how to customize it.

Install ScanRook

The shell installer auto-detects the platform and downloads the latest release binary. The binary is placed in /usr/local/bin and is immediately available for subsequent steps.

Build and save image

ScanRook scans saved Docker images (tar files), not running containers. Use docker save to export the image after building.

Pre-warm cache

Optional but recommended. Pre-warming the vulnerability cache before scanning reduces API calls and speeds up the scan. Set NVD_API_KEY as a repository secret for higher NVD rate limits.

Scan and report

The scan produces a JSON report. The workflow uploads it as a build artifact so it is available for download on every run.

Fail on critical/high CVEs

The final step reads the summary from the JSON report and fails the workflow if any critical or high severity findings are present. Adjust the threshold by changing the jq filter.

SBOM diff gate

Optional: compare SBOMs across PRs and enforce a policy on package changes.

SBOM diff workflow
name: SBOM Diff Gate

on:
  pull_request:
    branches: [main]

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

      - name: Install ScanRook
        run: curl -fsSL https://scanrook.sh/install | bash

      - name: Build and save image
        run: |
          docker build -t myapp:pr .
          docker save myapp:pr -o myapp.tar

      - name: Generate current SBOM
        run: |
          scanrook container --tar ./myapp.tar --sbom --format json --out current-report.json

      - name: Download baseline SBOM
        uses: actions/download-artifact@v4
        with:
          name: baseline-sbom
          path: .
        continue-on-error: true

      - name: Diff SBOMs
        if: hashFiles('baseline-sbom.json') != ''
        run: |
          scanrook sbom diff \
            --baseline ./baseline-sbom.json \
            --current ./current-report.json \
            --json --out diff.json

      - name: Check policy
        if: hashFiles('diff.json') != ''
        run: |
          scanrook sbom policy \
            --policy ./scanrook-policy.yaml \
            --diff ./diff.json \
            --report ./current-report.json

This workflow compares the current SBOM against a baseline stored as a build artifact from the last main branch build. The scanrook sbom policy step exits with code 1 if the policy file is violated, failing the PR check.

Tips

Best practices for CI integration.

  • Store NVD_API_KEY as a repository or organization secret, not in the workflow file.
  • Use --mode deep for the most thorough scan. Use --mode light for faster feedback on PRs.
  • Cache the ~/.scanrook/cache/ directory between runs using actions/cache to speed up repeated scans.
  • Filter findings by confidence tier in your gate step: only fail on ConfirmedInstalled findings to avoid blocking on heuristic-only matches.
  • Use if: always() on the upload step so reports are saved even when the scan or gate step fails.