From 15b616274ba217ad03639aa9ab29f9904658048b Mon Sep 17 00:00:00 2001 From: ced4568 Date: Wed, 26 Aug 2026 12:59:52 -0500 Subject: [PATCH] feat(root01): author Computing & Linux Foundations, and the real 01->05 prerequisite chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds all 6 ROOT 01 modules (how computers run software, the shell, filesystem navigation, files & text, processes, users & permissions foundations), each with a real lesson, demonstration/guided exercise, knowledge check where warranted, a hands-on Lab, and a reflection — 35 activities, 29 new content files. Adds 6 new hands-on Linux scenarios (linux-inspect-hardware, linux-shell-basics, linux-filesystem-navigation, linux-files-and-text, linux-process-management, linux-permissions-foundations) plus 2 MCQ scenarios, using the existing generic scenario/ validation engine (docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md §1) — every one tested end-to-end via the real scenario setup/validate API, including negative tests confirming they correctly FAIL when not actually solved (e.g. the process-management scenario fails while the target process is still running; the permissions scenario is tested against a real `su - labuser` denial). Wires rootnode-linux-foundations-assessment (2 required + 4 random-draw scenarios) using the existing Phase 3B assessment engine. Adds a real, server-side ROOT 01->02->03->04->05 course prerequisite chain (courses.prerequisites) — verified live on two students: one who completed ROOT 01 sees ROOT 02 unlock; a fresh student sees ROOT 02 correctly locked while 03/04/05 stay vacuously satisfied (their own prerequisite courses are still empty). ROOT 06+ and the Capstone are unaffected. Co-Authored-By: Claude Sonnet 5 --- .../01-lesson-how-computers-run-software.md | 66 ++++++++ ...ided-exercise-inspect-hardware-on-paper.md | 35 +++++ .../03-reflection.md | 27 ++++ .../01-lesson-linux-and-the-shell.md | 58 +++++++ .../02-demonstration-exit-codes-in-action.md | 49 ++++++ .../03-knowledge-check.md | 37 +++++ ...4-guided-exercise-predicting-exit-codes.md | 31 ++++ .../m02-linux-and-the-shell/05-reflection.md | 25 +++ .../01-lesson-filesystem-navigation.md | 55 +++++++ .../02-demonstration-absolute-vs-relative.md | 43 +++++ .../03-knowledge-check.md | 36 +++++ ...04-guided-exercise-planning-a-structure.md | 39 +++++ .../05-reflection.md | 27 ++++ .../01-lesson-files-and-text.md | 52 ++++++ .../02-demonstration-pipes-and-redirection.md | 56 +++++++ .../m04-files-and-text/03-knowledge-check.md | 37 +++++ ...guided-exercise-choosing-the-right-tool.md | 31 ++++ .../m04-files-and-text/05-reflection.md | 26 +++ .../m05-processes/01-lesson-processes.md | 64 ++++++++ ...02-demonstration-watching-a-process-die.md | 53 +++++++ .../m05-processes/03-knowledge-check.md | 38 +++++ .../04-guided-exercise-signals.md | 28 ++++ .../m05-processes/05-reflection.md | 27 ++++ .../01-lesson-users-and-permissions.md | 59 +++++++ .../02-demonstration-permission-denied.md | 55 +++++++ .../03-knowledge-check.md | 38 +++++ .../04-guided-exercise-least-privilege.md | 32 ++++ .../05-reflection.md | 33 ++++ .../025_phase6d_root_foundations_root01.sql | 148 ++++++++++++++++++ scenarios/data/linux-exit-codes-mcq.json | 22 +++ scenarios/data/linux-files-and-text.json | 31 ++++ .../data/linux-filesystem-navigation.json | 32 ++++ scenarios/data/linux-inspect-hardware.json | 36 +++++ .../data/linux-permissions-foundations.json | 37 +++++ scenarios/data/linux-permissions-mcq.json | 22 +++ scenarios/data/linux-process-management.json | 34 ++++ scenarios/data/linux-shell-basics.json | 30 ++++ 37 files changed, 1549 insertions(+) create mode 100644 content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/01-lesson-how-computers-run-software.md create mode 100644 content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/02-guided-exercise-inspect-hardware-on-paper.md create mode 100644 content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/03-reflection.md create mode 100644 content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/01-lesson-linux-and-the-shell.md create mode 100644 content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/02-demonstration-exit-codes-in-action.md create mode 100644 content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/03-knowledge-check.md create mode 100644 content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/04-guided-exercise-predicting-exit-codes.md create mode 100644 content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/05-reflection.md create mode 100644 content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/01-lesson-filesystem-navigation.md create mode 100644 content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/02-demonstration-absolute-vs-relative.md create mode 100644 content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/03-knowledge-check.md create mode 100644 content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/04-guided-exercise-planning-a-structure.md create mode 100644 content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/05-reflection.md create mode 100644 content/root/root-01-computing-linux-foundations/m04-files-and-text/01-lesson-files-and-text.md create mode 100644 content/root/root-01-computing-linux-foundations/m04-files-and-text/02-demonstration-pipes-and-redirection.md create mode 100644 content/root/root-01-computing-linux-foundations/m04-files-and-text/03-knowledge-check.md create mode 100644 content/root/root-01-computing-linux-foundations/m04-files-and-text/04-guided-exercise-choosing-the-right-tool.md create mode 100644 content/root/root-01-computing-linux-foundations/m04-files-and-text/05-reflection.md create mode 100644 content/root/root-01-computing-linux-foundations/m05-processes/01-lesson-processes.md create mode 100644 content/root/root-01-computing-linux-foundations/m05-processes/02-demonstration-watching-a-process-die.md create mode 100644 content/root/root-01-computing-linux-foundations/m05-processes/03-knowledge-check.md create mode 100644 content/root/root-01-computing-linux-foundations/m05-processes/04-guided-exercise-signals.md create mode 100644 content/root/root-01-computing-linux-foundations/m05-processes/05-reflection.md create mode 100644 content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/01-lesson-users-and-permissions.md create mode 100644 content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/02-demonstration-permission-denied.md create mode 100644 content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/03-knowledge-check.md create mode 100644 content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/04-guided-exercise-least-privilege.md create mode 100644 content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/05-reflection.md create mode 100644 platform/api/migrations/025_phase6d_root_foundations_root01.sql create mode 100644 scenarios/data/linux-exit-codes-mcq.json create mode 100644 scenarios/data/linux-files-and-text.json create mode 100644 scenarios/data/linux-filesystem-navigation.json create mode 100644 scenarios/data/linux-inspect-hardware.json create mode 100644 scenarios/data/linux-permissions-foundations.json create mode 100644 scenarios/data/linux-permissions-mcq.json create mode 100644 scenarios/data/linux-process-management.json create mode 100644 scenarios/data/linux-shell-basics.json diff --git a/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/01-lesson-how-computers-run-software.md b/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/01-lesson-how-computers-run-software.md new file mode 100644 index 0000000..09ced5a --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/01-lesson-how-computers-run-software.md @@ -0,0 +1,66 @@ +# How Computers Run Software + +## Hardware, OS, and application: three different layers + +When you run a program, three distinct layers cooperate: + +- **Hardware** — the physical CPU, RAM, and storage. It has no idea what a "file" or a "process" + is; it just executes instructions and stores bits. +- **The operating system (kernel)** — the layer that turns raw hardware into something usable: + it decides which program gets the CPU next, hands out memory, and organizes storage into + files and directories. Linux is a kernel plus a large set of standard tools around it. +- **Applications (userspace)** — the programs you actually run. They ask the kernel for + resources (memory, files, network) through a well-defined interface (system calls) instead of + touching hardware directly. + +This module gives you just enough of this model to reason about what you're actually looking at +for the rest of ROOT_ — not a full computer architecture course. + +## CPU: the thing that actually executes instructions + +A CPU has some number of **cores** — each core can run one stream of instructions at a time. +`nproc` tells you how many cores/threads Linux believes it has available. When a system feels +"slow," it's very often because more processes want CPU time than there are cores to give them. + +## RAM: fast, temporary, and finite + +RAM holds the data and code a running program is actively using. It's fast but **volatile** — +its contents disappear when power is lost, which is exactly why persistent data lives on +storage instead. `free -h` shows you total memory, how much is in use, and how much is free. + +## Storage: slower, but persistent + +Storage (an SSD/disk) keeps data even when the machine is off. It's organized into a +**filesystem** — the tree of directories and files you already have some intuition for. `df -h` +shows how much space exists and how much is used on each mounted filesystem. + +## Processes: a running program + +A **process** is a program actually being executed — code plus its own private memory, tracked +by the kernel with a unique ID (a PID). One program can have many processes running at once +(open two terminals running the same shell, and you have two separate processes). ROOT 01 +Module 5 goes much deeper into this; for now, just know: everything you run becomes a process +the kernel is responsible for scheduling onto a CPU core. + +## Why this matters for everything after this module + +Every concept the rest of ROOT_ builds on is a refinement of this same idea. A container is +(mostly) an isolated process with its own filesystem view. A Kubernetes Pod is a group of +containers the scheduler places onto a specific machine's CPU/RAM. None of that will make sense +as anything other than magic if you don't first have this base model of what a computer is +actually managing. + +## Instructor Notes + +**Lesson goal:** Give students just enough of a mental model to stop treating "the computer" as +an opaque box — without turning this into a full CS/architecture course. + +**Approximate timing:** 15 minutes read; 10 minutes live with discussion. + +**Common misconception to watch for:** students often conflate RAM and storage ("my computer +has 8GB" meaning disk space). Draw the volatile-vs-persistent distinction explicitly and early. + +**Discussion question:** "Why can't a program just talk to the hardware directly instead of +going through the kernel?" (Answer: the kernel is what lets many programs safely share one CPU/ +one block of RAM without stepping on each other — this is worth naming explicitly, as it's the +root of why containers and Kubernetes are even possible.) diff --git a/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/02-guided-exercise-inspect-hardware-on-paper.md b/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/02-guided-exercise-inspect-hardware-on-paper.md new file mode 100644 index 0000000..8f51597 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/02-guided-exercise-inspect-hardware-on-paper.md @@ -0,0 +1,35 @@ +# Guided Exercise: Predict Before You Look + +Before you run the real inspection commands in the Lab, commit to a guess — this is what makes +the real numbers meaningful instead of just scrolling past them. + +## Your task + +On paper or in a scratch file, write down your best GUESS for: + +1. How many CPU cores does this machine have? +2. How much total RAM, roughly, in GB? +3. How much free disk space is on the root filesystem? + +Then think through: which of these three would you expect a "student Lab" environment to be +MOST constrained on, and why? (Hint: think about what happens if 50 students are each running +their own Lab on one shared physical machine at the same time.) + +## A worked shape to check yourself against + +There's no single right numeric answer here — the point is the habit of predicting first. A +reasonable answer to the "most constrained" question: memory and CPU are typically the tightest +shared resource on a multi-tenant host, since every additional Lab needs its own slice of both, +while disk is comparatively cheap to over-provision. + +## Instructor Notes + +**Facilitation:** Have students commit to a number verbally or on a shared doc BEFORE anyone +runs the real commands — the value is in noticing the gap between guess and reality, not in +getting it right. + +**Approximate timing:** 5 minutes. + +**Optional extension:** ask what would happen to their guess if this were a "real" laptop +they personally own vs. a shared cloud server — good primer for later resource-limit +discussions (ROOT 06's resource requests/limits, ROOT 09's resource governance). diff --git a/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/03-reflection.md b/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/03-reflection.md new file mode 100644 index 0000000..988c5fb --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/03-reflection.md @@ -0,0 +1,27 @@ +# Reflection: You Just Looked Inside the Box + +## Reflection questions + +1. How close was your guess to the real numbers? What surprised you most? +2. Name one thing you now understand about "the computer" that you couldn't have explained + before this module. +3. When you eventually run `kubectl describe pod` and see `requests`/`limits` for CPU and + memory, what do you now expect those numbers to actually be constraining? + +## Real Ops takeaway + +**Every resource limit you'll ever configure — in Docker, in Kubernetes, in a systemd unit — is +a promise about exactly the three things this module named: CPU, memory, and storage.** You +can't reason well about "why did my container get killed" or "why is my Pod stuck Pending" +without this base model. This module isn't computer-science trivia — it's the vocabulary the +rest of ROOT_ assumes you have. + +This module is complete. Continue to the next module. + +## Instructor Notes + +**Discussion questions for a live classroom:** question 3 is worth spending real time on — it's +the first moment students connect this abstract lesson to something they'll type as a real +command many courses from now. Naming that connection explicitly here pays off later. + +**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing. diff --git a/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/01-lesson-linux-and-the-shell.md b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/01-lesson-linux-and-the-shell.md new file mode 100644 index 0000000..db7dd26 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/01-lesson-linux-and-the-shell.md @@ -0,0 +1,58 @@ +# Linux and the Shell + +## What "Linux" actually means + +Linux is a **kernel** — the core piece of software from Module 1 that manages CPU, memory, and +storage. What most people call "a Linux system" (Ubuntu, Debian, Fedora, Alpine...) is a +**distribution**: the Linux kernel plus a chosen set of standard tools, package manager, and +configuration conventions layered on top. Different distributions, same kernel underneath — +which is why a command you learn on Ubuntu mostly still works on Alpine. + +## Shell vs. terminal + +These get used interchangeably but are different things: + +- The **terminal** is the window/program that displays text and sends your keystrokes somewhere. +- The **shell** is the program actually interpreting what you type as commands — `bash` is the + shell this Lab uses. The terminal is just the display; the shell is the brain. + +## Command structure + +Every command follows roughly the same shape: + +``` +command [options] [arguments] +``` + +`ls -la /var/log` — `ls` is the command, `-la` are options (flags) that change its behavior, +`/var/log` is the argument (what to act on). Options can usually be combined (`-l -a` = `-la`). + +## Exit codes: how a command reports success or failure + +Every command returns a number when it finishes: `0` means success, anything else (1-255) means +some kind of failure. This isn't a Linux quirk — it's the exact mechanism scripts, CI pipelines, +and (much later) Kubernetes health checks all rely on to know whether something worked. You can +read the last command's exit code with the special variable `$?`. + +## Getting help without leaving the terminal + +- **Tab completion** — press Tab while typing a command or path; the shell completes it for you + or shows you the options. This is a genuine time-saver, not just a convenience. +- **Command history** — press the Up arrow to recall previous commands; `history` lists them. +- **`man `** — the manual page for almost any command, with every option explained. + `man ls`, `man grep`, `man chmod` are all real, useful references — reaching for `man` before + a search engine is a habit worth building now. + +## Instructor Notes + +**Lesson goal:** Establish shell fluency vocabulary (shell vs. terminal, exit codes, options vs. +arguments) that every later module assumes without re-explaining. + +**Approximate timing:** 15 minutes read; 10 minutes live with a short live demo of tab +completion and `man`. + +**Common misconception to watch for:** students often think "Linux" and "the terminal" are the +same thing — clarify the kernel/distribution/shell/terminal layering explicitly. + +**Demo idea:** live-type a command that fails (e.g. `ls /nonexistent`), then run `echo $?` +immediately after to show the exit code in real time — more convincing than describing it. diff --git a/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/02-demonstration-exit-codes-in-action.md b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/02-demonstration-exit-codes-in-action.md new file mode 100644 index 0000000..eeafb7c --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/02-demonstration-exit-codes-in-action.md @@ -0,0 +1,49 @@ +# Demonstration: Watching Exit Codes in Real Time + +## OBSERVE + +Run a command you know will succeed, then immediately check its exit code: + +``` +$ true +$ echo $? +0 +``` + +## HYPOTHESIS + +Now predict: what will the exit code be if the command fails instead? + +## INSPECT + +Run a command that fails, and check immediately: + +``` +$ ls /this-does-not-exist +ls: cannot access '/this-does-not-exist': No such file or directory +$ echo $? +2 +``` + +## CHANGE + +Try a few other failing commands and note their codes: `grep nomatch /etc/hostname` (exit 1 — +"no matches found," a different kind of failure than "file not found"). + +## VERIFY + +Notice: exit codes aren't just "0 or 1" — different failures often get different non-zero +codes. `0` always means success; the exact non-zero value's MEANING varies by command, but ANY +non-zero value reliably means "something went wrong," which is the part every script actually +relies on (`if command; then ... else ...`). + +## Instructor Notes + +**Demo goal:** Make the abstract "exit code" concept concrete by actually watching `$?` change +in real time, immediately after each command — this is far more convincing live than described +in prose. + +**Approximate timing:** 8 minutes live. + +**Common mistake to watch for:** running `echo $?` after ANY other command in between (even +`ls`) silently checks the WRONG command's exit code — emphasize "check it immediately." diff --git a/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/03-knowledge-check.md b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/03-knowledge-check.md new file mode 100644 index 0000000..c4a02f6 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/03-knowledge-check.md @@ -0,0 +1,37 @@ +# Knowledge Check: Linux and the Shell + +--- + +**1. What's the difference between a shell and a terminal?** + +*Answer:* The terminal is the window/program that displays text and captures keystrokes; the +shell (e.g. `bash`) is the program actually interpreting what you type as commands. The terminal +is the display, the shell is the brain. + +--- + +**2. A command exits with code `0`. What does that tell you?** + +*Answer:* It succeeded. `0` is the universal "success" convention every script and pipeline +relies on; any non-zero value means some kind of failure occurred. + +--- + +**3. You've typed half a long path and can't remember the rest. What should you press?** + +*Answer:* Tab — tab completion finishes the path (or shows the options) without you needing to +type or remember it exactly. + +--- + +**4. Where would you look to learn every option a command supports, without leaving the +terminal?** + +*Answer:* Its manual page — `man `. + +## Instructor Notes + +**Facilitation:** Question 1 is the one students most often blur together — worth confirming +verbally before moving on. + +**Approximate timing:** 5 minutes. diff --git a/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/04-guided-exercise-predicting-exit-codes.md b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/04-guided-exercise-predicting-exit-codes.md new file mode 100644 index 0000000..fca3969 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/04-guided-exercise-predicting-exit-codes.md @@ -0,0 +1,31 @@ +# Guided Exercise: Predict the Exit Code Before You Run It + +This is a paper exercise — commit to an answer before checking it in the Lab. + +## Your task + +For each command below, predict whether its exit code will be `0` (success) or non-zero +(failure), and why: + +1. `cat /etc/hostname` (a file that exists) +2. `cat /etc/does-not-exist-at-all` (a file that doesn't) +3. `grep root /etc/passwd` (a pattern that's very likely present) +4. `grep zzz-not-a-real-user /etc/passwd` (a pattern that's very likely absent) +5. `mkdir /tmp/already-exists && mkdir /tmp/already-exists` (running the same `mkdir` twice) + +## A worked shape to check yourself against + +1. `0` — the file exists and is readable. +2. Non-zero — the file doesn't exist, `cat` fails. +3. `0` — `grep` succeeds (exit 0) when it finds at least one match. +4. Non-zero (specifically `1`) — `grep` "fails" when it finds NO matches, even though nothing + went technically wrong. This is a common surprise: `grep`'s exit code means "did I find a + match," not "did an error occur." +5. The SECOND `mkdir` fails (non-zero) — the directory already exists. The first one succeeds. + +## Instructor Notes + +**Facilitation:** Item 4 is the one worth pausing on — many students assume "no error message" +means "exit code 0," and `grep`'s no-match convention is a good early counter-example. + +**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced. diff --git a/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/05-reflection.md b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/05-reflection.md new file mode 100644 index 0000000..668e32f --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/05-reflection.md @@ -0,0 +1,25 @@ +# Reflection: Exit Codes Are Everywhere After This + +## Reflection questions + +1. Before this module, did you know commands returned a machine-readable success/failure + signal at all? What did you assume happened instead? +2. Where do you think exit codes might matter later in ROOT_ — in a script, a CI pipeline, or + a container? + +## Real Ops takeaway + +**Every automated system you'll ever build or operate checks exit codes, not error messages.** +A script deciding whether to continue, a CI pipeline deciding whether to deploy, and (much +later) a container orchestrator deciding whether a process is healthy, all reduce to the exact +same question this module taught you to answer by hand: did this exit `0` or not? Getting +comfortable checking `$?` now means none of those later systems will feel like magic. + +This module is complete. Continue to the next module. + +## Instructor Notes + +**Discussion questions for a live classroom:** question 2 previews Docker/Kubernetes health +checks well before students get there — useful to name explicitly without going deep yet. + +**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing. diff --git a/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/01-lesson-filesystem-navigation.md b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/01-lesson-filesystem-navigation.md new file mode 100644 index 0000000..e901dde --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/01-lesson-filesystem-navigation.md @@ -0,0 +1,55 @@ +# Navigating the Filesystem + +## Everything is one tree, starting at `/` + +Linux has exactly one filesystem tree, rooted at `/` (pronounced "root," unrelated to your +username). Every file and directory, no matter what physical disk it's actually on, appears +somewhere under this one tree — there's no separate "C:\" and "D:\" the way Windows shows +multiple drives. + +## Absolute vs. relative paths + +An **absolute path** starts with `/` and always means the same location no matter where you +currently are: `/home/student/notes.txt`. A **relative path** is interpreted relative to your +CURRENT directory: `notes.txt` means something different depending on where you're standing +when you type it. `.` means "this directory," `..` means "one directory up" — `cd ..` moves up +one level, `cd ../..` moves up two. + +## Key commands + +- `pwd` — print your current directory (where am I?) +- `ls` — list what's in a directory (`ls -la` shows hidden files and details) +- `cd ` — change directory (absolute or relative) + +## Hidden files + +A file or directory starting with `.` (like `.bashrc` or `.config`) is "hidden" — `ls` skips it +by default, `ls -a` shows it. This isn't a security feature, just a convention to keep +configuration/metadata files out of the way of normal directory listings. + +## The important top-level directories (conceptually, not memorized) + +You don't need to memorize the entire Filesystem Hierarchy Standard, but recognizing these by +purpose will save you real confusion later: + +- **`/etc`** — system-wide configuration files (nginx's config lives at `/etc/nginx/nginx.conf`) +- **`/var`** — variable data that changes while the system runs: logs (`/var/log`), among others +- **`/home`** — personal directories for regular users +- **`/tmp`** — temporary files, safe to assume anything here can disappear on reboot +- **`/usr`** — most installed programs and their supporting files live somewhere under here +- **`/proc`** — not real files on disk at all — a live, kernel-generated view into running + processes and system state (you'll use this again in Module 5) + +## Instructor Notes + +**Lesson goal:** Give students a working mental model of "one tree, absolute vs. relative +paths" plus just enough top-level-directory recognition to not be lost later — not FHS +memorization. + +**Approximate timing:** 15 minutes read; 10 minutes live. + +**Common misconception to watch for:** students coming from Windows sometimes expect separate +drives/roots — emphasize the single unified tree explicitly. + +**Demo idea:** `cd /` then `ls`, narrating what each top-level directory is for as you see it, +rather than listing them in the abstract. diff --git a/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/02-demonstration-absolute-vs-relative.md b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/02-demonstration-absolute-vs-relative.md new file mode 100644 index 0000000..fb4ab2d --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/02-demonstration-absolute-vs-relative.md @@ -0,0 +1,43 @@ +# Demonstration: The Same Word, Two Different Destinations + +## OBSERVE + +Starting from `/home/student`, run `cd project` — you land at `/home/student/project`. + +## HYPOTHESIS + +Now, from `/home/student/project`, what do you predict `cd project` will do this time? + +## INSPECT + +``` +$ pwd +/home/student/project +$ cd project +bash: cd: project: No such file or directory +``` + +It fails — there's no `project` directory INSIDE `project` (unless you happened to create one). +The exact same relative path meant something completely different depending on where you stood. + +## CHANGE + +From `/home/student/project`, run `cd ../project` instead — this correctly goes back up one +level, then into `project` again, landing you right back where you started. + +## VERIFY + +`pwd` after each `cd` to confirm exactly where you ended up — this habit (verify your location +before assuming it) prevents a huge share of "why did my command run somewhere unexpected" +confusion later. + +## Instructor Notes + +**Demo goal:** Make "relative paths depend on where you are" concrete and slightly surprising, +rather than an abstract rule to memorize. + +**Approximate timing:** 8 minutes live. + +**Common mistake to watch for:** students assume a relative path always means the SAME thing +once they've used it once — reinforce that it's re-evaluated fresh every time, from wherever +they currently are. diff --git a/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/03-knowledge-check.md b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/03-knowledge-check.md new file mode 100644 index 0000000..26a50e3 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/03-knowledge-check.md @@ -0,0 +1,36 @@ +# Knowledge Check: Navigating the Filesystem + +--- + +**1. What does `..` mean in a path?** + +*Answer:* One directory up from your current location. + +--- + +**2. You're at `/home/student/project`. Does `cd project` do the same thing here as it did at +`/home/student`?** + +*Answer:* No — a relative path is re-evaluated from your CURRENT location every time. At +`/home/student`, `project` refers to `/home/student/project`; from inside that same directory, +`project` would refer to `/home/student/project/project`, which likely doesn't exist. + +--- + +**3. A file is "hidden" from a normal `ls`. What actually makes it hidden?** + +*Answer:* Its name starts with a `.` — it's purely a naming convention `ls` respects by +default, not a real permission or security feature. `ls -a` shows it. + +--- + +**4. Where would you expect to find a running system's log files?** + +*Answer:* `/var/log` — `/var` holds data that changes while the system runs. + +## Instructor Notes + +**Facilitation:** Question 2 is the one worth confirming out loud — it's the core "gotcha" of +relative paths. + +**Approximate timing:** 5 minutes. diff --git a/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/04-guided-exercise-planning-a-structure.md b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/04-guided-exercise-planning-a-structure.md new file mode 100644 index 0000000..f597427 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/04-guided-exercise-planning-a-structure.md @@ -0,0 +1,39 @@ +# Guided Exercise: Plan a Directory Structure on Paper First + +Before you build anything in the Lab, plan it — this is the same discipline you'll use later +when planning a Kubernetes namespace layout or a Git repository structure. + +## Your task + +You're setting up a small project called `weather-app`. On paper, sketch a directory tree +containing: + +- A place for source code +- A place for documentation +- A place for tests +- A single hidden configuration file at the project's root + +Write out the exact `mkdir` and file-creation commands you'd use, including whether each path +you write is absolute or relative. + +## A worked shape to check yourself against + +``` +mkdir -p weather-app/src weather-app/docs weather-app/tests +echo "ready" > weather-app/.config +``` + +(Or with an absolute path: `mkdir -p /srv/weather-app/src ...`.) The `-p` flag matters here — +without it, `mkdir` refuses to create `weather-app/src` if `weather-app` doesn't already exist. + +## Instructor Notes + +**Facilitation:** Have students commit to their command in writing before revealing the worked +answer — the value is in noticing what `-p` actually buys them, not just copying a correct +command. + +**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced. + +**Common mistake to watch for:** forgetting `mkdir -p` and getting a "No such file or +directory" error when creating a nested path in one command — a good moment to connect back to +Module 2's exit-code lesson (that error IS a non-zero exit code). diff --git a/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/05-reflection.md b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/05-reflection.md new file mode 100644 index 0000000..49946ac --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/05-reflection.md @@ -0,0 +1,27 @@ +# Reflection: Structure Isn't Bureaucracy, It's Communication + +## Reflection questions + +1. Why might a real engineering team insist on a consistent directory structure across every + project, instead of everyone organizing files however they like? +2. Which of `/etc`, `/var`, `/home`, `/tmp`, `/usr`, `/proc` do you feel most confident you could + explain to someone else right now? Which one still feels fuzzy? + +## Real Ops takeaway + +**A predictable filesystem layout is what lets tools (and other engineers) reason about a +system without asking you first.** `/etc` always means configuration, `/var/log` always means +logs — this convention is exactly why a monitoring tool can be pointed at "check `/var/log`" on +any Linux machine and just work. Container images later inherit this same convention (an +nginx container still keeps its config at `/etc/nginx/nginx.conf`) — you're not learning a +one-off Linux fact, you're learning a convention that outlives this specific module. + +This module is complete. Continue to the next module. + +## Instructor Notes + +**Discussion questions for a live classroom:** question 1 connects directly to why Kubernetes +namespaces and Git repository conventions matter later — a good moment to name that connection +without going deep yet. + +**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing. diff --git a/content/root/root-01-computing-linux-foundations/m04-files-and-text/01-lesson-files-and-text.md b/content/root/root-01-computing-linux-foundations/m04-files-and-text/01-lesson-files-and-text.md new file mode 100644 index 0000000..7543f3e --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m04-files-and-text/01-lesson-files-and-text.md @@ -0,0 +1,52 @@ +# Files and Text + +## Basic file operations + +- `touch ` — create an empty file (or update its timestamp if it exists) +- `mkdir ` — create a directory (`-p` creates any missing parent directories too) +- `cp ` — copy a file +- `mv ` — move OR rename a file (Linux treats renaming as "moving to a new name in + the same place") +- `rm ` — delete a file (`-r` for a directory, `-f` to skip confirmation — dangerous + combined: `rm -rf` deletes without asking, permanently) + +## Reading text + +- `cat ` — print the whole file at once +- `less ` — page through a file interactively (press `q` to quit) — the right tool for + anything too long to read in one screen +- `head ` / `tail ` — the first/last 10 lines by default (`-n 20` for a different + count); `tail -f` follows a file live as new lines are appended — exactly how you'd watch a + log file update in real time + +## Searching text: `grep` + +`grep PATTERN file` prints only the lines matching PATTERN. This is one of the most-used +commands in real operations work — "find the lines that matter" beats "read everything." + +## Pipes and redirection: composing commands + +- **A pipe (`|`)** sends one command's output as the next command's input: + `cat app.log | grep ERROR` — read the file, then filter it. +- **Redirection (`>`)** sends a command's output into a file instead of the screen (overwriting + it): `grep ERROR app.log > errors.txt`. `>>` appends instead of overwriting. + +## stdout vs. stderr + +A command actually has TWO separate output streams: **stdout** (normal output) and **stderr** +(error messages), even though both print to your screen by default. This is why +`command 2>/dev/null` (redirecting stream `2`, stderr, to nowhere) can suppress error noise +while still showing normal output — you'll use exactly this pattern in later Labs. + +## Instructor Notes + +**Lesson goal:** Build real fluency composing small commands together — this is the single +highest-leverage Linux skill for troubleshooting work later in ROOT_. + +**Approximate timing:** 15 minutes read; 10 minutes live. + +**Common misconception to watch for:** students often don't realize stdout/stderr are separate +streams until they see `2>/dev/null` change what's suppressed — worth demonstrating live. + +**Demo idea:** run a command that produces both real output and an error in the same call +(e.g. `ls /etc /nonexistent`) and show how `2>/dev/null` changes what appears. diff --git a/content/root/root-01-computing-linux-foundations/m04-files-and-text/02-demonstration-pipes-and-redirection.md b/content/root/root-01-computing-linux-foundations/m04-files-and-text/02-demonstration-pipes-and-redirection.md new file mode 100644 index 0000000..0fe01ae --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m04-files-and-text/02-demonstration-pipes-and-redirection.md @@ -0,0 +1,56 @@ +# Demonstration: Filtering a Log Down to What Matters + +## OBSERVE + +A raw log file has five lines mixing `INFO` and `ERROR`: + +``` +$ cat app.log +INFO: boot ok +ERROR: disk full +INFO: retry +ERROR: timeout +INFO: done +``` + +## HYPOTHESIS + +Predict what `grep ERROR app.log` will print, before running it. + +## INSPECT + +``` +$ grep ERROR app.log +ERROR: disk full +ERROR: timeout +``` + +Only the matching lines — everything else is filtered out. + +## CHANGE + +Now redirect that filtered result into a new file instead of just viewing it: + +``` +$ grep ERROR app.log > errors.txt +$ cat errors.txt +ERROR: disk full +ERROR: timeout +``` + +## VERIFY + +Count how many lines actually matched, without eyeballing them: `wc -l < errors.txt` (or +`grep -c ERROR app.log` directly). This composition — filter, then count, then act — is the +exact shape of a huge share of real troubleshooting work. + +## Instructor Notes + +**Demo goal:** Show the filter → redirect → verify chain as one continuous, composable +workflow, not three unrelated commands. + +**Approximate timing:** 8 minutes live. + +**Common mistake to watch for:** using `>` when they meant `>>` and accidentally overwriting a +file they wanted to append to — worth calling out explicitly since it's a real, common mistake +with no undo. diff --git a/content/root/root-01-computing-linux-foundations/m04-files-and-text/03-knowledge-check.md b/content/root/root-01-computing-linux-foundations/m04-files-and-text/03-knowledge-check.md new file mode 100644 index 0000000..d530c78 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m04-files-and-text/03-knowledge-check.md @@ -0,0 +1,37 @@ +# Knowledge Check: Files and Text + +--- + +**1. What's the difference between `>` and `>>`?** + +*Answer:* `>` overwrites the target file's contents entirely; `>>` appends to the end of it, +preserving what was already there. + +--- + +**2. A command prints both normal output and an error message. What are these two streams +called?** + +*Answer:* stdout (normal output) and stderr (error messages) — two separate streams that both +happen to print to your screen by default. + +--- + +**3. You want to watch a log file update live, as new lines are appended, without re-running a +command repeatedly.** + +*Answer:* `tail -f ` — follows the file and prints new lines as they're written. + +--- + +**4. `cat app.log | grep ERROR`. What does the `|` actually do?** + +*Answer:* It pipes `cat`'s output directly into `grep`'s input, so `grep` filters the file's +contents without needing a separate temporary file. + +## Instructor Notes + +**Facilitation:** Question 2 is worth a live show-of-hands check — many students haven't +consciously registered that stdout/stderr are separate until this module. + +**Approximate timing:** 5 minutes. diff --git a/content/root/root-01-computing-linux-foundations/m04-files-and-text/04-guided-exercise-choosing-the-right-tool.md b/content/root/root-01-computing-linux-foundations/m04-files-and-text/04-guided-exercise-choosing-the-right-tool.md new file mode 100644 index 0000000..ac2194d --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m04-files-and-text/04-guided-exercise-choosing-the-right-tool.md @@ -0,0 +1,31 @@ +# Guided Exercise: Which Tool Actually Answers the Question? + +This is a paper exercise — commit to an answer before checking it in the Lab. + +## Your task + +For each situation, name the ONE command (or short pipeline) you'd reach for first: + +1. You want to see just the last 20 lines of a 50,000-line log file. +2. You want to know how many lines in a file contain the word "timeout." +3. You want to watch a log file update live while a process is running. +4. You want to see a file's full contents but it's too long for one screen and you want to + scroll through it interactively. + +## A worked shape to check yourself against + +1. `tail -n 20 file.log` +2. `grep -c timeout file.log` +3. `tail -f file.log` +4. `less file.log` + +Notice: `cat` would technically "work" for #4 too, but it dumps everything at once with no way +to scroll back — `less` is the actual right tool once a file is longer than one screen. + +## Instructor Notes + +**Facilitation:** Item 4 is worth discussing explicitly — "it works" isn't the same bar as +"it's the right tool for this situation," and that distinction matters more as commands compose +into real troubleshooting workflows. + +**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced. diff --git a/content/root/root-01-computing-linux-foundations/m04-files-and-text/05-reflection.md b/content/root/root-01-computing-linux-foundations/m04-files-and-text/05-reflection.md new file mode 100644 index 0000000..9e40088 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m04-files-and-text/05-reflection.md @@ -0,0 +1,26 @@ +# Reflection: Filtering Is a Reasoning Skill, Not a Syntax Trick + +## Reflection questions + +1. Before this module, how would you have found "the important lines" in a huge log file? + How does that compare to `grep`? +2. Which combination (pipe, redirect, or a specific command like `tail -f`) do you expect to + use the most once you're doing real troubleshooting work? + +## Real Ops takeaway + +**"Read everything and eyeball it" does not scale — filtering does.** Every troubleshooting +framework you'll learn later in ROOT_ (starting with ROOT 02's own version, then again more +formally in ROOT 10) depends on being able to quickly narrow a huge amount of system output down +to the handful of lines that actually matter. `grep`, pipes, and redirection are the first real +tools you have for that — not a syntax exercise, a reasoning skill. + +This module is complete. Continue to the next module. + +## Instructor Notes + +**Discussion questions for a live classroom:** question 1 often produces good answers ("I'd +just scroll and read") that make the value of filtering obvious by contrast — let students +articulate this themselves rather than stating it for them. + +**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing. diff --git a/content/root/root-01-computing-linux-foundations/m05-processes/01-lesson-processes.md b/content/root/root-01-computing-linux-foundations/m05-processes/01-lesson-processes.md new file mode 100644 index 0000000..48c8c19 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m05-processes/01-lesson-processes.md @@ -0,0 +1,64 @@ +# Processes + +## What a process actually is + +A **process** is a running instance of a program — its own code, its own private memory, and a +unique identifier the kernel tracks called a **PID** (Process ID). Run the same program twice +(open two terminals both running `bash`), and you get two separate processes with two different +PIDs, even though they're running identical code. + +## Foreground vs. background + +A command you run normally occupies your terminal until it finishes (**foreground**) — you +can't type anything else until it's done. Append `&` to run it in the **background** instead, +freeing your terminal immediately while the process keeps running. `sleep 300 &` starts a +300-second sleep in the background and hands your prompt right back. + +## Inspecting processes: `ps` and `top` + +- `ps aux` — a snapshot of every process currently running, including its PID, how much CPU/ + memory it's using, and the exact command that started it. +- `top` (or `htop`, if installed) — the same idea, but live-updating and sorted by resource + usage, useful for "what's actually eating CPU/memory right now." + +## Stopping a process: `kill` and signals + +`kill ` doesn't instantly destroy a process — it sends it a **signal**, a message the +process can (usually) choose how to respond to. The default signal, `SIGTERM` (15), politely +asks a process to shut down, giving it a chance to clean up first. `kill -9 ` sends +`SIGKILL`, which the kernel enforces immediately with no chance for the process to react — +appropriate only when a process is truly stuck and ignoring `SIGTERM`. `kill -0 ` is a +special case: it sends NO real signal at all, just checks whether the PID still exists — +exactly how you confirm "did that process actually stop" without side effects. + +## Process hierarchy + +Every process (except the very first one at boot) has a **parent** — the process that started +it. Your shell is the parent of every command you run from it. This matters later: a parent +process's own lifecycle can affect its children (this is part of why a container, which is +often just one process tree, behaves the way it does when its main process exits). + +## Why this matters for containers and Kubernetes + +A container is, underneath, mostly an isolated process (or small process tree) with its own +view of the filesystem and network — when people say "a container exited," they mean its main +process exited, exactly the same event you'll cause on purpose in this module's Lab. Kubernetes' +entire job, at its core, is deciding which machine a process (inside a container) runs on and +restarting it if it dies unexpectedly — none of that will feel intuitive without this module's +model of what a process actually is. + +## Instructor Notes + +**Lesson goal:** Build a real process mental model (PID, foreground/background, signals, +parent/child) that ROOT 04 (containers) and ROOT 06 (Kubernetes workloads) both directly build +on without re-explaining. + +**Approximate timing:** 15 minutes read; 10 minutes live. + +**Common misconception to watch for:** students often think `kill` always means "forcefully +destroy" — clarify that plain `kill` sends a polite, ignorable request (SIGTERM), and `-9` is +the forceful escalation, not the default. + +**Discussion question:** "What do you think happens to a container if its main process exits on +its own, versus if something outside kills it?" (Don't need a complete answer yet — just plant +the question for later.) diff --git a/content/root/root-01-computing-linux-foundations/m05-processes/02-demonstration-watching-a-process-die.md b/content/root/root-01-computing-linux-foundations/m05-processes/02-demonstration-watching-a-process-die.md new file mode 100644 index 0000000..25b9a2e --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m05-processes/02-demonstration-watching-a-process-die.md @@ -0,0 +1,53 @@ +# Demonstration: Watching a Process Actually Terminate + +## OBSERVE + +Start a long-running background process and note its PID: + +``` +$ sleep 300 & +[1] 1421 +``` + +`1421` is the PID (yours will differ every time). + +## HYPOTHESIS + +Predict: will `kill -0 1421` print anything if the process is still running? + +## INSPECT + +``` +$ kill -0 1421 && echo "still running" +still running +``` + +`kill -0` sends no real signal — silence (or, here, our own `echo`) means the process exists. + +## CHANGE + +Now actually terminate it: + +``` +$ kill 1421 +``` + +## VERIFY + +``` +$ kill -0 1421 2>/dev/null && echo "still running" || echo "gone" +gone +``` + +The exact same check now reports the opposite result — real, observable proof the process is +gone, not an assumption. + +## Instructor Notes + +**Demo goal:** Make "checking before and after" a visible habit, not just narrated — students +should see the SAME command return a different real answer once state actually changed. + +**Approximate timing:** 8 minutes live. + +**Common mistake to watch for:** reaching for `kill -9` by default "to be safe" — reinforce that +plain `kill` (SIGTERM) is the correct first attempt almost always. diff --git a/content/root/root-01-computing-linux-foundations/m05-processes/03-knowledge-check.md b/content/root/root-01-computing-linux-foundations/m05-processes/03-knowledge-check.md new file mode 100644 index 0000000..329284c --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m05-processes/03-knowledge-check.md @@ -0,0 +1,38 @@ +# Knowledge Check: Processes + +--- + +**1. What does a PID identify?** + +*Answer:* One specific running instance of a program — the kernel's unique identifier for that +process, distinct from every other running process, even other copies of the same program. + +--- + +**2. What's the actual difference between `kill ` and `kill -9 `?** + +*Answer:* Plain `kill` sends SIGTERM, a polite request the process can choose to handle (clean +up, then exit). `kill -9` sends SIGKILL, which the kernel enforces immediately with no chance +for the process to react — an escalation for when SIGTERM is ignored, not the default choice. + +--- + +**3. You want to confirm a process is still running WITHOUT affecting it in any way. What do +you use?** + +*Answer:* `kill -0 ` — sends no real signal, only checks whether the PID still exists. + +--- + +**4. Why might understanding processes matter for understanding containers later?** + +*Answer:* A container is, underneath, mostly an isolated process (or small process tree) — a +container "exiting" is really its main process exiting, the exact same event this module's Lab +causes on purpose. + +## Instructor Notes + +**Facilitation:** Question 2 is worth confirming explicitly — "kill -9 by default" is a common, +worth-correcting habit. + +**Approximate timing:** 5 minutes. diff --git a/content/root/root-01-computing-linux-foundations/m05-processes/04-guided-exercise-signals.md b/content/root/root-01-computing-linux-foundations/m05-processes/04-guided-exercise-signals.md new file mode 100644 index 0000000..b4eeb0d --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m05-processes/04-guided-exercise-signals.md @@ -0,0 +1,28 @@ +# Guided Exercise: Choosing the Right Signal + +This is a paper exercise — commit to an answer before checking it in the Lab. + +## Your task + +For each situation, decide: plain `kill` (SIGTERM) first, or is `kill -9` (SIGKILL) actually +justified? + +1. A normal web server process you want to shut down for a routine restart. +2. A process that received SIGTERM two minutes ago and is still running, showing no signs of + responding. +3. A script you just started by mistake, that hasn't done anything harmful yet. + +## A worked shape to check yourself against + +1. Plain `kill` — give it the chance to shut down cleanly (close connections, flush data, etc). +2. `kill -9` is now justified — you already gave it the polite chance, and it didn't respond. +3. Plain `kill` first, still — "just started" doesn't change the default; SIGKILL is a last + resort, not a shortcut for convenience. + +## Instructor Notes + +**Facilitation:** Item 3 sometimes trips students who reach for `-9` out of impatience — worth +reinforcing that SIGTERM-first is the discipline REGARDLESS of urgency, since a process that +ignores SIGTERM is the actual signal that escalation is warranted. + +**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced. diff --git a/content/root/root-01-computing-linux-foundations/m05-processes/05-reflection.md b/content/root/root-01-computing-linux-foundations/m05-processes/05-reflection.md new file mode 100644 index 0000000..038dc19 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m05-processes/05-reflection.md @@ -0,0 +1,27 @@ +# Reflection: You Just Stopped a Real Process, Not a Simulation + +## Reflection questions + +1. Before checking `kill -0` after your `kill`, how confident were you the process was + actually gone? What would you have done if it hadn't stopped? +2. Why do you think SIGTERM-before-SIGKILL matters more for a real production service than for + a throwaway script in a Lab? + +## Real Ops takeaway + +**"I ran the kill command" is not the same as "I confirmed the process is gone."** This module's +Lab required you to verify state, not just take an action and assume it worked — that +verification step is exactly what separates a confident operator from someone hoping for the +best. You'll repeat this exact pattern (act, then verify) constantly for the rest of ROOT_, +starting as soon as ROOT 04's containers and continuing all the way through Kubernetes +troubleshooting. + +This module is complete. Continue to the next module. + +## Instructor Notes + +**Discussion questions for a live classroom:** question 2 is a good bridge to ROOT 06's later +discussion of graceful shutdown/`terminationGracePeriodSeconds` — plant the idea now without +naming Kubernetes specifics yet. + +**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing. diff --git a/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/01-lesson-users-and-permissions.md b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/01-lesson-users-and-permissions.md new file mode 100644 index 0000000..a124b53 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/01-lesson-users-and-permissions.md @@ -0,0 +1,59 @@ +# Users and Permissions Foundations + +## Users, groups, and ownership + +Every file on Linux has an **owner** (a user) and a **group**. `ls -la` shows both: the third +column is the owning user, the fourth is the owning group. Multiple users can belong to the same +group, which is how permissions get shared across a team without giving every individual user +direct ownership. + +## Read, write, execute — for three different audiences + +Every file has permissions for THREE separate audiences: the owner, the group, and everyone +else ("other"). Each audience gets some combination of: + +- **r**ead — can view the file's contents (or list a directory's contents) +- **w**rite — can modify the file (or create/delete files inside a directory) +- e**x**ecute — can run the file as a program (or enter/traverse into a directory) + +`ls -la` shows this as a 10-character string like `-rw-r--r--`: the first character is the file +type, then three groups of `rwx` for owner/group/other. + +## Reading and setting permissions as octal numbers + +Each `rwx` triplet can be written as one digit: read=4, write=2, execute=1, summed together. +`rw-` = 4+2 = `6`. `r--` = `4`. So `644` means: owner can read+write (6), group can read-only +(4), everyone else can read-only (4) — a very common, sensible default for a regular file. +`chmod 644 ` sets exactly that. + +## `sudo`: temporary elevated privilege + +Rather than logging in AS the root user (with permanent full access to everything), `sudo +` runs just that one command with elevated privileges, after checking you're allowed +to. This is deliberate: the less time you spend with full privileges, the smaller the window for +a mistake (or a compromised session) to do serious damage — the exact same reasoning behind +"least privilege," which this module introduces by name for the first time. + +## Least privilege: the principle, not just the command + +**Least privilege** means: grant exactly the access something needs to do its job, and nothing +more. A user who only needs to read a file shouldn't also be able to write it. A process that +only needs to read one directory shouldn't have write access to the whole filesystem. This +principle isn't specific to Linux permissions — you'll meet it again, in a much more elaborate +form, in ROOT 09's Kubernetes RBAC and SecurityContext content. This module is where it starts. + +## Instructor Notes + +**Lesson goal:** Build real fluency with rwx/octal permissions AND plant the least-privilege +PRINCIPLE explicitly — not just command syntax, since ROOT 09 depends on students already +having this vocabulary. + +**Approximate timing:** 15 minutes read; 10 minutes live. + +**Common misconception to watch for:** students often memorize "644 = read/write" without being +able to derive it from 4+2+1 — walk through the arithmetic explicitly rather than treating the +numbers as magic. + +**Discussion question:** "Why not just make everything readable and writable by everyone, to +avoid permission headaches?" (Good setup for the least-privilege principle — let students +generate the security argument themselves before you confirm it.) diff --git a/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/02-demonstration-permission-denied.md b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/02-demonstration-permission-denied.md new file mode 100644 index 0000000..28e56fa --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/02-demonstration-permission-denied.md @@ -0,0 +1,55 @@ +# Demonstration: A Real Permission Denial, and the Real Fix + +## OBSERVE + +A file is owned by root with permissions `600` (owner read/write only): + +``` +$ stat -c '%a %U' data.txt +600 root +``` + +## HYPOTHESIS + +Predict: can a different, non-root user read this file? + +## INSPECT + +``` +$ su - labuser -c "cat data.txt" +cat: data.txt: Permission denied +``` + +Confirmed — `600` grants nothing to group or other, so `labuser` (neither the owner nor root) +is correctly denied. + +## CHANGE + +Grant read access to everyone, while keeping write access limited to the owner: + +``` +$ chmod 644 data.txt +$ stat -c '%a' data.txt +644 +``` + +## VERIFY + +``` +$ su - labuser -c "cat data.txt" +sensitive +``` + +The exact same command that failed before now succeeds — the permission bits, not the file's +actual content, were the only thing that changed. + +## Instructor Notes + +**Demo goal:** Show a permission denial as a real, reproducible fact (not just a described +error message) and the exact minimal fix, not an overcorrection like `chmod 777`. + +**Approximate timing:** 8 minutes live. + +**Common mistake to watch for:** students reaching for `chmod 777` "to make the error go away" +— explicitly name why that's wrong (it also grants WRITE to everyone, not just the read access +actually needed) and connect it back to least privilege. diff --git a/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/03-knowledge-check.md b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/03-knowledge-check.md new file mode 100644 index 0000000..03a9907 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/03-knowledge-check.md @@ -0,0 +1,38 @@ +# Knowledge Check: Users and Permissions Foundations + +--- + +**1. A colleague says "permission denied" and fixes it with `chmod 777`. What's wrong with +that fix?** + +*Answer:* `777` grants read, write, AND execute to the owner, group, AND everyone else — almost +always far more access than the actual problem required. It "fixes" the symptom while violating +least privilege, usually granting write access nobody asked for. + +--- + +**2. What does the permission `644` actually mean, broken down?** + +*Answer:* Owner: read+write (4+2=6). Group: read-only (4). Other: read-only (4). Nobody but the +owner can modify the file; everyone can read it. + +--- + +**3. Why does `sudo ` exist instead of just logging in as root permanently?** + +*Answer:* It grants elevated privilege only for the one command that needs it, minimizing the +time spent with full access — reducing the chance a mistake (or a compromised session) causes +serious, wide damage. + +--- + +**4. State the least-privilege principle in your own words.** + +*Answer:* Grant exactly the access something needs to do its job, and nothing more. + +## Instructor Notes + +**Facilitation:** Question 1 is worth discussing as a group — most students have seen `chmod +777` somewhere online as "the fix," and unlearning that habit early matters. + +**Approximate timing:** 5 minutes. diff --git a/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/04-guided-exercise-least-privilege.md b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/04-guided-exercise-least-privilege.md new file mode 100644 index 0000000..c4002fd --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/04-guided-exercise-least-privilege.md @@ -0,0 +1,32 @@ +# Guided Exercise: Pick the Minimal Permission, Not the Easy One + +This is a paper exercise — commit to an answer before checking it in the Lab. + +## Your task + +For each situation, write the exact `chmod` octal value that grants the MINIMUM permission +actually needed: + +1. A private SSH key file — only the owner should ever read or write it, nobody else, no + execute for anyone. +2. A shared script every user on the system should be able to run, but only the owner should be + able to edit. +3. A log file every user should be able to read (for troubleshooting), but only a logging + service (the owner) should write to it. + +## A worked shape to check yourself against + +1. `600` — owner read+write (6), nothing for group or other (0, 0). This is the real, standard + permission for private SSH keys — SSH itself refuses to use a key file that's more open than + this. +2. `755` — owner read+write+execute (7), group and other read+execute (5, 5) so they can run it + but not modify it. +3. `644` — owner read+write (6), group and other read-only (4, 4). + +## Instructor Notes + +**Facilitation:** Item 1 is a good moment to mention that this isn't a hypothetical rule — SSH +genuinely refuses to use an overly-permissive private key file, a real-world consequence of +exactly this principle. + +**Approximate timing:** 8-10 minutes live discussion; 5 minutes self-paced. diff --git a/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/05-reflection.md b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/05-reflection.md new file mode 100644 index 0000000..d7614b8 --- /dev/null +++ b/content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/05-reflection.md @@ -0,0 +1,33 @@ +# Reflection: Least Privilege Is a Habit, Not a One-Time Fix + +## Reflection questions + +1. Before this module, what would you have done the first time you hit a "permission denied" + error? How does that compare to what you'd do now? +2. Name one place outside of file permissions where you'd expect "grant only what's needed" to + matter (a user account, an API key, a service's network access — anything). + +## Real Ops takeaway + +**Least privilege is the single idea from this entire module that reappears the most across +the rest of ROOT_.** File permissions are just the first, most concrete place you'll apply it — +ROOT 09 applies the exact same principle to Kubernetes RBAC (what can a user or workload +actually DO) and SecurityContext (what can a container actually access). Getting comfortable +asking "what's the minimum this actually needs" now, on a file you can see and touch, makes that +same question much easier to ask later about something more abstract, like a ServiceAccount's +permissions. + +This module is complete. This is the end of ROOT 01 — continue to ROOT 02: Linux +Administration & Networking. + +## Instructor Notes + +**Discussion questions for a live classroom:** question 2 works well as a round-robin — the +variety of answers (API keys, database credentials, network firewall rules) is itself useful +evidence of how far this one principle travels. + +**Approximate timing:** 5-8 minutes live discussion; 5 minutes self-paced writing. + +**Milestone note:** this is the last module of ROOT 01 — consider a short recap of the whole +course's arc (hardware → shell → filesystem → files/text → processes → permissions) before +moving on, so students see it as one coherent foundation rather than six separate topics. diff --git a/platform/api/migrations/025_phase6d_root_foundations_root01.sql b/platform/api/migrations/025_phase6d_root_foundations_root01.sql new file mode 100644 index 0000000..8042528 --- /dev/null +++ b/platform/api/migrations/025_phase6d_root_foundations_root01.sql @@ -0,0 +1,148 @@ +-- Phase 6D — ROOT 01: Computing & Linux Foundations. Adds 6 modules/activities under the +-- existing (PLANNED, zero-content) root-01-computing-linux-foundations course row seeded by +-- Phase 6A's 022_course_content.sql. Every lab activity references a NEW scenario file +-- (scenarios/data/linux-*.json) using the existing, generic scenario/validation engine — see +-- docs/ROOT_FOUNDATIONS_LAB_STRATEGY.md §1 for why no new activity type or mechanism was +-- needed. Every lesson/demonstration/knowledge_check/guided_exercise/reflection activity +-- references a real content file under content/root/root-01-computing-linux-foundations/. + +UPDATE courses SET + status = 'ready', + objectives = '{"Explain what the OS/kernel manages versus an application","Use a Linux shell confidently, including reading exit codes","Navigate the filesystem using absolute and relative paths","Manipulate files and text with pipes and redirection","Inspect and safely terminate a real process","Apply the least-privilege principle to file permissions"}', + updated_at = now() +WHERE course_id = 'root-01-computing-linux-foundations'; + +INSERT INTO course_modules (module_id, course_id, title, description, sequence, objectives, prerequisites, estimated_duration_minutes, status) VALUES +('root-01-m01-how-computers-run-software', 'root-01-computing-linux-foundations', 'How Computers Run Software', + 'Hardware vs. OS vs. application, and the CPU/RAM/storage/process vocabulary the rest of ROOT_ assumes. Target learner: no assumed prior Linux/CLI experience.', + 1, '{"Explain the hardware/kernel/application layering","Describe what CPU, RAM, and storage each actually do","Inspect a real machine''s CPU, memory, and disk"}', '{}', 40, 'ready'), +('root-01-m02-linux-and-the-shell', 'root-01-computing-linux-foundations', 'Linux and the Shell', + 'What Linux/a distribution/a shell actually are, command structure, and exit codes as the universal success/failure signal.', + 2, '{"Distinguish shell, terminal, and distribution","Read and interpret a command''s exit code","Use tab completion, history, and man pages"}', '{root-01-m01-how-computers-run-software}', 45, 'ready'), +('root-01-m03-navigating-the-filesystem', 'root-01-computing-linux-foundations', 'Navigating the Filesystem', + 'Absolute vs. relative paths, and what the standard top-level directories are for.', + 3, '{"Navigate using absolute and relative paths correctly","Explain the purpose of /etc, /var, /home, /tmp, /usr, /proc","Build a real nested directory structure"}', '{root-01-m02-linux-and-the-shell}', 45, 'ready'), +('root-01-m04-files-and-text', 'root-01-computing-linux-foundations', 'Files and Text', + 'File manipulation, reading text, and composing commands with pipes/redirection.', + 4, '{"Manipulate files and directories with the core file commands","Filter text with grep","Compose commands using pipes and redirection"}', '{root-01-m03-navigating-the-filesystem}', 45, 'ready'), +('root-01-m05-processes', 'root-01-computing-linux-foundations', 'Processes', + 'The process concept, foreground/background, signals, and why this matters for containers later.', + 5, '{"Explain what a process and a PID are","Inspect running processes with ps","Terminate a process correctly, verifying the result"}', '{root-01-m04-files-and-text}', 40, 'ready'), +('root-01-m06-users-and-permissions-foundations', 'root-01-computing-linux-foundations', 'Users & Permissions Foundations', + 'Ownership, rwx permissions, sudo, and the least-privilege principle this phase introduces for the first time in ROOT_.', + 6, '{"Read and set rwx permissions using octal notation","Explain why sudo exists instead of permanent root access","State and apply the least-privilege principle"}', '{root-01-m05-processes}', 45, 'ready') +ON CONFLICT (module_id) DO NOTHING; + +INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES +-- M01 +('root-01-m01-a01-lesson', 'root-01-m01-how-computers-run-software', 1, 'lesson', 'How Computers Run Software', + 'content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/01-lesson-how-computers-run-software.md', NULL, NULL, 'manual_marker', 15, 'ready'), +('root-01-m01-a02-guided-exercise', 'root-01-m01-how-computers-run-software', 2, 'guided_exercise', 'Guided Exercise: Predict Before You Look', + 'content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/02-guided-exercise-inspect-hardware-on-paper.md', NULL, NULL, 'manual_marker', 5, 'ready'), +('root-01-m01-a03-lab-inspect-hardware', 'root-01-m01-how-computers-run-software', 3, 'lab', 'Lab: Inspect What This Machine Actually Has', + NULL, 'linux-inspect-hardware', NULL, 'auto_scenario', 10, 'ready'), +('root-01-m01-a04-reflection', 'root-01-m01-how-computers-run-software', 4, 'reflection', 'Reflection: You Just Looked Inside the Box', + 'content/root/root-01-computing-linux-foundations/m01-how-computers-run-software/03-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'), +-- M02 +('root-01-m02-a01-lesson', 'root-01-m02-linux-and-the-shell', 1, 'lesson', 'Linux and the Shell', + 'content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/01-lesson-linux-and-the-shell.md', NULL, NULL, 'manual_marker', 15, 'ready'), +('root-01-m02-a02-demonstration', 'root-01-m02-linux-and-the-shell', 2, 'demonstration', 'Demonstration: Watching Exit Codes in Real Time', + 'content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/02-demonstration-exit-codes-in-action.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m02-a03-knowledge-check', 'root-01-m02-linux-and-the-shell', 3, 'knowledge_check', 'Knowledge Check: Linux and the Shell', + 'content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'), +('root-01-m02-a04-guided-exercise', 'root-01-m02-linux-and-the-shell', 4, 'guided_exercise', 'Guided Exercise: Predict the Exit Code', + 'content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/04-guided-exercise-predicting-exit-codes.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m02-a05-lab-shell-basics', 'root-01-m02-linux-and-the-shell', 5, 'lab', 'Lab: Reading Exit Codes Like an Engineer', + NULL, 'linux-shell-basics', NULL, 'auto_scenario', 10, 'ready'), +('root-01-m02-a06-reflection', 'root-01-m02-linux-and-the-shell', 6, 'reflection', 'Reflection: Exit Codes Are Everywhere After This', + 'content/root/root-01-computing-linux-foundations/m02-linux-and-the-shell/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'), +-- M03 +('root-01-m03-a01-lesson', 'root-01-m03-navigating-the-filesystem', 1, 'lesson', 'Navigating the Filesystem', + 'content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/01-lesson-filesystem-navigation.md', NULL, NULL, 'manual_marker', 15, 'ready'), +('root-01-m03-a02-demonstration', 'root-01-m03-navigating-the-filesystem', 2, 'demonstration', 'Demonstration: The Same Word, Two Different Destinations', + 'content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/02-demonstration-absolute-vs-relative.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m03-a03-knowledge-check', 'root-01-m03-navigating-the-filesystem', 3, 'knowledge_check', 'Knowledge Check: Navigating the Filesystem', + 'content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'), +('root-01-m03-a04-guided-exercise', 'root-01-m03-navigating-the-filesystem', 4, 'guided_exercise', 'Guided Exercise: Plan a Directory Structure on Paper First', + 'content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/04-guided-exercise-planning-a-structure.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m03-a05-lab-filesystem-navigation', 'root-01-m03-navigating-the-filesystem', 5, 'lab', 'Lab: Build a Real Project Directory Structure', + NULL, 'linux-filesystem-navigation', NULL, 'auto_scenario', 10, 'ready'), +('root-01-m03-a06-reflection', 'root-01-m03-navigating-the-filesystem', 6, 'reflection', 'Reflection: Structure Isn''t Bureaucracy, It''s Communication', + 'content/root/root-01-computing-linux-foundations/m03-navigating-the-filesystem/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'), +-- M04 +('root-01-m04-a01-lesson', 'root-01-m04-files-and-text', 1, 'lesson', 'Files and Text', + 'content/root/root-01-computing-linux-foundations/m04-files-and-text/01-lesson-files-and-text.md', NULL, NULL, 'manual_marker', 15, 'ready'), +('root-01-m04-a02-demonstration', 'root-01-m04-files-and-text', 2, 'demonstration', 'Demonstration: Filtering a Log Down to What Matters', + 'content/root/root-01-computing-linux-foundations/m04-files-and-text/02-demonstration-pipes-and-redirection.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m04-a03-knowledge-check', 'root-01-m04-files-and-text', 3, 'knowledge_check', 'Knowledge Check: Files and Text', + 'content/root/root-01-computing-linux-foundations/m04-files-and-text/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'), +('root-01-m04-a04-guided-exercise', 'root-01-m04-files-and-text', 4, 'guided_exercise', 'Guided Exercise: Which Tool Actually Answers the Question?', + 'content/root/root-01-computing-linux-foundations/m04-files-and-text/04-guided-exercise-choosing-the-right-tool.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m04-a05-lab-files-and-text', 'root-01-m04-files-and-text', 5, 'lab', 'Lab: Extract the Signal From a Log File', + NULL, 'linux-files-and-text', NULL, 'auto_scenario', 10, 'ready'), +('root-01-m04-a06-reflection', 'root-01-m04-files-and-text', 6, 'reflection', 'Reflection: Filtering Is a Reasoning Skill, Not a Syntax Trick', + 'content/root/root-01-computing-linux-foundations/m04-files-and-text/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'), +-- M05 +('root-01-m05-a01-lesson', 'root-01-m05-processes', 1, 'lesson', 'Processes', + 'content/root/root-01-computing-linux-foundations/m05-processes/01-lesson-processes.md', NULL, NULL, 'manual_marker', 15, 'ready'), +('root-01-m05-a02-demonstration', 'root-01-m05-processes', 2, 'demonstration', 'Demonstration: Watching a Process Actually Terminate', + 'content/root/root-01-computing-linux-foundations/m05-processes/02-demonstration-watching-a-process-die.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m05-a03-knowledge-check', 'root-01-m05-processes', 3, 'knowledge_check', 'Knowledge Check: Processes', + 'content/root/root-01-computing-linux-foundations/m05-processes/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'), +('root-01-m05-a04-guided-exercise', 'root-01-m05-processes', 4, 'guided_exercise', 'Guided Exercise: Choosing the Right Signal', + 'content/root/root-01-computing-linux-foundations/m05-processes/04-guided-exercise-signals.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m05-a05-lab-process-management', 'root-01-m05-processes', 5, 'lab', 'Lab: Find and Stop a Runaway Process', + NULL, 'linux-process-management', NULL, 'auto_scenario', 10, 'ready'), +('root-01-m05-a06-reflection', 'root-01-m05-processes', 6, 'reflection', 'Reflection: You Just Stopped a Real Process, Not a Simulation', + 'content/root/root-01-computing-linux-foundations/m05-processes/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready'), +-- M06 +('root-01-m06-a01-lesson', 'root-01-m06-users-and-permissions-foundations', 1, 'lesson', 'Users and Permissions Foundations', + 'content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/01-lesson-users-and-permissions.md', NULL, NULL, 'manual_marker', 15, 'ready'), +('root-01-m06-a02-demonstration', 'root-01-m06-users-and-permissions-foundations', 2, 'demonstration', 'Demonstration: A Real Permission Denial, and the Real Fix', + 'content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/02-demonstration-permission-denied.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m06-a03-knowledge-check', 'root-01-m06-users-and-permissions-foundations', 3, 'knowledge_check', 'Knowledge Check: Users and Permissions Foundations', + 'content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/03-knowledge-check.md', NULL, NULL, 'manual_marker', 5, 'ready'), +('root-01-m06-a04-guided-exercise', 'root-01-m06-users-and-permissions-foundations', 4, 'guided_exercise', 'Guided Exercise: Pick the Minimal Permission, Not the Easy One', + 'content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/04-guided-exercise-least-privilege.md', NULL, NULL, 'manual_marker', 8, 'ready'), +('root-01-m06-a05-lab-permissions', 'root-01-m06-users-and-permissions-foundations', 5, 'lab', 'Lab: Fix a Real Permission Denial', + NULL, 'linux-permissions-foundations', NULL, 'auto_scenario', 10, 'ready'), +('root-01-m06-a06-reflection', 'root-01-m06-users-and-permissions-foundations', 6, 'reflection', 'Reflection: Least Privilege Is a Habit, Not a One-Time Fix', + 'content/root/root-01-computing-linux-foundations/m06-users-and-permissions-foundations/05-reflection.md', NULL, NULL, 'manual_marker', 8, 'ready') +ON CONFLICT (activity_id) DO NOTHING; + +-- ═══════════════════════════════════════════════════════════════════════════════════════════ +-- ROOT 01 course assessment — mixes real state-validation tasks (the same scenarios already +-- used as labs above, plus two more) with knowledge-recall MCQs, via the existing Phase 3B +-- assessment engine. No Kubernetes scenario is force-fit into this non-Kubernetes assessment. +-- ═══════════════════════════════════════════════════════════════════════════════════════════ +INSERT INTO assessment_definitions (assessment_definition_id, type, title, description, duration_minutes, hint_policy, pool_spec, completion_rule) +VALUES ( + 'rootnode-linux-foundations-assessment', 'exam', 'ROOT 01 Linux Foundations Assessment', + 'A timed check across shell fluency, filesystem navigation, process management, and least-privilege permissions — combining real state-validation tasks with conceptual reasoning questions.', + 30, 'disabled', + '{"required": ["linux-shell-basics", "linux-permissions-foundations"], + "random": [ + {"count":2,"from":["linux-inspect-hardware","linux-filesystem-navigation","linux-files-and-text","linux-process-management"]}, + {"count":2,"from":["linux-exit-codes-mcq","linux-permissions-mcq"]} + ]}', + '{"type":"all_scenarios_passed"}' +) ON CONFLICT (assessment_definition_id) DO NOTHING; + +INSERT INTO module_activities (activity_id, module_id, sequence, activity_type, title, content_path, scenario_id, assessment_definition_id, completion_behavior, estimated_duration_minutes, status) VALUES +('root-01-m06-a07-assessment', 'root-01-m06-users-and-permissions-foundations', 7, 'assessment', 'ROOT 01 Linux Foundations Assessment', NULL, NULL, 'rootnode-linux-foundations-assessment', 'auto_assessment', 30, 'ready') +ON CONFLICT (activity_id) DO NOTHING; + +-- ═══════════════════════════════════════════════════════════════════════════════════════════ +-- Step 19 — real ROOT 01→02→03→04→05 course prerequisite chain, server-side (courses.prerequisites), +-- not UI-hidden alone. root-02/03/04 remain PLANNED with zero activities this phase, so per +-- docs/COURSE_CONTENT_MODEL.md §5's "zero activities is vacuously satisfied" rule, this chain +-- has no practical locking effect YET on 02/03/04 or on 05 (which already only real-gates once +-- root-04 is eventually authored) — it correctly encodes the INTENDED sequence now, so a future +-- phase authoring ROOT 02-04 doesn't need to reopen this decision, without breaking any current +-- Kubernetes-track student's path today (root-05's real prerequisite content, root-04, is still +-- honestly empty). +-- ═══════════════════════════════════════════════════════════════════════════════════════════ +UPDATE courses SET prerequisites = '{root-01-computing-linux-foundations}', updated_at = now() WHERE course_id = 'root-02-linux-administration-networking'; +UPDATE courses SET prerequisites = '{root-02-linux-administration-networking}', updated_at = now() WHERE course_id = 'root-03-git-collaborative-development'; +UPDATE courses SET prerequisites = '{root-03-git-collaborative-development}', updated_at = now() WHERE course_id = 'root-04-containers-and-docker'; +UPDATE courses SET prerequisites = '{root-04-containers-and-docker}', updated_at = now() WHERE course_id = 'root-05-kubernetes-foundations'; diff --git a/scenarios/data/linux-exit-codes-mcq.json b/scenarios/data/linux-exit-codes-mcq.json new file mode 100644 index 0000000..a957716 --- /dev/null +++ b/scenarios/data/linux-exit-codes-mcq.json @@ -0,0 +1,22 @@ +{ + "id": "linux-exit-codes-mcq", + "title": "Reading Exit Code Conventions", + "category": "Linux Fundamentals", + "isolation_type": "shared_namespace", + "difficulty": "Easy", + "type": "mcq", + "weight": 3, + "description": "## Reading Exit Code Conventions\n\nYou run `grep pattern file.txt` and it exits with code `1`, printing no error message at all. What actually happened?", + "options": [ + { "id": "a", "text": "The file doesn't exist" }, + { "id": "b", "text": "grep found no lines matching the pattern — this is grep's normal way of reporting \"no match,\" not an error" }, + { "id": "c", "text": "You don't have permission to read the file" }, + { "id": "d", "text": "The command is broken and needs to be reinstalled" } + ], + "correct_option": "b", + "explanation": "grep's exit code means \"did I find at least one match,\" not \"did something go wrong.\" Exit 1 with no error message is grep's normal, expected way of reporting zero matches — a very common early surprise, since silence plus a non-zero code doesn't always mean a real failure occurred.", + "hints": [], + "setup_commands": [], + "default_namespace": "default", + "teardown_commands": [] +} diff --git a/scenarios/data/linux-files-and-text.json b/scenarios/data/linux-files-and-text.json new file mode 100644 index 0000000..35e56e3 --- /dev/null +++ b/scenarios/data/linux-files-and-text.json @@ -0,0 +1,31 @@ +{ + "id": "linux-files-and-text", + "title": "Extract the Signal From a Log File", + "category": "Linux Fundamentals", + "isolation_type": "shared_namespace", + "difficulty": "Easy", + "type": "task", + "weight": 4, + "description": "## Extract the Signal From a Log File\n\nA real application log (`/srv/text-lab/app.log`) has been generated for you, mixing `INFO` and `ERROR` lines. Reading raw logs line-by-line doesn't scale — filtering does.\n\n**Your task:**\n\n1. Use `grep` to extract only the `ERROR` lines from `/srv/text-lab/app.log`\n2. Redirect the result into a new file: `/srv/text-lab/errors.txt`\n3. Count how many ERROR lines there were and save the count to `/srv/text-lab/error-count.txt`", + "hints": [ + { + "title": "Filtering and redirecting", + "body": "`grep PATTERN file > newfile` writes only matching lines to a new file. Pipe to `wc -l` to count them.", + "command": "grep ERROR /srv/text-lab/app.log > /srv/text-lab/errors.txt\ngrep -c ERROR /srv/text-lab/app.log > /srv/text-lab/error-count.txt" + } + ], + "setup_commands": [ + { "command": "mkdir -p /srv/text-lab && printf 'INFO: boot ok\\nERROR: disk full\\nINFO: retry\\nERROR: timeout\\nINFO: done\\n' > /srv/text-lab/app.log" } + ], + "validation": { + "commands": [ + { "description": "errors.txt contains only ERROR lines", "command": "grep -vc ERROR /srv/text-lab/errors.txt || true", "expected_output": "0", "match": "exact" }, + { "description": "errors.txt has exactly the 2 real ERROR lines", "command": "wc -l < /srv/text-lab/errors.txt | tr -d ' '", "expected_output": "2", "match": "exact" }, + { "description": "error-count.txt records the count", "command": "cat /srv/text-lab/error-count.txt", "expected_output": "2", "match": "exact" } + ] + }, + "default_namespace": "default", + "teardown_commands": [ + { "command": "rm -rf /srv/text-lab" } + ] +} diff --git a/scenarios/data/linux-filesystem-navigation.json b/scenarios/data/linux-filesystem-navigation.json new file mode 100644 index 0000000..2d12ae3 --- /dev/null +++ b/scenarios/data/linux-filesystem-navigation.json @@ -0,0 +1,32 @@ +{ + "id": "linux-filesystem-navigation", + "title": "Build a Real Project Directory Structure", + "category": "Linux Fundamentals", + "isolation_type": "shared_namespace", + "difficulty": "Easy", + "type": "task", + "weight": 3, + "description": "## Build a Real Project Directory Structure\n\nEvery real codebase has a directory structure that means something. Practice building and navigating one.\n\n**Your task:**\n\nUnder `/srv/fs-lab/`, create:\n\n1. A directory tree: `project/src`, `project/docs`, `project/tests`\n2. A hidden file at `project/.config` containing exactly the text `ready`\n3. Navigate into `project/src` using a RELATIVE path from `/srv/fs-lab` (not an absolute path) to confirm you understand `cd project/src` vs `cd /srv/fs-lab/project/src`", + "hints": [ + { + "title": "Creating the tree in one command", + "body": "`mkdir -p` creates every intermediate directory in one call, and brace expansion lets you create three siblings at once.", + "command": "mkdir -p /srv/fs-lab/project/{src,docs,tests}\necho -n 'ready' > /srv/fs-lab/project/.config" + } + ], + "setup_commands": [ + { "command": "mkdir -p /srv/fs-lab" } + ], + "validation": { + "commands": [ + { "description": "project/src exists", "command": "[ -d /srv/fs-lab/project/src ] && echo yes", "expected_output": "yes", "match": "exact" }, + { "description": "project/docs exists", "command": "[ -d /srv/fs-lab/project/docs ] && echo yes", "expected_output": "yes", "match": "exact" }, + { "description": "project/tests exists", "command": "[ -d /srv/fs-lab/project/tests ] && echo yes", "expected_output": "yes", "match": "exact" }, + { "description": "hidden .config file has the right content", "command": "cat /srv/fs-lab/project/.config", "expected_output": "ready", "match": "exact" } + ] + }, + "default_namespace": "default", + "teardown_commands": [ + { "command": "rm -rf /srv/fs-lab" } + ] +} diff --git a/scenarios/data/linux-inspect-hardware.json b/scenarios/data/linux-inspect-hardware.json new file mode 100644 index 0000000..ef2ef2b --- /dev/null +++ b/scenarios/data/linux-inspect-hardware.json @@ -0,0 +1,36 @@ +{ + "id": "linux-inspect-hardware", + "title": "Inspect What This Machine Actually Has", + "category": "Linux Fundamentals", + "isolation_type": "shared_namespace", + "difficulty": "Easy", + "type": "task", + "weight": 3, + "description": "## Inspect What This Machine Actually Has\n\nThe kernel manages CPU, memory, and storage on behalf of every process running here — before you go further, look at what's actually available.\n\n**Your task:**\n\n1. Find the number of CPUs available (`nproc`)\n2. Find the total memory in MB (`free -m`)\n3. Find the size of the root filesystem in GB (`df -BG /`)\n4. Create a file at `/srv/hardware-lab/report.txt` with exactly three lines in this format (replace `` with the real numbers you found):\n\n```\nCPUS=\nMEM_MB=\nDISK_GB=\n```", + "hints": [ + { + "title": "Getting each number", + "body": "`nproc` alone prints the CPU count. `free -m` prints a table — the second column of the `Mem:` row is total memory in MB. `df -BG /` prints a table — the second column of the second row is the root filesystem size in GB (the number, not including the trailing G).", + "command": "nproc; free -m; df -BG /" + }, + { + "title": "Writing the report", + "body": "Use a heredoc or several `echo` lines with `>>` to build the file.", + "command": "mkdir -p /srv/hardware-lab && cat < /srv/hardware-lab/report.txt\nCPUS=$(nproc)\nMEM_MB=$(free -m | awk '/Mem:/ {print $2}')\nDISK_GB=$(df -BG / | awk 'NR==2{gsub(\"G\",\"\",$2); print $2}')\nEOF" + } + ], + "setup_commands": [ + { "command": "mkdir -p /srv/hardware-lab" } + ], + "validation": { + "commands": [ + { "description": "report.txt exists and has a CPUS line", "command": "grep -E '^CPUS=[0-9]+$' /srv/hardware-lab/report.txt", "expected_output": "^CPUS=[0-9]+$", "match": "regex" }, + { "description": "report.txt has a MEM_MB line", "command": "grep -E '^MEM_MB=[0-9]+$' /srv/hardware-lab/report.txt", "expected_output": "^MEM_MB=[0-9]+$", "match": "regex" }, + { "description": "report.txt has a DISK_GB line", "command": "grep -E '^DISK_GB=[0-9]+$' /srv/hardware-lab/report.txt", "expected_output": "^DISK_GB=[0-9]+$", "match": "regex" } + ] + }, + "default_namespace": "default", + "teardown_commands": [ + { "command": "rm -rf /srv/hardware-lab" } + ] +} diff --git a/scenarios/data/linux-permissions-foundations.json b/scenarios/data/linux-permissions-foundations.json new file mode 100644 index 0000000..cc7e0ec --- /dev/null +++ b/scenarios/data/linux-permissions-foundations.json @@ -0,0 +1,37 @@ +{ + "id": "linux-permissions-foundations", + "title": "Fix a Real Permission Denial", + "category": "Linux Fundamentals", + "isolation_type": "shared_namespace", + "difficulty": "Easy", + "type": "task", + "weight": 4, + "description": "## Fix a Real Permission Denial\n\nA second user, `labuser`, already exists on this system. A file at `/srv/perm-lab/data.txt` currently has permissions `600` (owner read/write only) — `labuser` cannot read it. Confirm the denial is real, then fix it correctly.\n\n**Your task:**\n\n1. As `labuser`, try to read `/srv/perm-lab/data.txt` and see the permission denial for yourself: `su - labuser -c \"cat /srv/perm-lab/data.txt\"`\n2. Change the file's permissions so it's readable by everyone but still only writable by its owner (this is exactly what `644` means)\n3. Confirm `labuser` can now read it", + "hints": [ + { + "title": "Reading permissions as a number", + "body": "Each of the three permission groups (owner/group/other) is one octal digit: read=4, write=2, execute=1, summed. `644` = owner read+write (6), group read-only (4), other read-only (4).", + "command": "stat -c '%a %U' /srv/perm-lab/data.txt" + }, + { + "title": "Fixing it", + "body": "`chmod 644 ` sets exactly that permission pattern.", + "command": "chmod 644 /srv/perm-lab/data.txt" + } + ], + "setup_commands": [ + { "command": "id labuser >/dev/null 2>&1 || useradd -m labuser" }, + { "command": "mkdir -p /srv/perm-lab && chmod 755 /srv/perm-lab" }, + { "command": "echo sensitive > /srv/perm-lab/data.txt && chmod 600 /srv/perm-lab/data.txt && chown root:root /srv/perm-lab/data.txt" } + ], + "validation": { + "commands": [ + { "description": "data.txt is now exactly 644", "command": "stat -c '%a' /srv/perm-lab/data.txt", "expected_output": "644", "match": "exact" }, + { "description": "labuser can actually read it now", "command": "su - labuser -c 'cat /srv/perm-lab/data.txt' 2>&1", "expected_output": "sensitive", "match": "exact" } + ] + }, + "default_namespace": "default", + "teardown_commands": [ + { "command": "rm -rf /srv/perm-lab" } + ] +} diff --git a/scenarios/data/linux-permissions-mcq.json b/scenarios/data/linux-permissions-mcq.json new file mode 100644 index 0000000..f40fadd --- /dev/null +++ b/scenarios/data/linux-permissions-mcq.json @@ -0,0 +1,22 @@ +{ + "id": "linux-permissions-mcq", + "title": "Choosing the Minimal Permission", + "category": "Linux Fundamentals", + "isolation_type": "shared_namespace", + "difficulty": "Easy", + "type": "mcq", + "weight": 3, + "description": "## Choosing the Minimal Permission\n\nA private SSH key file should be readable and writable by its owner only — nobody else should be able to read, write, or execute it. Which `chmod` octal value is correct?", + "options": [ + { "id": "a", "text": "777" }, + { "id": "b", "text": "644" }, + { "id": "c", "text": "600" }, + { "id": "d", "text": "444" } + ], + "correct_option": "c", + "explanation": "600 grants the owner read+write (4+2=6) and nothing at all to group or other (0, 0) — the minimum needed, and the actual permission SSH itself enforces for private key files. 644 incorrectly leaves the file readable by everyone; 777 grants full access to everyone, the opposite of least privilege.", + "hints": [], + "setup_commands": [], + "default_namespace": "default", + "teardown_commands": [] +} diff --git a/scenarios/data/linux-process-management.json b/scenarios/data/linux-process-management.json new file mode 100644 index 0000000..6cb4ef6 --- /dev/null +++ b/scenarios/data/linux-process-management.json @@ -0,0 +1,34 @@ +{ + "id": "linux-process-management", + "title": "Find and Stop a Runaway Process", + "category": "Linux Fundamentals", + "isolation_type": "shared_namespace", + "difficulty": "Easy", + "type": "task", + "weight": 4, + "description": "## Find and Stop a Runaway Process\n\nA background process has been started for you and its PID recorded at `/srv/proc-lab/target.pid`. Every process in Kubernetes and Docker is, underneath, exactly this: a PID the kernel is tracking.\n\n**Your task:**\n\n1. Confirm the process is currently running (`kill -0 ` succeeds silently if a process exists)\n2. Send it a termination signal: `kill ` (using the PID recorded in the file, not a hardcoded number — it will be different every time)\n3. Confirm it is actually gone afterward", + "hints": [ + { + "title": "Reading the PID and checking it's alive", + "body": "`kill -0` sends no real signal — it only checks whether the process exists, which is why it's the standard way to test \"is this PID still running\" without side effects.", + "command": "cat /srv/proc-lab/target.pid\nkill -0 $(cat /srv/proc-lab/target.pid) && echo RUNNING" + }, + { + "title": "Terminating it", + "body": "A plain `kill ` sends SIGTERM, the polite \"please shut down\" signal — the correct first choice before ever reaching for `kill -9`.", + "command": "kill $(cat /srv/proc-lab/target.pid)" + } + ], + "setup_commands": [ + { "command": "mkdir -p /srv/proc-lab && (sleep 900 & echo $! > /srv/proc-lab/target.pid)" } + ], + "validation": { + "commands": [ + { "description": "the target process has actually been terminated", "command": "kill -0 $(cat /srv/proc-lab/target.pid) 2>/dev/null && echo RUNNING || echo GONE", "expected_output": "GONE", "match": "exact" } + ] + }, + "default_namespace": "default", + "teardown_commands": [ + { "command": "kill -9 $(cat /srv/proc-lab/target.pid) 2>/dev/null; rm -rf /srv/proc-lab" } + ] +} diff --git a/scenarios/data/linux-shell-basics.json b/scenarios/data/linux-shell-basics.json new file mode 100644 index 0000000..709838a --- /dev/null +++ b/scenarios/data/linux-shell-basics.json @@ -0,0 +1,30 @@ +{ + "id": "linux-shell-basics", + "title": "Reading Exit Codes Like an Engineer", + "category": "Linux Fundamentals", + "isolation_type": "shared_namespace", + "difficulty": "Easy", + "type": "task", + "weight": 3, + "description": "## Reading Exit Codes Like an Engineer\n\nEvery command you run returns an exit code — `0` means success, anything else means failure. Scripts, CI pipelines, and Kubernetes probes all rely on this exact convention.\n\n**Your task:**\n\n1. Run a command that succeeds (e.g. `true`, or `ls` on a directory that exists) and save its exit code to `/srv/shell-lab/success-exit-code.txt`\n2. Run a command that fails (e.g. `ls` on a path that does NOT exist) and save its exit code to `/srv/shell-lab/fail-exit-code.txt`\n3. Look up the manual page for `ls` (`man ls`) and find one option you didn't know about", + "hints": [ + { + "title": "Capturing an exit code", + "body": "The special variable `$?` holds the exit code of the LAST command that ran — capture it immediately, before running anything else.", + "command": "mkdir -p /srv/shell-lab\ntrue\necho $? > /srv/shell-lab/success-exit-code.txt\nls /this-path-does-not-exist 2>/dev/null\necho $? > /srv/shell-lab/fail-exit-code.txt" + } + ], + "setup_commands": [ + { "command": "mkdir -p /srv/shell-lab" } + ], + "validation": { + "commands": [ + { "description": "success-exit-code.txt records 0", "command": "cat /srv/shell-lab/success-exit-code.txt", "expected_output": "0", "match": "exact" }, + { "description": "fail-exit-code.txt records a non-zero code", "command": "cat /srv/shell-lab/fail-exit-code.txt", "expected_output": "^[1-9][0-9]*$", "match": "regex" } + ] + }, + "default_namespace": "default", + "teardown_commands": [ + { "command": "rm -rf /srv/shell-lab" } + ] +}