Safeguard Docs
CI/CD Integration

Container images

Scan the container image your pipeline builds, for each environment (dev, staging, production), and fail the build on vulnerabilities

Container images

Add one step after your pipeline builds an image. It scans that image on the runner and records it in Safeguard under the image's repository (for example ghcr.io/acme/api), one version per environment and tag, such as prod-1.4.2.

safeguard ci scan --image "ghcr.io/acme/api:$TAG" --environment prod --wait --fail-on critical

In the app, every container registry card under Integrations (Amazon ECR, Docker Hub, Azure Container Registry, Google Artifact Registry, Harbor, JFrog, Nexus, Quay and the rest) has a Set up CI/CD button. Pick your CI, the image and the environments, and it gives you the steps.

Setup

  1. Get a secret key with scans:trigger and scans:read. Admins create one in the Set up CI/CD sheet or under Settings → Developer; others ask an admin.
  2. Store it in your CI as SAFEGUARD_API_KEY, the same way as for code scans: GitHub Actions, GitLab CI/CD, Bitbucket Pipelines, Jenkins, Azure Pipelines.
  3. Add the step after the image is built, in each environment's pipeline.

Environments

Use one step per environment, each with its own --environment: dev, staging, prod, or any name of letters, digits and dashes. Each environment's build is its own version, so you can see what runs where, and fail only where it matters, for example --fail-on critical in production and no --fail-on in development.

Image--environmentVersion
ghcr.io/acme/api:1.4.2prodprod-1.4.2
ghcr.io/acme/api:1.4.2stagingstaging-1.4.2
ghcr.io/acme/api:latestdevdev-<commit> (a latest or missing tag uses the build's commit)

Where the image is read from

  • The local Docker daemon, when the step runs on the machine that built the image. Nothing to set up.
  • A registry, otherwise. Set SAFEGUARD_REGISTRY_USERNAME and SAFEGUARD_REGISTRY_PASSWORD as CI secrets so the scan can pull it. On GitLab's own registry use $CI_REGISTRY_USER and $CI_REGISTRY_PASSWORD.

Only the results leave the runner. No repository integration is needed.

Example: GitHub Actions

      - name: Build
        run: docker build -t "ghcr.io/acme/api:${{ github.sha }}" .
      - name: Safeguard image scan (prod)
        env:
          SAFEGUARD_API_KEY: ${{ secrets.SAFEGUARD_API_KEY }}
          SAFEGUARD_INSTALL_DIR: ${{ runner.temp }}/safeguard-bin
          IMAGE: ghcr.io/acme/api:${{ github.sha }}
        run: |
          set -eu
          curl -fsSL https://cli.safeguard.sh/install | bash
          "$SAFEGUARD_INSTALL_DIR/safeguard" ci scan --image "$IMAGE" --environment prod --wait --fail-on critical

Options

FlagWhat it does
--image <ref>The image to scan. Implies an on-runner scan.
--environment <name>The environment this build is for; names the version.
--fail-on <severity>With --wait, fail on a vulnerability at or above critical, high, medium or low.
--project <name>Record under another project instead of the image repository.

Troubleshooting

MessageWhat to do
reading image …The image is not in the local daemon and could not be pulled. Set the registry credentials, or run the step where the image was built.
BAD_ENVIRONMENTUse letters, digits and dashes, like prod.
--image and --path are two different targetsPass one: --image for an image, --local --path for code.

Other errors are listed in CI/CD Integration.

On this page