GitLab CI

Integrate ScanRook into your GitLab CI/CD pipeline. Scan container images on every push, produce structured vulnerability reports, and gate merge requests on severity thresholds.

Complete pipeline

Copy this to .gitlab-ci.yml in the root of your repository.

.gitlab-ci.yml
stages:
  - build
  - scan

variables:
  SCANROOK_VERSION: "latest"

build-image:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker save $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -o image.tar
  artifacts:
    paths:
      - image.tar
    expire_in: 1 hour

scanrook-scan:
  stage: scan
  image: ubuntu:24.04
  dependencies:
    - build-image
  before_script:
    - apt-get update && apt-get install -y curl jq
    - curl -fsSL https://scanrook.sh/install | bash
  script:
    - |
      scanrook scan \
        --file ./image.tar \
        --mode deep \
        --format json \
        --out report.json
    - |
      echo "=== Scan Summary ==="
      jq '.summary' report.json
    - |
      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
  artifacts:
    paths:
      - report.json
    reports:
      dotenv: scanrook.env
    when: always
    expire_in: 30 days
  variables:
    NVD_API_KEY: $NVD_API_KEY

Stage breakdown

What each stage and job does.

build-image

Builds the Docker image and saves it as a tar file artifact. The docker:dind service provides Docker-in-Docker for the build. The tar is passed to the scan stage via GitLab artifacts.

scanrook-scan

Installs ScanRook via the shell installer, scans the saved image tar, prints the summary, and exits with code 1 if critical or high vulnerabilities are found. The JSON report is saved as an artifact with a 30-day retention.

Run only on merge requests

Limit scans to merge request pipelines to save CI minutes.

MR-only rule
scanrook-scan:
  stage: scan
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  # ... rest of job config

Caching between runs

Speed up scans by caching vulnerability API responses across pipeline runs.

Cache configuration
scanrook-scan:
  cache:
    key: scanrook-cache
    paths:
      - .scanrook-cache/
  variables:
    SCANNER_CACHE: "$CI_PROJECT_DIR/.scanrook-cache"
  # ... rest of job config

Set SCANNER_CACHE to a path inside $CI_PROJECT_DIR so GitLab can cache it between runs. The scanrook-cache key ensures the cache is shared across all branches.

Tips

Best practices for GitLab CI integration.

  • Store NVD_API_KEY as a CI/CD variable (Settings > CI/CD > Variables). Mark it as masked and protected.
  • Use when: always on the artifacts block so the report is saved even when the scan fails.
  • For large images, increase the artifact expiration on the build stage or use GitLab's container registry to avoid re-building.
  • Filter findings by confidence in the gate script to avoid failing on heuristic-only matches. Add select(.confidence == "ConfirmedInstalled") to the jq filter.
  • Consider running scanrook db update before the scan to pre-warm the cache, especially in cold environments without a persistent cache.