Skip to content

DevSecOps CI/CD Security Platform

Security gates from commit to registry

Production experience — sanitized case studyImplemented & validated locally

Basis: CV: embedded SonarQube, Snyk, container image scanning and automated testing into Jenkins, GitLab CI and GitHub Actions pipelines, blocking non-compliant builds. The published code is a reference implementation of that pattern — the application, findings and values are synthetic.

Overview

A pipeline that runs secrets scanning, SAST, dependency and image scanning, DAST against a preview environment and SBOM generation, and blocks promotion on policy failures.

Problem

Security reviews at the end of a release cycle find issues too late and become a bottleneck. Scanners that only report, never block, get ignored — and the CI system itself, with its tokens and third-party actions, is often the least-reviewed part of the supply chain.

Solution

One reusable workflow every service calls, with each gate in order of cost and severity thresholds as inputs. Exceptions must carry an expiry date. And the pipeline is hardened against attacks on CI itself: pinned actions, minimal token scopes, no persisted credentials, no script injection.

Architecture

  1. Source

    • Gitleaks

      secrets, with allowlist

    • Semgrep

      SAST → SARIF

    • Trivy fs / Snyk

      dependencies

  2. Build

    • Buildx image

      pinned base by digest

    • Trivy image

      fixable CRITICAL/HIGH block

  3. Supply chain

    • Syft SBOM

      SPDX + CycloneDX

    • Cosign keyless

      publish-gated

    • SLSA provenance

  4. Runtime & gate

    • OWASP ZAP baseline

      optional DAST

    • Summary gate

      step summary + SARIF

Gates run in parallel where possible; the summary gate blocks on any failure.

Technology stack

  • GitHub Actions (reusable workflow)
  • Gitleaks
  • Semgrep
  • SonarQube (optional)
  • Trivy
  • Snyk (optional)
  • Syft (SPDX + CycloneDX)
  • Cosign
  • SLSA provenance
  • OWASP ZAP

Implementation

  • A reusable workflow called with inputs for thresholds, DAST and Sonar; each job gets only the permissions it needs, and only SARIF-uploading jobs can write security events.
  • Every action is pinned to a commit SHA resolved from its real release tag — none from memory.
  • Scanners were run locally: the Trivy gate failed the first base image on 37 fixable findings, then passed after moving to a newer slim base and removing pip from the runtime image.
  • A workflow-hardening linter checks permissions, SHA pinning, pull_request_target misuse, script injection, job-scoped id-token and persisted credentials. Its first run over the whole repository found 39 errors and 46 warnings in other projects' workflows; all were fixed and the repository now lints clean.
  • A .trivyignore checker requires an expiry date and a reason on every exception and fails on expired ones.
  • 52 unit tests over every linter rule, the ignore-file checker and the demo app.

Security

  • Threat model for CI itself: poisoned pull requests, script injection through event fields, over-scoped tokens and compromised third-party actions.
  • Keyless signing and provenance mean consumers can verify where an image was built without managing signing keys.
  • Leaked-secret procedure: revoke first, then purge history — rotation is never skipped because history was rewritten.

Reliability

  • Image gate blocks on fixable findings only; unfixed ones are still reported in SARIF so they are visible without blocking every build.
  • Sonar and Snyk run only when their tokens exist, so the pipeline works for forks and new repositories.

Cost

  • Runner minutes dominate; caching the Trivy vulnerability database avoids re-downloading it on every job (see the cost doc).

Results

No quantified results are published for this project. Figures from client work are confidential, and this portfolio only shows numbers that can be verified or reproduced.

Code & documentation

Lessons learned

  • Start with blocking on critical only; ratchet thresholds once the backlog is cleared.
  • An exception process with expiry dates beats ad-hoc bypasses.
  • Point the security tooling at your own CI: the linter's first finding list was in this repository.
  • Known gaps, stated in the README: the workflows have not run on GitHub yet, and the DAST and signing jobs are unverified.