Building an End-to-End DevSecOps Pipeline (Trivy + Gitleaks + tfsec + SBOM)

end to end devsecops pipeline trivy gitleaks tfsec sbom custom-e2epipeline-featured.png

This blog has covered gitleaks, tfsec/Checkov, Trivy, and SBOM generation individually. This guide combines all four into a single, ordered CI/CD pipeline — commit to production — so each gate catches its category of problem before the next stage even starts, ending with an ArgoCD sync as the final deployment step.

Step 1: The Full Pipeline Shape

The pipeline runs as an ordered sequence of gates, each one blocking the next on failure: secrets scanIaC scanbuildimage scanSBOM generationpushdeploy. Ordering matters — catching a leaked secret before spending build minutes on an image that will fail scanning anyway saves pipeline time, and fixing IaC issues before image concerns keeps failure feedback focused on one category at a time.

Full end-to-end DevSecOps pipeline stage sequence
Step 1: The Full Pipeline Shape

Step 2: Secrets Scan Stage

First stage, runs against the commit before anything else: gitleaks detect --source . --exit-code 1. This is deliberately the very first gate — a leaked credential is the most urgent class of finding, and there’s no reason to spend compute building or scanning an image from a commit that already needs to be blocked and the secret rotated.

Secrets scan stage as first gate in DevSecOps pipeline
Step 2: Secrets Scan Stage

Step 3: IaC Scan Stage

If the repo includes Terraform (as with our Proxmox Terraform setup), run tfsec . and checkov -d . next, before any application build — infrastructure misconfigurations are independent of the application code and shouldn’t wait behind a build step to be caught.

IaC security scan stage in DevSecOps pipeline with tfsec Checkov
Step 3: IaC Scan Stage

Step 4: Build Stage

Only after both prior gates pass does the pipeline build the actual container image (docker build -t registry.example.com/app:$CI_COMMIT_SHA .) — building is often the slowest step, so gating it behind the fast secrets/IaC checks avoids wasting that time on commits that were already going to be rejected.

Build stage in DevSecOps pipeline after passing security gates
Step 4: Build Stage

Step 5: Image Scan Stage

Immediately after build: trivy image --severity CRITICAL,HIGH --exit-code 1 registry.example.com/app:$CI_COMMIT_SHA. This is the gate that catches vulnerable base images and dependencies baked into the container — failing here means the image never gets pushed to the registry at all.

Image vulnerability scan stage with Trivy in pipeline
Step 5: Image Scan Stage

Step 6: SBOM Generation Stage

Once the image passes scanning, generate its SBOM: syft registry.example.com/app:$CI_COMMIT_SHA -o cyclonedx-json > sbom.json, then upload it as a pipeline artifact or attach it to the image in Harbor. This runs after the scan gate, not before — no reason to catalog an image that just failed and won’t be pushed anyway.

SBOM generation stage after successful image scan
Step 6: SBOM Generation Stage

Step 7: Push and Deploy Stages

Push the now-scanned, now-catalogued image to the registry, then trigger deployment — in a GitOps flow, this typically means updating the image tag in the manifests repo that ArgoCD watches, letting ArgoCD’s own sync (automatic or triggered with argocd app sync) handle the actual cluster rollout rather than the CI pipeline pushing to Kubernetes directly.

Push and ArgoCD deploy stages completing DevSecOps pipeline
Step 7: Push and Deploy Stages

Step 8: Rolling This Out Without Breaking Every Build on Day One

Enabling every gate as a hard failure simultaneously on an existing codebase usually surfaces a backlog of pre-existing findings that blocks every single build immediately. Roll out in report-only mode first (run each tool, log findings, but don’t fail the build) for a week or two, triage the backlog with documented exceptions (.trivyignore, tfsec inline suppressions, gitleaks allowlist entries), and only then flip each gate to hard-fail once the baseline is actually clean.

Rolling out DevSecOps pipeline gates gradually without breaking builds
Step 8: Rolling This Out Without Breaking Every Build on Day One

Example combined GitLab CI pipeline

stages: [secrets-scan, iac-scan, build, image-scan, sbom, deploy]

secrets-scan:
  stage: secrets-scan
  script: gitleaks detect --source . --exit-code 1

iac-scan:
  stage: iac-scan
  script:
    - tfsec .
    - checkov -d .

build:
  stage: build
  script: docker build -t $IMAGE .

image-scan:
  stage: image-scan
  script: trivy image --severity CRITICAL,HIGH --exit-code 1 $IMAGE

sbom:
  stage: sbom
  script: syft $IMAGE -o cyclonedx-json > sbom.json
  artifacts: { paths: [sbom.json] }

deploy:
  stage: deploy
  script:
    - docker push $IMAGE
    - argocd app sync myapp

Related tutorials

Terminal screenshots are original illustrations created for Gnome IT Solutions (blog.gnomeitsolutions.com).