Security CI Pipeline — Design
Date: 2026-03-29
Problem
The CI pipeline has Django security checks and Codacy static analysis, but no dependency vulnerability scanning, Python security linting, secret detection, or Docker image scanning.
Goal
Add a dedicated security.yml GitHub Actions workflow with two parallel jobs that catch security issues before they reach production.
Triggers
- Main push: Always runs all scans (blocks production if red)
- PR: Only when relevant files change (Python files, pyproject.toml, uv.lock, Dockerfile, docker-compose.yml, or security.yml itself)
Jobs
Job 1: Code Security
Runs three scans sequentially:
- pip-audit — checks Python dependencies against known vulnerability databases (PyPI advisory DB).
--strictfails on any known vuln. - bandit — Python security anti-pattern linter. Catches eval(), subprocess with shell=True, hardcoded passwords, insecure hashing, etc. Scans
apps/andconfig/. - detect-secrets — scans all files for accidentally committed secrets, API keys, tokens. Excludes
.env.sampleanduv.lock(false positives).
Job 2: Docker Security
- Builds the Docker image from
deploy/docker/Dockerfile - trivy — scans the built image for OS package and Python dependency vulnerabilities. Fails on CRITICAL and HIGH severity only. MEDIUM/LOW reported as info.
Severity gating
All scans fail the workflow on findings (CRITICAL/HIGH for trivy, any finding for the rest). Main branch goes red if vulnerabilities exist — visible before deployment.
File changes
New:
.github/workflows/security.yml— workflow with both jobs
Modified:
pyproject.toml— addpip-audit,bandit,detect-secretsto dev deps; add[tool.bandit]config
Approach
Two-job workflow (selected): code scans and infra scans run in parallel. Logical grouping, 2 status checks, fast execution.
Rejected:
- One job per scan — 4 status checks clutters PR
- Single sequential job — slower, one failure hides remaining results