Scan with GitLab CI

DevGuard provides reusable GitLab CI components that you can include in your .gitlab-ci.yml to add security scanning with minimal configuration. Each component is a self-contained job definitionyou pick what you need and pass your DevGuard credentials as inputs.

Prerequisites

  • A DevGuard account and an asset created for your repository
  • A DevGuard Personal Access Token with the scan scopecreate one under User SettingsPersonal Access Tokens
  • The asset name in the format @<org>/projects/<project>/assets/<asset> (visible in the asset settings)

Store both values as GitLab CI/CD variables in your project:

VariableValue
DEVGUARD_TOKENYour PAT private key
DEVGUARD_ASSET_NAMEe.g. @myorg/projects/backend/assets/api

Quick start: full pipeline

The full component wires together all scanning jobs and the complete container lifecycle in one include. It's the fastest way to get a complete DevSecOps pipeline:

stages:
  - test
  - oci-image
  - attestation

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/full.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"

This adds the following jobs to your pipeline:

  • devguard:secret_scanningdetect leaked secrets with Gitleaks
  • devguard:static_application_security_testingSAST on your source code
  • devguard:infrastructure_as_code_scanningscan IaC files for misconfigurations
  • devguard:software_composition_analysisscan dependencies for known CVEs
  • devguard:generate_tagdevguard:build_oci_imagedevguard:container_scanningdevguard:push_oci_imagedevguard:sign_oci_imagedevguard:attest

Individual scanning components

Secret scanning

Detects secrets, API keys, and credentials in your repository using Gitleaks.

stages:
  - test

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/secret-scanning.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"

SAST

Analyzes source code for security vulnerabilities without executing it.

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/static-application-security-testing.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"

Infrastructure-as-Code scanning

Scans Terraform, Kubernetes manifests, Docker configurations and other IaC files for misconfigurations.

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/infrastructure-as-code-scanning.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"

Software Composition Analysis (SCA)

Scans your dependencies for known vulnerabilities. Fails the pipeline if findings meet or exceed fail_on_risk / fail_on_cvss.

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/software-composition-analysis.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      fail_on_risk: "critical"   # none | low | medium | high | critical
      fail_on_cvss: "critical"   # none | low | medium | high | critical

Container scanning

Scans a container image for vulnerabilities. Accepts either a local tar file (from a previous build job) or a remote image from a registry.

Scan a local tar artifact:

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/container-scanning.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      image_tar_path: "image.tar"

Scan a remote image from the registry:

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/container-scanning.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      image_tag: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"

If both image_tag and image_tar_path are provided, image_tag takes precedence.


Container lifecycle

For projects that build and push container images, the container-lifecycle component handles the complete workflow: tag generationbuild (Kaniko) → container scanpushCosign signingin-toto attestation.

stages:
  - oci-image
  - attestation

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/container-lifecycle.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      build_args: "--context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile"

The image tag is generated automatically from the branch name, commit SHA, and timestamp. It is passed between all jobs via the $IMAGE_TAG variable. The image is only pushed after the container scan passes.


Bring your own scanner (upload components)

If you already run your own scanners, you can upload their output to DevGuard directly:

Upload a SARIF file (from any SAST tool):

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/sarif-upload.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      sarif_file: "results.sarif"

Upload an SBOM (CycloneDX JSON/XML):

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/sbom-upload.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_web_ui: "https://app.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      sbom_file: "sbom.json"

Upload a VEX document:

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/vex-upload.yml"
    inputs:
      devguard_api_url: "https://api.devguard.org"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      vex_file: "vex.json"

Common inputs reference

All components accept these shared inputs:

InputDefaultDescription
devguard_api_urlhttps://api.devguard.orgDevGuard API URL (change for self-hosted)
devguard_web_uihttps://app.devguard.orgDevGuard UI URL (used in job links)
devguard_asset_name$DEVGUARD_ASSET_NAMEAsset identifier
devguard_token$DEVGUARD_TOKENPAT private key
stagevaries per componentGitLab pipeline stage
allow_failurefalseLet the pipeline continue even if the job fails
fail_on_riskcriticalMinimum DevGuard risk level to fail the job (SCA/container scanning)
fail_on_cvsscriticalMinimum CVSS severity to fail the job (SCA/container scanning)
runner_tags[]GitLab runner tags
job_suffix""Append a suffix to job names — required when including the same component twice
pull_policyalwaysDocker image pull policy

Using the same component twice

To run the same component twice in one pipeline (e.g., scanning two separate paths in a monorepo), use job_suffix to avoid job name collisions:

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/software-composition-analysis.yml"
    inputs:
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      job_suffix: "-frontend"
      path: "$CI_PROJECT_DIR/frontend"

  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/software-composition-analysis.yml"
    inputs:
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"
      job_suffix: "-backend"
      path: "$CI_PROJECT_DIR/backend"

Self-hosted DevGuard

If you run DevGuard on your own infrastructure, replace the API and web UI URLs:

include:
  - remote: "https://gitlab.com/l3montree/devguard/-/raw/main/templates/full.yml"
    inputs:
      devguard_api_url: "https://devguard-api.example.com"
      devguard_web_ui: "https://devguard.example.com"
      devguard_asset_name: "$DEVGUARD_ASSET_NAME"
      devguard_token: "$DEVGUARD_TOKEN"