Secure it by default: shift-left and delivery hygiene
Continues from the last build: TaskFlow is observable and GitOps-deployed but security is an afterthought.
In the last rung you closed the loop: Argo CD reconciles TaskFlow from Git, Prometheus and Grafana show you golden signals, and an on-call alert fires before users notice.
What you'll build
A TaskFlow delivery pipeline and cluster where insecure changes cannot reach production: gitleaks blocks committed secrets, Bandit and pip-audit and CodeQL catch vulnerable code and dependencies, Trivy fails the build on critical image CVEs, External Secrets Operator injects the database password from AWS Secrets Manager so no secret lives in Git, branch protection forces PR review plus green status checks before merge, and Kyverno admission policies reject any pod using :latest, running as root, or missing resource limits.
See how we teach, before you sign up
You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:
name: security
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
id-token: write # for OIDC auth to AWS, no long-lived keys
jobs:
scan-and-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # gitleaks needs full history
- name: Secret detection (gitleaks)
uses: gitleaks/gitleaks-action@v2
env:
GITLEAKS_CONFIG: .gitleaks.toml
- name: Python SAST (Bandit)
run: |
pip install bandit
bandit -r backend/app -ll # -ll = report medium+ severity; bandit exits non-zero only on findings at/above this threshold, which is the gate
- name: Dependency audit (pip-audit)
run: |
pip install pip-audit
pip-audit -r backend/requirements.txt # requirements must be == pinned so the scan matches what ships
- name: Build image
run: docker build -t taskflow-backend:${{ github.sha }} backend
- name: Image scan gate (Trivy)
uses: aquasecurity/trivy-action@0.24.0
with:
image-ref: taskflow-backend:${{ github.sha }}
severity: CRITICAL
exit-code: '1' # fail the build on any CRITICAL
ignore-unfixed: true # do not fail on CVEs with no fix yetReading this file
scan-and-build:The job name; you reference this exact string as the required status check on the main branch.fetch-depth: 0Pulls the full git history so gitleaks can scan every past commit, not just the latest one.id-token: writeLets the job request a short-lived OIDC token to log in to AWS without storing permanent access keys.exit-code: '1'Tells Trivy to fail the build (return error code 1) when it finds a matching vulnerability.bandit -r backend/app -llScans the backend source for insecure Python patterns and reports issues of medium severity or higher.
Runs on every PR and on pushes to main. The job is named scan-and-build, the exact name you mark as a required status check in milestone 5. The Trivy step is the hard gate: exit-code 1 on CRITICAL stops the push.
That's 1 of 10 explained code blocks in this single project.
The build, milestone by milestone
- 1
Add secret detection, SAST, and dependency scanning to the pipeline
3 guided stepsSecrets and vulnerable dependencies are the two most common ways small teams get breached. Catching them at the commit boundary is the literal definition of shift-left: the earlier a defect is found, the cheaper it is to fix. A leaked DB password in git history is forever, so detecting it before merge is the only cheap moment.
- 2
Gate the build on container image vulnerabilities with Trivy
3 guided stepsSAST reads your code, but most of the attack surface in a container is the base image and OS packages you did not write. Image scanning is the only check that sees that layer. Gating the push (not just reporting) is what makes it real: a critical CVE physically cannot reach the registry.
- 3
Replace the raw Kubernetes Secret with External Secrets Operator
3 guided stepsA base64 Kubernetes Secret is encoding, not encryption, and committing it to the GitOps repo means the prod DB password is readable by everyone with repo access. Pulling it from Secrets Manager at runtime means the secret has one source of truth, supports rotation, and is governed by IAM least-privilege instead of git permissions.
- 4
Enforce admission policy with Kyverno: no :latest, non-root, resource limits
3 guided stepsCI gates protect the path through CI, but anything applied directly to the cluster (a teammate's kubectl apply, a misconfigured manifest) bypasses CI entirely. Admission control is the backstop that enforces baseline hygiene on everything, regardless of how it arrived. A conditional anchor on securityContext would let a default-root pod slip through, defeating the whole point, so the non-root rule must require the field unconditionally.
- 5
Lock down delivery: trunk-based flow with required PR review and status checks
3 guided stepsThe strongest scanners are worthless if anyone can push straight to main and skip them. Branch protection is the enforcement layer that makes review and the CI gates mandatory. Trunk-based development with short-lived branches keeps integration frequent and shrinks the window where insecure or stale code diverges from production.
What's inside when you start
You'll walk away with
This is portfolio-grade. Build it free.
Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.
Start building