The DevSecOps capstone: a single service, notes-api, hardened in twelve versions checked by tests, from the first pipeline to the SLO and the DORA metrics.
The issue opens pre-filled with this page title and URL.
The DevSecOps common thread applies the whole course to a single service,
notes-api, a small Flask API that stores notes. You evolve it in twelve
versions, from V0 to V11: a first pipeline, then a threat model, security
gates, an identity without a secret, a signed image that a cluster knows how
to refuse, and finally an SLO and DORA metrics, with a side version, V9b, that adds runtime detection on a
real machine. Each version is a dsoxlab lab whose five checks judge the
result, not the commands typed.
It is meant for those who followed the course modules and want to prove it
on a complete case, over nearly eleven hours.
What you will learn
Build a pipeline that blocks on a secret, an injection, a vulnerable dependency or an image running as root
Keep a STRIDE threat model up to date, version after version, with the evidence of each mitigated threat
Publish without a stored key, attest the provenance of an archive and verify it before deploying it
Make Kubernetes refuse an unsigned image, and contain the pod that runs
Record the security decisions: dated exceptions, VEX document, SLO and DORA metrics
How does the common thread work?
The common thread fits in a single repository, which gets hardened from
one version to the next. The starting point of a version is the solution of
the previous one: what you build in V3 serves in V4, and nothing starts
over. The lab repository
devsecops-dsoxlab-training
carries the twelve versions, their scenarios in French and English, and their
encrypted solutions.
The threat model is the backbone. Set up in V1, it names each weakness of
notes-api, from the SQL injection of the search to the security group
open to the world, and each version moves one or two of them from open to
mitigated, with the file that proves it. At the end, thirteen threats
out of eighteen are mitigated and one is accepted. The last four stay open,
and named: the missing authentication of notes-api and the log of its
writes belong to the application, not to its delivery chain.
Each version also cites the NIST SSDF practice it implements, NIST's
secure development framework (SP 800-218). The checks play your pipeline
with act, which runs GitHub Actions locally, then replay it on
booby-trapped copies of the project: a token pasted in the code, a
vulnerable lock, a pull request that runs its own code. Your pipeline must
pass on the project, and break on the copy.
What do you need on your workstation?
The common thread runs on your workstation, with no cloud account or
cluster to rent. You need a Docker that answers, the dsoxlab CLI and
the mise tool, which installs the versions pinned by the catalog: act
0.2.89, uv, Python, and from V8 on kind, kubectl, helm and cosign. Only
V9b needs a virtual machine, which dsoxlab creates on your workstation
with KVM or Incus.
dsoxlab run prepares the lab's working directory, dsoxlab check runs
its five checks, twenty points each. Versions V8 and V9 set up a
throwaway one-node kind cluster for the duration of the checks: allow
three to four minutes, the first run downloading the images of the
cluster and of Kyverno.
What are the twelve versions?
The table gives, for each version, what notes-api gains, the SSDF
practice targeted and the course lesson that teaches the concept.
Follow it in order: each row assumes the previous ones.
Version
What notes-api gains
SSDF
Lesson that teaches it
V0
A pipeline that installs the lock and tests every push
The thirteen labs fall into four stages. Each block below says what the
version asks of you and what its checks look at. They read what your
pipeline produces, what your image carries or what your cluster
admits, never the shape of your YAML alone.
Foundations: a pipeline, a threat model, two gates
The first three versions lay the groundwork. V0 writes the pipeline that
installs the locked dependencies and runs the tests: the checks verify
that a broken test and an out-of-sync uv.lock make it fail. V1 adds the
threat model, confronted with the real routes of the application. V2
plugs gitleaks and Semgrep in as blocking gates, and the
booby-trapped copy adds a route no test covers: only static analysis can
stop it.
The supply chain, from dependency to provenance
The next five versions secure what notes-api consumes and what it
ships. V3 makes osv-scanner block and separates what can be fixed
from what must be triaged: a vulnerability without a fix gets a dated
exception, and a copy whose expiry has passed turns red again. V4 replaces the
stored AWS key with an OIDC exchange: the checks evaluate your trust
policy against five tokens, and only the one from a push on main,
addressed to STS, must pass.
V5 audits the workflows themselves with actionlint and zizmor, and
rewrites a welcome workflow that ran the code of pull requests with a write
token. V6 analyses the Dockerfile, the Terraform and the built image
with Trivy: the checks build your image and verify the user that runs it.
V7 produces the image SBOM, confronts it with the lock, and expects a
script that refuses an archive whose provenance does not come from the
main pipeline.
Deploying and running: the cluster refuses, the pod is contained
Versions V8 and V9 follow notes-api into Kubernetes. V8 writes the
Kyverno admission policies of the namespace: the checks set up a kind
cluster, an internal registry and Kyverno, then request the admission of a
signed image, an unsigned one, one signed with another key and an image from
Docker Hub. V9 enforces the restricted Pod Security Standard and
NetworkPolicies: the checks measure the real traffic, from the ingress
controller, from another namespace and from notes-api itself, which must only
go out to DNS.
V9b, a side version, sees what these protections do not tell: when
someone got in. On an Ubuntu machine that dsoxlab provisions, notes-api
runs in Docker under Falco 0.45.0 and its modern eBPF probe. You
write the rules that report a shell opened in its container and a write into
its code; the checks trigger these actions themselves, then the normal
activity, which must trigger nothing.
Governing and measuring: written decisions, measured reliability
The last two versions deal with what remains once everything blocks. V10
raises the threshold to MEDIUM: what can be fixed is fixed, what is
accepted becomes a dated exception with its reason, and a VEX
document tells the operators of the previous releases that pip, present
in the base image, does not affect notes-api. V11 writes the SLO as a
Prometheus alert, the runbook it links to, and the computation of the
four DORA metrics. For a 99.5% SLO, the alert pages the on-call person
when the error budget burns 14.4 times too fast, that is above 7.2% of
errors: the checks verify with promtool that 10% fires it and that 1% does
not.
What the checks cannot prove
A green check is only worth what it measures, and the common thread says
so. act provides no OIDC token: under act, a job that authenticates to
AWS fails the same way with a role and with a static key, as measured with
configure-aws-credentials v6.3.0. V4 and V7 therefore judge the
configuration of the publication, and run the trust policy and the
verification script, without being able to replay the keyless signing
itself.
Runtime detection with Falco is not part of V9: it requires a real
machine, not a cluster that shares the host kernel. That is why V9b runs
on a VM. Finally,
vulnerability databases evolve: a dependency that is clean today may
carry a CVE tomorrow and make an already passed version fail. That is the
expected behaviour of a blocking gate, and the catalog replays its solutions to
detect it.
Two pitfalls measured while building the common thread are worth knowing
outside the lab. cosign 3.1 signs in the new bundle format by default,
which Kyverno 1.19.1 does not find ("no signatures found"): signing takes
--new-bundle-format=false. And the python:3.12-slim image of 3 October
2026 already carried a HIGH CVE in libpcre2 fixed in Debian, hence the
apt-get upgrade on every build in V6.
Key points
The common thread evolves a single service, notes-api, in twelve versions; each starts from the solution of the previous one.
The threat model set up in V1 is the backbone: each version handles a threat and cites the file that proves it.
The checks judge what the pipeline produces, then replay it on booby-trapped copies that must make it fail.
A vulnerability that has a fix gets fixed; one without a fix becomes a dated exception, which raises the alarm again at its expiry.
Publishing goes through OIDC, without a stored key, and the cluster refuses any image the platform did not sign.
A green check only proves what it measures: act does not replay keyless signing, and Falco requires a real machine, hence the V9b VM.
Knowledge check
Check that the essentials of this lesson are understood. The questions only
cover what has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
6 questions
6 min
70% to pass
How it works
The timer starts when you click Start
Multiple choice, true/false and short answer questions
You can move between questions
Detailed results are shown at the end
Starts the quiz and the timer
⏱️--:--
0 / 6
Review
(0/0)
--:--
0%
0Correct
0To review
0:00Time
-Level
Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
A new full quiz with random questions
Work again only on the questions you missed
FAQ: frequently asked questions
The questions below come up most often before starting the common
thread: total duration, Kubernetes prerequisites, tools to install,
order of the versions and what the lab checks are worth.
The common thread is the course capstone: a single service, notes-api, which you harden in twelve versions. Each version starts from the solution of the previous one and is a dsoxlab lab checked by five controls, from the first pipeline to the SLO and the DORA metrics.
The thirteen labs add up to nearly eleven hours of practice: 30 minutes for V0, one hour for V6 and V11, around 50 minutes for the others. Reading the lessons that teach each concept comes on top, if you have not followed them yet.
No. Everything runs on your workstation: act plays the GitHub Actions workflows locally, V8 and V9 set up a throwaway kindcluster, and V9b a virtual machine that dsoxlab creates with KVM or Incus. You need a Docker that answers, the dsoxlab CLI and mise.
Yes: dsoxlab run prepares each version from the solution of the previous one, already provided. Following the order is still advised, because each version assumes the skills learned before: you do not harden a pipeline (V5) you never wrote (V0).
They judge what the pipeline produces, what the image carries or what the clusteradmits, never the shape of the YAML alone. Then they replay the pipeline on booby-trapped copies of the project, a token pasted in the code or a vulnerable lock, which must make it fail.
act provides no OIDC token: the OIDC exchange of V4 and the keyless signing of V7 cannot be replayed locally, so their configuration is reread and evaluated. Runtime detection with Falco, which requires a real machine, is played separately, in V9b, on a VM.