A production-grade, security-first CI/CD pipeline built with GitHub Actions — integrating SAST, SCA, secret scanning, container scanning, and DAST as automated security gates.
Author: Adarsh Singh | DevSecOps Engineer | SecurityWithAdarsh
- Architecture
- Pipeline Stages
- Security Tools
- Project Structure
- Quick Start
- Kubernetes Deployment
- Security Reports
- Secrets Management
- Contributing
┌─────────────────────────────────────────────────────────────────────────┐
│ GitHub Repository │
│ │
│ Code Push / PR │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────────┐ │
│ │ SAST │ │ SCA │ │ Secret │ │ Unit Tests │ │
│ │ Bandit │──▶│ Safety │──▶│ Scan │──▶│ + Code Coverage │ │
│ │ Semgrep │ │ pip-audit│ │ Gitleaks │ │ (pytest) │ │
│ │ CodeQL │ └──────────┘ └──────────┘ └────────┬───────────┘ │
│ └──────────┘ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Docker Build │ │
│ │ + Push GHCR │ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Container │ │
│ │ Scan (Trivy)│ │
│ └──────┬───────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ DAST (OWASP │ │
│ │ ZAP) │ │
│ └──────┬───────┘ │
│ │ │
│ ┌────────────────────────────┤ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ │
│ │ Staging │ │ Production │ │
│ │ (develop) │ │ (main) │ │
│ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
| # | Stage | Tools | Trigger | Gate |
|---|---|---|---|---|
| 1 | SAST | Bandit, Semgrep, CodeQL | Push/PR | ❌ Fails on Medium+ severity |
| 2 | SCA | Safety, pip-audit | Push/PR | ❌ Fails on known CVEs |
| 3 | Secret Scan | Gitleaks | Push/PR | ❌ Fails on any secret |
| 4 | Unit Tests | pytest + coverage | After SAST/SCA | ❌ Fails on test failure |
| 5 | Build | Docker Buildx, GHCR | After tests | Pushes signed image |
| 6 | Container Scan | Trivy | After build | ❌ Fails on CRITICAL/HIGH |
| 7 | DAST | OWASP ZAP | After container scan | |
| 8 | Deploy Staging | kubectl + Kustomize | develop branch |
Manual approval |
| 9 | Deploy Prod | kubectl + Kustomize | main branch |
Manual approval |
| Tool | What it Checks | Config |
|---|---|---|
| Bandit | Python security anti-patterns, hardcoded passwords, SQL injection | security/bandit/bandit.ini |
| Semgrep | Custom rules + community rulesets (flask, secrets, python) | security/semgrep/semgrep-rules.yml |
| CodeQL | Deep semantic code analysis by GitHub | .github/workflows/codeql.yml |
| Tool | What it Checks |
|---|---|
| Safety | Known CVEs in Python dependencies (PyPI advisory DB) |
| pip-audit | Vulnerability audit via OSV and PyPI advisories |
| GitHub Dependency Review | PR-level dependency diff with vulnerability flagging |
| Tool | What it Checks |
|---|---|
| Gitleaks | 150+ secret patterns: AWS keys, GCP tokens, JWT, SSH keys, API tokens |
| Tool | What it Checks | Config |
|---|---|---|
| Trivy | OS packages, language deps, misconfigs, embedded secrets | security/trivy/trivy.yaml |
| Tool | What it Tests |
|---|---|
| OWASP ZAP | XSS, SQLi, CSRF, security headers, active crawl |
DevSecOps-CI-CD-Pipeline/
│
├── .github/
│ └── workflows/
│ ├── devsecops-pipeline.yml # Main pipeline (SAST→SCA→Build→Scan→DAST→Deploy)
│ ├── codeql.yml # GitHub CodeQL analysis
│ ├── dependency-review.yml # PR dependency gate
│ └── secret-scan.yml # Gitleaks secret scanning
│
├── app/
│ ├── __init__.py # Flask app factory
│ ├── routes.py # API routes (/health, /api/info)
│ └── templates/
│ └── index.html # Pipeline visualization UI
│
├── tests/
│ └── test_app.py # Pytest unit tests
│
├── security/
│ ├── bandit/bandit.ini # Bandit SAST config
│ ├── semgrep/semgrep-rules.yml # Custom Semgrep rules
│ └── trivy/trivy.yaml # Trivy scanner config
│
├── k8s/
│ ├── base/ # Kustomize base manifests
│ │ ├── deployment.yaml # Hardened K8s deployment
│ │ ├── service.yaml
│ │ ├── network-policy.yaml # Zero-trust NetworkPolicy
│ │ └── kustomization.yaml
│ └── overlays/
│ ├── dev/ # Staging (1 replica)
│ └── prod/ # Production (3 replicas)
│
├── scripts/
│ ├── run-security-scan.sh # Local security scan runner
│ └── zap-scan.sh # Local OWASP ZAP runner
│
├── reports/ # Generated security reports (gitignored)
├── .zap/rules.tsv # ZAP rule overrides
├── .gitleaks.toml # Gitleaks config
├── Dockerfile # Multi-stage, hardened
├── docker-compose.yml # Local dev + DAST profile
├── main.py # App entrypoint
├── requirements.txt # Production dependencies
├── requirements-dev.txt # Dev/security tool dependencies
├── pytest.ini # Test config
├── SECURITY.md # Vulnerability disclosure policy
└── CONTRIBUTING.md
- Python 3.12+
- Docker
- (Optional) kubectl + a Kubernetes cluster
# Clone the repo
git clone https://github.com/SecurityWithAdarsh/DevSecOps-CI-CD-Pipeline.git
cd DevSecOps-CI-CD-Pipeline
# Create virtual environment
python -m venv venv && source venv/bin/activate
# Install dependencies
pip install -r requirements.txt -r requirements-dev.txt
# Run the app
python main.py
# → Visit http://localhost:5000# Build and start
docker compose up --build
# Run DAST against the running app
docker compose --profile dast up zap# Run all security tools (Bandit + Safety + Semgrep + Trivy)
bash scripts/run-security-scan.sh
# Run unit tests with coverage
pytest# Deploy to staging
kubectl apply -k k8s/overlays/dev/
# Deploy to production
kubectl apply -k k8s/overlays/prod/
# Watch rollout
kubectl rollout status deployment/devsecops-app -n productionrunAsNonRoot: true— no root containersreadOnlyRootFilesystem: true— immutable container FSallowPrivilegeEscalation: falsecapabilities: drop: [ALL]seccompProfile: RuntimeDefaultNetworkPolicy— restricts ingress/egress traffic
All reports are generated as GitHub Actions artifacts (retained 30 days):
| Report | Tool | Format |
|---|---|---|
bandit-report.json |
Bandit | JSON |
semgrep-report.json |
Semgrep | JSON |
safety-report.json |
Safety | JSON |
pip-audit-report.json |
pip-audit | JSON |
trivy-report.json |
Trivy | JSON |
trivy-results.sarif |
Trivy | SARIF → GitHub Security tab |
zap-report.json |
OWASP ZAP | JSON |
coverage.xml |
pytest-cov | XML |
Never commit secrets. This pipeline uses:
- GitHub Secrets for
GITHUB_TOKEN(auto-provided), kubeconfig, registry credentials - Gitleaks to block secret commits at the PR gate
- Trivy to detect secrets baked into Docker images
Required secrets for full pipeline operation:
| Secret | Used By |
|---|---|
GITHUB_TOKEN |
Auto-provided — GHCR push, release creation |
KUBECONFIG |
kubectl deploy steps (add manually) |
MIT License — see LICENSE
Adarsh Singh — DevSecOps Engineer | Application Security | OT/ICS Security
"Security is not a feature — it's a pipeline gate."