DevSecOps CI/CD Security Platform
Security gates from commit to registry
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
Source
Gitleaks
secrets, with allowlist
Semgrep
SAST → SARIF
Trivy fs / Snyk
dependencies
Build
Buildx image
pinned base by digest
Trivy image
fixable CRITICAL/HIGH block
Supply chain
Syft SBOM
SPDX + CycloneDX
Cosign keyless
publish-gated
SLSA provenance
Runtime & gate
OWASP ZAP baseline
optional DAST
Summary gate
step summary + SARIF
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.