This project is a minimal DevSecOps example built around a small Python/Flask API and a Jenkins pipeline. It demonstrates how security is integrated at both the developer side (Shift Left) and the CI/CD pipeline.
- Language: Python
- Framework: Flask
- Endpoints:
GET /health→ basic health check.POST /echo→ echoes the JSON payload.
Folder structure:
app/
main.py # Flask app
__init__.py # exposes app for tests/imports
requirements.txt # runtime + test dependencies
tests/
test_basic.py # minimal pytest suite
Dockerfile # builds devsecops-demo:latest image
Jenkinsfile # CI/CD + security stages
.pre-commit-config.yaml # local security hooks
On the developer machine:
- VS Code + SonarLint are used to detect security/code smells while coding.
- Alerts are shown directly in the editor (before commit).
File: .pre-commit-config.yaml
Configured hooks:
-
pre-commit-hooks: whitespace + end-of-file checks.
-
Semgrep (
p/security-audit):- Static security analysis (SAST) on the source code.
-
Bandit:
- Python-specific security checks in
app/.
- Python-specific security checks in
-
Gitleaks:
- Detects hardcoded secrets in the repository.
Behavior:
- Hooks run automatically on each
git commit. - If a serious issue or secret is detected, the commit is blocked until fixed.
➡ This satisfies the “pre-commit / IDE / SAST / secrets” part of the development phase.
File: Jenkinsfile
The pipeline is declarative and uses Dockerized tools so the Jenkins agent does not need to have them pre-installed.
-
Checkout
checkout scm- Retrieves the source code from Git.
-
Build & Unit Tests
- Creates a Python virtual environment.
- Installs dependencies from
app/requirements.txt. - Runs
pytest app/tests. - Builds the Docker image:
devsecops-demo:latest.
-
SAST – Semgrep
-
Runs Semgrep in a container:
returntocorp/semgrepwithp/security-audit.
-
Outputs
semgrep-report.json. -
Artifact is archived in Jenkins.
-
-
SCA – Dependency Check
-
Runs OWASP Dependency-Check in a container:
- Scans the workspace for vulnerable dependencies.
- Uses
--failOnCVSS 7to fail the stage if a dependency has CVSS ≥ 7.
-
Outputs
depcheck-report/dependency-check-report.json. -
Artifact is archived.
-
-
Secret Scan – Gitleaks
- Runs
zricethezav/gitleaksin a container against the repo. - Outputs
gitleaks-report.json. - Artifact is archived.
- Runs
-
Docker Scan – Trivy
-
Runs
aquasec/trivyagainst the built image:--severity HIGH,CRITICAL--exit-code 1→ pipeline fails on serious CVEs.
-
Outputs
trivy-report.json. -
Artifact is archived.
-
-
DAST – OWASP ZAP Baseline
- Starts the application container on port 8000.
- Runs
owasp/zap2docker-stablebaseline scan againsthttp://localhost:8000/health. - Uses
-m 1to fail on Medium/High alerts. - Outputs
zap-report.jsonandzap-warn.txt. - Artifacts are archived.
- Stops the app container.
-
Reporting & Notification
- Logs pipeline result with commit, job name, and build number.
- Optionally sends a Slack notification if
SLACK_WEBHOOK_URLis defined.
-
Shift Left / Development Phase
- IDE plugin: SonarLint in VS Code.
- Pre-commit security hooks: Semgrep, Bandit, Gitleaks.
- Secure coding practices enforced before commit.
-
Acceptance Phase / Build Stage
- SAST: Semgrep stage in Jenkins.
- SCA: Dependency-Check stage.
- Secret scanning: Gitleaks stage.
- Container security: Trivy stage.
- DAST: OWASP ZAP baseline stage.
- Reports archived in Jenkins and usable for audits.
# Run tests
python -m venv .venv
source .venv/bin/activate
pip install -r app/requirements.txt
pytest app/tests
# Build and run Docker image
docker build -t devsecops-demo:latest .
docker run --rm -p 8000:8000 devsecops-demo:latestThis project is intentionally minimal: it’s just enough to demonstrate DevSecOps integration (development + acceptance phases) without overcomplicating the codebase.