diff --git a/docs/ROOT_FOUNDATIONS_ARCHITECTURE.md b/docs/ROOT_FOUNDATIONS_ARCHITECTURE.md new file mode 100644 index 0000000..bbc23bb --- /dev/null +++ b/docs/ROOT_FOUNDATIONS_ARCHITECTURE.md @@ -0,0 +1,130 @@ +# ROOT Foundations Architecture — ROOT 01-04 + +Phase 6D §1 — the curriculum architecture for the foundational half of ROOT_, built entirely on +the existing course/module/activity model (`docs/COURSE_CONTENT_MODEL.md`) and the existing +scenario/assessment engines. See `docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md` for why no new +activity type or content model was needed. Every course below is a row that already exists in +`courses` (`status='planned'`, seeded by Phase 6A's `022_course_content.sql`) — this phase adds +their modules and activities, and updates their `status`/`objectives`/`prerequisites`. + +## Course sequence and prerequisite chain + +``` +01 Computing & Linux Foundations + ↓ +02 Linux Administration & Networking + ↓ +03 Git & Collaborative Development + ↓ +04 Containers & Docker + ↓ +05 Kubernetes Foundations (existing) +``` + +Enforced server-side via `courses.prerequisites` (the same mechanism already gating +05→06→07/09/10→12→Capstone) — not UI-hidden alone. `root-05-kubernetes-foundations.prerequisites` +is updated this phase to add `root-04-containers-and-docker`, so a student cannot reach ROOT 05 +without the foundations chain complete. This does not touch the capstone assessment engine's own +`unlock_rule` (still the original 6 `rootnode-path.json` stages) — course-level prerequisite +gating and the capstone's own gate remain the two independent systems `docs/COURSE_CONTENT_MODEL.md` +§5 and `docs/ROOT_CAPSTONE_READINESS.md` §3 already establish. + +## Extension point for future placement/override (Step 20) + +Not built this phase. The extension point already exists structurally: `courses.prerequisites` +is a plain array a future placement-assessment feature could programmatically satisfy (e.g. by +recording a passing placement score as an `activity_completions`-equivalent fact), or an +instructor override could satisfy by directly marking an enrollment's course complete through +the existing admin layer — neither requires a schema change to unlock. No bypass button is +implemented; this paragraph exists so a future phase doesn't need to reopen the prerequisite +model to add one. + +--- + +## ROOT 01 — Computing & Linux Foundations + +Target learner: a technically curious beginner with no assumed prior Linux/CLI experience. +Estimated duration: ~5.5 hours self-paced / ~4 hours instructor-led (see +`docs/ROOT_PROGRAM_DURATION_MODEL.md` for the derived total). + +| # | Module | Outcome (verb-first) | Activities | Real Ops connection | +|---|---|---|---|---| +| 1 | How Computers Run Software | Explain what the OS/kernel manages (CPU, RAM, storage, processes) vs. what an application does | lesson, guided_exercise (inspect `/proc/cpuinfo`, `free -h`, `lsblk`, `ps aux` on paper first), lab (`linux-inspect-hardware` — real inspection commands), reflection | This is literally what a container later virtualizes — a Pod's resource requests/limits are promises about exactly these same resources. | +| 2 | Linux & The Shell | Use a shell confidently: run commands, read exit codes, use history/tab-completion/man pages | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-shell-basics`), reflection | Every `kubectl exec` session later drops a student into this exact shell experience. | +| 3 | Navigating the Filesystem | Navigate absolute/relative paths; explain what `/etc`, `/var`, `/home`, `/tmp`, `/usr`, `/proc` are for at a conceptual level | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-filesystem-navigation`), reflection | Container images later have this exact same tree — `/etc/nginx/nginx.conf` isn't a new idea, it's the same filesystem convention. | +| 4 | Files & Text | Manipulate files and text streams; use pipes/redirection to compose commands | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-files-and-text`), reflection | `kubectl logs \| grep` later is the exact same composition skill applied to a different data source. | +| 5 | Processes | Explain the process concept (PID, foreground/background, signals); inspect and terminate a real process | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-process-management`), reflection | A container IS (mostly) one isolated process tree — this module is the direct prerequisite for understanding what a container "contains." | +| 6 | Users & Permissions Foundations | Explain ownership and rwx permissions; use `chmod`/`sudo` correctly; state the least-privilege principle | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-permissions-foundations`), reflection | Direct root of ROOT 09's SecurityContext/RBAC — "least privilege" is introduced here first, in a context students can literally see and touch. | + +Assessment: `rootnode-linux-foundations-assessment` (knowledge + state-validation, see §"Assessments" below). + +## ROOT 02 — Linux Administration & Networking + +Prerequisite: ROOT 01 complete. Target learner: comfortable with the ROOT 01 shell/filesystem/ +process/permissions basics, ready to reason about services and networks. + +| # | Module | Outcome | Activities | Real Ops connection | +|---|---|---|---|---| +| 1 | Linux System Administration | Explain packages/services/systemd conceptually; read logs; use environment variables and config files | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-admin-services-logs`), reflection | A Kubernetes controller IS a systemd-like supervisor pattern generalized across a cluster — "restart on failure" isn't new in ROOT 06, it's a concept students meet here first. | +| 2 | Storage & Filesystems | Explain block devices/partitions/mounts conceptually; distinguish persistent vs. temporary data; inspect real disk usage | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-storage-inspection`), reflection | Direct root of ROOT 08's PV/PVC model and ROOT 04's bind-mount/volume distinction. | +| 3 | Networking Mental Model | Explain hosts/interfaces/IP/subnet/gateway/DNS/ports/TCP-vs-UDP/client-server at a conceptual level | lesson, demonstration, knowledge_check, guided_exercise, reflection (conceptual module — no lab; see note below) | **Critical module** — the direct prerequisite for reasoning about Pod IPs, Services, Ingress, NetworkPolicy, and DNS later. | +| 4 | Linux Network Inspection | Use `ip addr`/`ip route`/`ss`/`ping`/`curl`/`dig` to answer a specific diagnostic question, not just run syntax | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-network-inspection`), reflection | Exactly the toolkit ROOT 10's troubleshooting framework assumes a student already has. | +| 5 | DNS & HTTP | Trace a request: browser → DNS → IP → TCP → HTTP → server → response | lesson, demonstration, knowledge_check, guided_exercise, lab (`linux-dns-http-trace`), reflection | The exact conceptual bridge `docs/ROOT_PROGRAM_ARCHITECTURE.md` names for later Kubernetes Services/Ingress/DNS. | +| 6 | Troubleshooting Linux Systems | Apply Observe→Evidence→Hypothesize→Test→Repair→Validate→Prevent to a Linux-level failure | lesson, demonstration, guided_exercise, lab (`linux-troubleshooting-framework`), reflection | Literally the same framework `root-10-m03-troubleshooting-framework` already teaches — introduced here first, at the Linux level, so it "already feels natural" by ROOT 10 (Step 15's explicit goal). | + +Module 3 note: per the readiness standard's "sequence should match the subject," a purely +conceptual mental-model module earns READY through demonstrated reasoning (its knowledge check +and guided exercise), not a forced lab — mirroring `root-05-m00`'s own precedent. Module 4 +immediately after it is where the same concepts become hands-on. + +Assessment: `rootnode-linux-networking-assessment`. + +## ROOT 03 — Git & Collaborative Development + +Prerequisite: ROOT 02 complete. Uses only local repositories (a working tree + a local bare +"remote") inside the student's own Lab — no Gitea account, no network credential, no +RootNode-canonical-repo access ever reaches a student Lab (`docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md` +§4). + +| # | Module | Outcome | Activities | Real Ops connection | +|---|---|---|---|---| +| 1 | Why Version Control Exists | Explain what problem version control solves (history, collaboration, reproducibility, source of truth) | lesson, knowledge_check, reflection | Sets up "Git as source of truth" — the exact idea GitOps (ROOT 11) generalizes. | +| 2 | Git Mental Model | Explain working tree / staging area / repository / commit / branch / remote as a model, before commands | lesson, demonstration, knowledge_check, guided_exercise, reflection | Same "model before commands" pedagogy as ROOT 05's mental-model module. | +| 3 | Everyday Git | Use `status`/`add`/`commit`/`log`/`diff` to make and inspect real changes | lesson, demonstration, knowledge_check, guided_exercise, lab (`git-everyday-basics`), reflection | Every future IaC/GitOps workflow assumes this fluency as a given. | +| 4 | Branching | Create branches, switch between them, merge, resolve a simple conflict | lesson, demonstration, knowledge_check, guided_exercise, lab (`git-branching-and-merge`), reflection | Direct root of CI/CD's branch-triggered pipelines (future ROOT 11 content). | +| 5 | Remote Repositories | Clone/fetch/pull/push against a real local-bare remote; explain `origin` | lesson, demonstration, knowledge_check, guided_exercise, lab (`git-remote-clone-push`), reflection | Direct root of GitOps's "push triggers deployment" model. | +| 6 | Engineering Workflow | Write meaningful commits; explain why `main` is protected and why rollback via history matters | lesson, demonstration, knowledge_check, reflection | Explicit bridge to ROOT 11's "Git as source of truth for infrastructure" framing. | + +Assessment: `rootnode-git-fundamentals-assessment`. + +## ROOT 04 — Containers & Docker + +Prerequisite: ROOT 03 complete. Uses the nested Docker Engine +(`docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md` §3) — the direct bridge into Kubernetes. + +| # | Module | Outcome | Activities | Real Ops connection | +|---|---|---|---|---| +| 1 | Why Containers Exist | Explain the packaging/dependency-isolation/repeatability problem containers solve; contrast VM vs. container | lesson, demonstration, knowledge_check, reflection | Sets up "Kubernetes orchestrates what Docker already isolates" — Module 8's thesis. | +| 2 | Images & Containers | Explain image/layer/container/registry/tag as a model | lesson, demonstration, knowledge_check, guided_exercise, reflection | A Kubernetes Pod's `image:` field is this exact concept, unchanged. | +| 3 | Docker CLI | Pull/run/inspect/log/exec/stop/remove a real container | lesson, demonstration, knowledge_check, guided_exercise, lab (`docker-cli-basics`), reflection | `kubectl exec`/`kubectl logs` are the same actions against a different orchestrator. | +| 4 | Container Networking | Explain host-vs-container port, publish a port, reach one container from another | lesson, demonstration, knowledge_check, guided_exercise, lab (`docker-container-networking`), reflection | Direct root of Pod IPs/Services — builds explicitly on ROOT 02 M3/M4. | +| 5 | Container Storage | Explain ephemeral container filesystem vs. bind mounts vs. volumes | lesson, demonstration, knowledge_check, guided_exercise, lab (`docker-container-storage`), reflection | Direct root of Kubernetes PVC — builds explicitly on ROOT 02 M2. | +| 6 | Dockerfile & Image Build | Write a Dockerfile (`FROM`/`RUN`/`COPY`/`WORKDIR`/`CMD`) and build a real image | lesson, demonstration, knowledge_check, guided_exercise, lab (`docker-build-image`), reflection | Direct root of CI/CD's build step (future ROOT 11 content). | +| 7 | Docker Compose | Define and run a real multi-service app (two services, one network, one volume) | lesson, demonstration, knowledge_check, guided_exercise, lab (`docker-compose-multiservice`), reflection | Direct conceptual root of a Kubernetes multi-Pod application. | +| 8 | Containers → Kubernetes | Explain what Kubernetes adds on top of what Docker already does (scheduling, desired state, controllers, service discovery, health management, scaling, rollout) | lesson, knowledge_check, reflection | The explicit bridge module — a student should be able to answer "why Kubernetes" in their own words entering ROOT 05. | + +Assessment: `rootnode-containers-assessment`. + +## Assessments (Step 18) + +Four new `assessment_definitions` rows, one per course, using the existing Phase 3B engine +exactly as `rootnode-security-assessment` (Phase 6C) does — mixing knowledge-recall scenarios +(`type: mcq`) with real state-validation scenarios (`type: task`, the same `runCommand`-backed +mechanism every lab already uses). No KubeKosh/Kubernetes scenario is force-fit into a +non-Kubernetes assessment. See `docs/PHASE6D_ROOT_FOUNDATIONS.md` for which are actually wired +this phase vs. deferred. + +## Duration model + +See `docs/ROOT_PROGRAM_DURATION_MODEL.md` for the derived instructional-hour estimate — computed +from actual `estimated_duration_minutes` values on real activities, not invented. diff --git a/docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md b/docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md new file mode 100644 index 0000000..f008733 --- /dev/null +++ b/docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md @@ -0,0 +1,117 @@ +# ROOT Foundations Lab Strategy + +Phase 6D §7/§10 — what the existing disposable Lab can safely teach for ROOT 01-04, evaluated +by actually reading `backend/server.js` and testing inside a real container, not assumed. + +## 1. The scenario engine is already generic — no new activity type needed + +`POST /api/scenarios/:id/setup` and `POST /api/scenarios/:id/validate` (`backend/server.js`) +run `setup_commands[].command` / `validation.commands[].command` through `runCommand()`, which +is a bare `child_process.exec(cmd)` — an arbitrary shell command string, checked against +`expected_output` by `checkMatch()` (exact/contains/not_contains/regex). **Nothing about this +is Kubernetes-specific.** Every existing scenario just happens to write `kubectl ...` as its +command string. `isolation_type` (`shared_namespace` etc.) is pure descriptive metadata — grepped +across the entire backend and frontend, it gates no actual behavior. + +This means the existing `lab` activity type (`module_activities.activity_type = 'lab'`, +`completion_behavior = 'auto_scenario'`) and the existing `scenarios/data/*.json` format already +fully support Linux, networking-inspection, and Git exercises with real, deterministic +validation — a scenario file with `"command": "test -f /root/lab/notes.txt && echo exists"` is +exactly as valid as one with `"command": "kubectl get pod ..."`. **No `shell_lab`/`git_lab`/ +`container_lab` activity type is built or needed.** The speculative multi-type model the +authorization raised as a possibility is unnecessary — it would duplicate a generic mechanism +that already exists. + +The only wrinkle: `runCommand` does not pass a `cwd`, so every command runs wherever the backend +process's cwd is; multi-step Linux/Git scenarios must `cd /root/lab- && ...` inside each +command string (exactly how a real student would chain commands), not rely on shell state +persisting between `setup` and `validate` calls beyond what the filesystem/git/process state +itself carries. + +## 2. What the Lab image already contains (verified from the real `Dockerfile`) + +Ubuntu 22.04 base with `curl wget git vim nano jq bash-completion iproute2 iptables +iputils-ping procps htop mount kmod python3 nginx` already installed, plus k3s (bundling +`kubectl`/`crictl`/containerd) started by `scripts/entrypoint.sh`. The student terminal execs +into this same container via node-pty — there is no separate "Linux sandbox," it's the same +shell k3s runs in. + +**Already usable with zero image changes:** shell navigation, file manipulation (`cp`/`mv`/`rm`/ +`cat`/`grep`/pipes/redirection), process inspection (`ps`/`top`/`kill`), permissions +(`chmod`/`chown`/`sudo` — the container runs as root, so a permission-teaching scenario should +`useradd` a second user in its `setup_commands` to demonstrate a real permission denial), and +network inspection (`ip addr`/`ip route`/`ss`/`ping`/`curl`). + +**Missing, needed for ROOT 02 Module 5 (DNS & HTTP):** `dig`/`nslookup` are NOT installed +(`dnsutils`/`bind9-dnsutils` is absent from the current package list). This is a genuinely small, +justified Dockerfile addition (one more `apt-get install` package, same risk class as everything +else already there) — not a new mechanism. `curl` alone already covers the HTTP half. + +## 3. Container runtime decision — tested, not assumed + +**Decision: install real Docker Engine (`docker.io`) inside the same already-privileged Lab +container, alongside k3s, as a second independent container runtime with its own nested +`/var/run/docker.sock`.** Podman was not chosen — Docker Engine matches the actual ROOT 04 +curriculum content (Docker CLI, Dockerfile, Compose terminology) and required no new privilege. + +**Why this doesn't weaken the security boundary:** the student Lab container is already +launched with `Privileged: true` (`platform/provisioner/src/lifecycle.js` — required for k3s, +already the accepted threat model per `docs/LAB_ARCHITECTURE.md` §7: the Lab Host VM, not the +container boundary, is what actually contains a student). A second container runtime running +*inside* an already-fully-privileged guest adds no new host capability. **The Lab Host's own +Docker socket is never touched or exposed** — the nested `dockerd` started inside the guest +listens on its own `/var/run/docker.sock` *inside that guest's filesystem namespace*, entirely +separate from the Lab Host's real Docker daemon that the Provisioner itself talks to. + +**Tested empirically** (not assumed) against the exact production resource caps +(`resource-policy.yaml`: 2 vCPU, 4096MB memory, 512 PIDs, `Privileged: true`): built +`rootnode-academy:test` fresh from the real `Dockerfile`, layered `docker.io` on top, launched +it under those exact `docker run` constraints, and ran real workloads inside: + +| Step | Result | Memory | PIDs | +|---|---|---|---| +| k3s alone, ready | ✓ | 357MB | 36 | +| + `dockerd --storage-driver=vfs` started | ✓ | — | — | +| `docker run --rm hello-world` | ✓ passed | — | — | +| `docker run -d -p 8080:80 nginx:alpine`, `curl localhost:8080` | ✓ 200, real HTML returned | 866MB | 159 | +| `docker build` a real 2-line Dockerfile, `docker run` the result | ✓ passed | 884MB | 160 | + +Comfortable headroom remained in all three dimensions (884MB/4096MB, 160/512 PIDs, CPU settled +after the image pull). `--storage-driver=vfs` was used deliberately — overlay2-on-overlay2 +(the Lab Host's own overlay filesystem, nested inside another overlay driver) is a known source +of instability in Docker-in-Docker setups; vfs is slower per-layer but has no such nesting +hazard, and ROOT 04's exercises are small single-purpose images, not build-heavy CI workloads. + +**`docker compose` is NOT included by `docker.io`** — Ubuntu's packaged Docker CLI does not ship +the Compose v2 plugin. Fixed the same way the Dockerfile already fetches k3s: download the +static `docker-compose` v2 binary directly (matching the existing "curl a static binary rather +than add a whole package repository" pattern already used for k3s) into +`/usr/local/lib/docker/cli-plugins/docker-compose` so `docker compose` works as a CLI subcommand. + +**What was NOT done:** no change to the Provisioner, Lab Router, or Gateway. No change to +`HostConfig` (still `Privileged: true`, same CPU/memory/PIDs caps as every other Lab). No mount +of the Lab Host's `/var/run/docker.sock` into any container — verified this was never written +anywhere in this phase's changes. + +## 4. Git strategy + +`git` is already installed. All ROOT 03 exercises use **local repositories created inside the +student's own Lab** (`git init` in a scenario's `setup_commands`) — no Gitea account, no network +credentials, no dependency on RootNode's own canonical repository ever touching a student Lab. +A later module ("Remote Repositories") teaches `clone`/`fetch`/`pull`/`push`/`origin` conceptually +and against a **second local bare repository** created in the same Lab (`git init --bare`, +`git remote add origin /root/lab-remote.git`) to give students a genuine push/pull/clone +round-trip without needing any real network service, credential, or RootNode-adjacent +infrastructure — Step 9's explicit constraint. + +## 5. Classification summary + +| Capability | Classification | +|---|---| +| Shell/filesystem/process/permissions exercises | **SUPPORTED NOW** — zero image or code change | +| Network inspection (`ip`, `ss`, `ping`, `curl`) | **SUPPORTED NOW** | +| DNS tooling (`dig`/`nslookup`) | **REQUIRES SMALL PLATFORM EXTENSION** — one apt package added to the Lab Dockerfile | +| Git exercises (local + local-bare-remote) | **SUPPORTED NOW** — zero image or code change | +| Docker CLI / image build / single containers | **REQUIRES SMALL PLATFORM EXTENSION** — `docker.io` + entrypoint change to start `dockerd`, tested and proven safe/performant above | +| Docker Compose | **REQUIRES SMALL PLATFORM EXTENSION** — static `docker-compose` v2 binary, same pattern as k3s's own binary fetch | +| A distinct `shell_lab`/`git_lab`/`container_lab` activity type | **NOT NEEDED** — the existing generic `lab` + scenario-JSON model already covers all of the above |