Ship it hardened and keep it that way
Continues from the last build: You can detect and respond to attacks, and every layer has automated gates.
Every gate from the last eleven rungs works in isolation. You can run gitleaks by hand and get zero secrets.
What you'll build
A single GitHub Actions workflow gates every commit through secret scanning, SAST, dependency scanning, policy-as-code, image build and scan, SBOM and keyless signing, a DAST pass against a live preview, and a signature-verified deploy, in that order, with no path around it except a scoped, approved, audited break-glass lane. The app runs on a managed host that only ever pulls a Cosign-verified image by digest, behind TLS with real security headers, with a rehearsed rollback that restores the last-good signed digest in minutes. The threat model is closed: every original risk is mapped to the control that mitigates it and the CI job that enforces it, with an honest residual-risk list instead of a false all-clear. A security.txt and disclosure policy with a real SLA turn outside reports into gated fixes instead of dead inbox threads. And a README makes the whole thing demonstrable: a pipeline diagram, a before-and-after finding count for every prior rung, an OWASP Top 10 and CI/CD Top 10 coverage matrix, and a script that pushes a known-bad commit and shows it die in CI in under ninety seconds.
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: ship
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<PIN_TO_SHA>
# TODO: gitleaks
build-scan-sign:
needs: [secret-scan]
runs-on: ubuntu-latest
permissions:
packages: write
id-token: write
steps:
# TODO: build, trivy image, syft, push, cosign sign
verify-and-deploy:
needs: [build-scan-sign]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production
steps:
# TODO: cosign verify then run deploy.sh
Reading this file
permissions: contents: readthe least-privilege default every job inherits unless it explicitly asks for moreneeds: [secret-scan]the build job cannot start until the secret scan has passed, not just runif: github.ref == 'refs/heads/main'restricts the deploy job so no fork or PR can ever reach itpackages: writewrite access to the registry granted only on the job that actually needs it
This is intentionally incomplete, add sast, dep-scan, policy, preview-deploy and dast as their own needs-chained jobs before treating this as done.
That's 1 of 9 explained code blocks in this single project.
The build, milestone by milestone
- 1
The end-to-end secure pipeline
6 guided stepsRight now each gate runs as its own workflow with no guarantee of order, a developer can merge past a failing SAST job while a separate secret-scan workflow is still green, or push straight to production while the DAST workflow was never wired to the deploy decision at all. Sequencing them into one dependency graph is what turns eight independent scripts into one enforced gate.
- 2
Deploy the signed image
6 guided stepsSigning an image is theater if nothing ever checks the signature at the point it matters. Anyone with registry push access, or a leaked long-lived token, can still land an unsigned or tampered image on the host if the deploy path doesn't fail closed on a bad signature, and secrets baked into a layer survive in every registry mirror and every image history forever, long after you rotate the credential.
- 3
Break-glass and rollback
6 guided stepsGates will occasionally block a legitimate emergency fix, a payment outage that needs a hotfix faster than a full DAST pass can run. If there's no approved way to move fast in that moment, people eventually disable the whole pipeline instead, quietly, and it never gets turned back on. And if rollback has never been rehearsed, the first time it's needed for real is the worst possible time to be improvising commands under pressure.
- 4
The full threat model, closed
6 guided stepsA threat model written once at the start of the project and never revisited only documents intentions. The whole point of eleven rungs of gates is to close the loop, row by row, and prove which promise is actually enforced by running code today versus which one is still just aspirational from week one.
- 5
A vulnerability disclosure + patch SLA
5 guided stepsScanners only catch the bug classes they were built to catch. Business logic flaws, novel chains, and anything outside a ruleset are far more likely to surface from a report, either a teammate or, on a real product, an outside researcher. Without a published process and a timed SLA, reports have nowhere defined to go and quietly die in an inbox.
- 6
The portfolio writeup
6 guided stepsNone of the automation from the previous eleven rungs matters as a portfolio piece if nobody can see it work quickly. An interviewer will not read twelve rungs of history, they will watch you push a bad commit and watch it die in CI, that ninety seconds is the entire pitch.
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