Skip to content

Commit c6e3c2d

Browse files
authored
Merge pull request #1657 from inno-devops-labs/docs/week2-and-course-tooling
docs: rewrite all 12 labs and 12 lectures to a verified, sourced standard, add course maintenance tooling
2 parents dfdc68f + ca69def commit c6e3c2d

36 files changed

Lines changed: 2075 additions & 4008 deletions

‎.github/ISSUE_TEMPLATE/lab-bug.yml‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Lab bug
2+
description: A command, script or file in a lab does not work as written
3+
title: "lab N: <what breaks>"
4+
labels: ["lab-bug"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
Reporting these is the fastest way to get a lab fixed for everyone. You are not
10+
expected to work around a broken command on your own.
11+
- type: input
12+
id: lab
13+
attributes:
14+
label: Lab and step
15+
placeholder: "lab 5, step 5.3"
16+
validations:
17+
required: true
18+
- type: textarea
19+
id: command
20+
attributes:
21+
label: The command you ran
22+
description: Copy it exactly as the lab prints it.
23+
render: shell
24+
validations:
25+
required: true
26+
- type: textarea
27+
id: output
28+
attributes:
29+
label: What happened
30+
description: Error message or wrong output, pasted, not described.
31+
render: shell
32+
validations:
33+
required: true
34+
- type: input
35+
id: env
36+
attributes:
37+
label: OS and tool version
38+
placeholder: "macOS 15.5, Docker 28.1, bash 3.2"
39+
validations:
40+
required: true
41+
- type: textarea
42+
id: workaround
43+
attributes:
44+
label: Workaround you found, if any
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Course health
2+
3+
# Weekly drift check on the pinned tool stack. It opens one issue when a pin has
4+
# fallen behind upstream; re-pinning happens before the next cohort, not on every
5+
# release. See tools/versions.yaml for the cadence.
6+
7+
on:
8+
schedule:
9+
- cron: "0 6 * * 1"
10+
workflow_dispatch:
11+
12+
permissions:
13+
contents: read
14+
15+
jobs:
16+
versions:
17+
runs-on: ubuntu-latest
18+
permissions:
19+
contents: read
20+
issues: write
21+
steps:
22+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23+
- name: Check pinned versions against upstream
24+
id: check
25+
env:
26+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
run: |
28+
python3 -m pip install --quiet pyyaml
29+
# $? after a pipeline is tee's status, which is always 0. Capture the
30+
# checker's own exit code instead, or the drift issue never opens.
31+
set +e
32+
python3 tools/check-versions.py > report.txt
33+
drift=$?
34+
set -e
35+
cat report.txt
36+
echo "drift=$drift" >> "$GITHUB_OUTPUT"
37+
- name: Open or update the drift issue
38+
if: steps.check.outputs.drift != '0'
39+
env:
40+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41+
run: |
42+
title="Tool pins have drifted"
43+
body=$(printf 'Weekly check of `tools/versions.yaml`.\n\n```\n%s\n```\n\nRe-pin before the next cohort. A mid-semester bump needs a full lab re-run and a Common pitfalls line.' "$(cat report.txt)")
44+
existing=$(gh issue list --state open --search "$title in:title" --json number --jq '.[0].number')
45+
if [ -n "$existing" ]; then
46+
gh issue comment "$existing" --body "$body"
47+
else
48+
gh issue create --title "$title" --body "$body" --label lab-bug
49+
fi

‎README.md‎

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ The course follows a **map → discover → write → ship → scan → harden
2121
| 1 | Lab 1 | Foundations & SDLC | OWASP Top 10:2025, Juice Shop deploy, PR workflow |
2222
| 2 | Lab 2 | Threat Modeling | STRIDE, DFDs, trust boundaries, Threagile YAML |
2323
| 3 | Lab 3 | Secure Git | SSH commit signing, pre-commit gitleaks, history rewrite with `git filter-repo` |
24-
| 4 | Lab 4 | SBOM + SCA | Syft (CycloneDX 1.6 + SPDX), Grype, Trivy, sign-ready attestations |
24+
| 4 | Lab 4 | SBOM + SCA | Syft (CycloneDX 1.7 + SPDX), Grype, Trivy, sign-ready attestations |
2525
| 5 | Lab 5 | SAST + DAST | Semgrep (`p/owasp-top-ten`), ZAP baseline + authenticated, cross-tool correlation |
2626
| 6 | Lab 6 | IaC Security | Checkov 3.x on Terraform, KICS on Ansible + Pulumi, custom Checkov policies |
27-
| 7 | Lab 7 | Container/K8s | Trivy image scan, Pod Security Standards (`restricted`), securityContext, NetworkPolicy, Conftest gate |
28-
| 8 | Lab 8 | Supply Chain | Cosign v3 sign + verify + tamper demo, SBOM/SLSA attestations, `cosign sign-blob` |
27+
| 7 | Lab 7 | Container/K8s | Trivy image and Dockerfile scan, Pod Security Standards (`restricted`), securityContext, NetworkPolicy, read-only root filesystem |
28+
| 8 | Lab 8 | Supply Chain | Cosign 3.0 sign + verify + tag-overwrite demo, CycloneDX and SLSA attestations, `cosign sign-blob` |
2929
| 9 | Lab 9 | Runtime + PaC | Falco (modern eBPF), custom rules, Conftest/Rego policies at CI time |
30-
| 10 | Lab 10 | Vulnerability Management | DefectDojo capstone — import all prior labs, dedup, SLA matrix, MTTR/age, 5-min walkthrough |
30+
| 10 | Lab 10 | Vulnerability Management | DefectDojo capstone — import labs 4-7, dedup, SLA configuration, finding age and SLA compliance, 5-min walkthrough |
3131
| — | Lab 11 | Edge Hardening *(bonus)* | Nginx TLS 1.3, security headers, rate limiting, cert rotation; bonus: Coraza WAF + OWASP CRS |
32-
| — | Lab 12 | VM Sandboxing *(bonus)* | Kata Containers, runc-vs-VM isolation, perf benchmark; bonus: real container-escape PoC blocked by Kata |
32+
| — | Lab 12 | VM Sandboxing *(bonus)* | Kata Containers, runc-vs-VM isolation, perf benchmark; bonus: a privileged-container escape stopped by the guest kernel |
3333

3434
---
3535

@@ -78,31 +78,31 @@ graph LR
7878

7979
## Technology Stack
8080

81-
All tools free and open-source (or have a meaningful free tier). Versions pinned to April-May 2026.
81+
All tools free and open-source (or have a meaningful free tier). [`tools/versions.yaml`](tools/versions.yaml) is the source of truth for every pin; a weekly job reports when one falls behind upstream. Pins are refreshed before each cohort, not mid-semester.
8282

8383
| Category | Tool | Version | Introduced |
8484
|----------|------|---------|------------|
8585
| Target app | OWASP Juice Shop | v20.0.0 | Week 1 (provided) |
8686
| Containers | Docker / Docker Compose | 28.x | Week 1 |
87-
| Threat modeling | Threagile | 0.9.1 | Week 2 |
87+
| Threat modeling | Threagile | 0.9.1 (Jul 2024, latest release) | Week 2 |
8888
| Pre-commit framework | pre-commit | latest | Week 3 |
89-
| Secret scanning | gitleaks | 8.21.x | Week 3 |
89+
| Secret scanning | gitleaks | 8.30.x | Week 3 |
9090
| History rewrite | git-filter-repo | 2.45+ | Week 3 |
91-
| SBOM | Syft | 1.41.x | Week 4 |
92-
| SCA | Grype | 0.107.x | Week 4 |
93-
| Multi-purpose scanner | Trivy | 0.69.x | Week 4, 6, 7 |
94-
| SAST | Semgrep CE | 1.157.x | Week 5 |
95-
| DAST | OWASP ZAP | stable (Checkmarx-maintained) | Week 5 |
96-
| IaC scanning (Terraform) | Checkov | 3.2.x | Week 6 |
91+
| SBOM | Syft | 1.51.x | Week 4 |
92+
| SCA | Grype | 0.118.x | Week 4 |
93+
| Multi-purpose scanner | Trivy | 0.74.x | Week 4, 6, 7 |
94+
| SAST | Semgrep CE | 1.176.x | Week 5 |
95+
| DAST | ZAP (ex-OWASP, now Checkmarx) | 2.17.x via the `stable` tag | Week 5 |
96+
| IaC scanning (Terraform) | Checkov | 3.3.x | Week 6 |
9797
| IaC scanning (Ansible/Pulumi) | KICS | latest | Week 6 |
98-
| Kubernetes | k3d (k3s in Docker) | v5.8.3 / k3s v1.31.x | Week 7 |
99-
| Policy-as-Code | Conftest + OPA Rego | 0.68.x / 1.15.x | Week 7, 9 |
100-
| Supply chain | Cosign | v3.0.x | Week 8 |
98+
| Kubernetes | k3d (k3s in Docker) | v5.9.0 / k3s v1.33.x | Week 7 |
99+
| Policy-as-Code | Conftest + OPA Rego | 0.69.x / 1.15.x | Week 7, 9 |
100+
| Supply chain | Cosign | v3.0.x (not 3.1: see versions.yaml) | Week 8 |
101101
| Local registry | Distribution | v3 | Week 8 |
102-
| Runtime detection | Falco | 0.43.x | Week 9 |
102+
| Runtime detection | Falco | 0.43.1 | Week 9 |
103103
| Vulnerability mgmt | DefectDojo | v2.58.x | Week 10 |
104104
| Bonus: Edge | Nginx | stable-alpine | Lab 11 |
105-
| Bonus: VM sandbox | Kata Containers | v3.x | Lab 12 |
105+
| Bonus: VM sandbox | Kata Containers | 4.1.x | Lab 12 |
106106

107107
---
108108

@@ -121,6 +121,8 @@ The course repo ships **only** lab specs, lecture notes, and plumbing files. Stu
121121
| `labs/lab10/imports/` — DefectDojo importer | ✅ | |
122122
| `labs/lab11/docker-compose.yml`, `labs/lab11/reverse-proxy/nginx.conf` | ✅ | |
123123
| `labs/lab12/scripts/` — Kata install/configure | ✅ | |
124+
| `tools/` — version manifest + drift and lab checkers | ✅ | |
125+
| `.github/workflows/course-health.yml`, `.github/ISSUE_TEMPLATE/` | ✅ | |
124126
| `.github/PULL_REQUEST_TEMPLATE.md` — students write in Lab 1 | | ✅ |
125127
| `.github/workflows/*.yml` — students add from Lab 1 bonus onward | | ✅ |
126128
| `.pre-commit-config.yaml` — students write in Lab 3 | | ✅ |
@@ -148,7 +150,7 @@ Each main lab (Labs 1-10) caps at **12 pts = 10 main + 2 bonus**.
148150

149151
A student who only completes Task 1 across all 10 labs ends with a working DevSecOps pipeline — just not all the deeper-dive controls.
150152

151-
**Bonus labs (11 + 12)** have a tighter shape: **Task 1 (4 pts) + Task 2 (4 pts) + Bonus Task (2 pts) = 10 pts total** (vs main labs' 12). The labs are bonus-track in the sense that they're not on the critical path; the Bonus Task inside each lab is still the genuinely-challenging extension. Bonus labs count toward a separate 20% weight (see grading below).
153+
**Bonus labs (11 + 12)** have a tighter shape: **Task 1 (4 pts) + Task 2 (4 pts) + Bonus Task (2 pts) = 10 pts total** (vs main labs' 12). The labs are bonus-track in the sense that they're not on the critical path; the Bonus Task inside each lab is still the harder extension. Bonus labs count toward a separate 20% weight (see grading below).
152154

153155
### Submission Workflow
154156

@@ -286,6 +288,11 @@ DevSecOps-Intro/
286288
│ ├── lab11/docker-compose.yml, lab11/reverse-proxy/ # Nginx stack
287289
│ └── lab12/scripts/, lab12/setup/ # Kata install
288290
│
291+
├── tools/ # Course maintenance (ships)
292+
│ ├── versions.yaml # every pinned tool version, one source of truth
293+
│ ├── check-versions.py # compares the pins with upstream releases
294+
│ └── verify-lab.sh # runs every shell block of a lab spec
295+
│
289296
├── refs/ # Instructor reference submissions (gitignored)
290297
│ └── labN.md # model answers per lab, captured from dry-runs
291298
│
@@ -318,7 +325,7 @@ DevSecOps-Intro/
318325
</details>
319326

320327
<details>
321-
<summary>Talks worth your time</summary>
328+
<summary>Talks</summary>
322329

323330
- *"What Happens When Falco Detects?"* — Loris Degioanni, KubeCon EU 2024
324331
- *"The xz Backdoor — Engineering Postmortem"* — Andres Freund, BSDCan 2024

‎labs/lab1.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- Docker 26 or newer (`docker --version`), Git 2.34 or newer, `curl`, `jq` (`brew install jq` or `apt install jq`), a GitHub account.
1515
- Fork the course repo, clone your fork, create the branch:
1616

17+
<!-- verify:skip student fork clone -->
1718
```bash
1819
git clone https://github.com/<your-username>/DevSecOps-Intro.git
1920
cd DevSecOps-Intro
@@ -34,6 +35,7 @@ docker run -d --name juice-shop -p 127.0.0.1:3000:3000 bkimminich/juice-shop:v20
3435

3536
Wait about 20 seconds, then:
3637

38+
<!-- verify:wait 25 -->
3739
```bash
3840
docker ps --filter name=juice-shop --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
3941
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:3000
@@ -71,6 +73,7 @@ Actual values only. A placeholder left in the report costs points.
7173

7274
### 1.4 Keep the container
7375

76+
<!-- verify:skip stops the container later blocks need -->
7477
```bash
7578
docker stop juice-shop # do not `docker rm`: Labs 4, 5 and 7 reuse this image
7679
```
@@ -120,6 +123,7 @@ Push, open the draft PR, and make the run green.
120123

121124
## Submit
122125

126+
<!-- verify:skip student fork files -->
123127
```bash
124128
git add .github/PULL_REQUEST_TEMPLATE.md submissions/lab1.md
125129
git add .github/workflows/lab1-smoke.yml # bonus only

0 commit comments

Comments
 (0)