diff --git a/COMPREHENSION_QUESTIONS.md b/COMPREHENSION_QUESTIONS.md new file mode 100644 index 0000000..ebec9ba --- /dev/null +++ b/COMPREHENSION_QUESTIONS.md @@ -0,0 +1,415 @@ +# Module 01 — Linux & Command Line · Comprehension Questions + +Gating question bank for the LMS. Each question lists options, the correct +answer, and a one-line rationale for the instructor/feedback panel. Mixed +recall and applied ("predict the output") items. `[R]` = recall, `[A]` = applied. + +--- + +## Workflow & mindset (gate before Lab 00) + +**Q0.1 [R]** In this workspace, what file is the authoritative definition of "done" for an exercise? +- A. `README.md` +- B. `solution.sh` +- C. **`tests/*.bats`** +- D. `scripts/grade.mjs` + +**Answer: C.** The bats test spec defines exactly what your solution must do; the README explains, the solution is your work, the grader just runs the spec. + +**Q0.2 [R]** The module's "golden rule" is: +- A. Always use `sudo` so commands don't fail. +- B. **Never run a command — or paste one from an AI — that you cannot explain.** +- C. Prefer GUI tools over the command line when unsure. +- D. Copy the hint verbatim; it is always correct. + +**Answer: B.** Understanding is the deliverable; the green check is only the evidence. + +**Q0.3 [A]** You push a commit. The Autograde check goes green only when: +- A. At least one exercise passes. +- B. The score is 70% or higher. +- C. **Every exercise's tests pass AND every `solution.sh` parses cleanly (`bash -n`).** +- D. You manually approve the run. + +**Answer: C.** The grader requires all tests green plus a passing shell-syntax gate. + +**Q0.4 [R]** In the "Draft → Verify → Log" AI workflow, why must you never run AI output on a real system unread? +- A. It runs too slowly. +- B. **AI is a fast but fallible pair; its output must be verified with the right tool before it touches a system.** +- C. It always costs money. +- D. The LMS blocks it. + +**Answer: B.** Verify with the matching tool (`shellcheck`, `sshd -t`, a dry-run `find`, `visudo -c`), then log what it got right/wrong. + +--- + +## Lab 00 — Environment + +**Q00.1 [R]** Which file do Linux distributions ship so tools and humans can identify the running OS? +- A. `/etc/hostname` +- B. **`/etc/os-release`** +- C. `/proc/version` +- D. `/etc/motd` + +**Answer: B.** `/etc/os-release` is the standard key=value OS-identity file; `PRETTY_NAME` is the human-readable name. + +**Q00.2 [A]** Given the line `PRETTY_NAME="Ubuntu 24.04.1 LTS"`, the lab requires you to print exactly `Ubuntu 24.04.1 LTS`. What must your command do that a plain `grep` does not? +- A. Sort the output. +- B. **Split on `=` to take the value, then strip the surrounding double quotes.** +- C. Convert to uppercase. +- D. Add a trailing newline. + +**Answer: B.** e.g. `grep '^PRETTY_NAME=' | cut -d= -f2- | tr -d '"'`. + +--- + +## Lab 01 — Filesystem survey + +**Q01.1 [A]** You must find the *largest* file in a tree. Which pipeline is the right shape? +- A. `ls -l | head -1` +- B. **`find -type f -printf '%s %p\n' | sort -rn | head -1`** (or `du`-based equivalent) +- C. `cat * | wc -c` +- D. `grep -c . *` + +**Answer: B.** List each file with its size, sort numerically descending, take the top line. `ls -l | head` only looks at one directory and isn't sorted by size. + +**Q01.2 [R]** To count only regular files (not directories) under a tree, the key predicate is: +- A. `-name '*'` +- B. **`-type f`** +- C. `-perm 644` +- D. `-maxdepth 0` + +**Answer: B.** `-type f` matches regular files; `-type d` matches directories. + +--- + +## Lab 02 — File recovery + +**Q02.1 [A]** You need to copy every `*.log` file under a tree into `recovered/`. Which approach is safest and most correct? +- A. `mv *.log recovered/` +- B. **`find -type f -name '*.log' -exec cp {} recovered/ \;`** +- C. `cp *.log recovered/` +- D. `rm *.log` + +**Answer: B.** `find … -name '*.log'` recurses into subdirectories; a bare `*.log` glob only matches the current directory, and `mv`/`rm` would destroy the originals. + +**Q02.2 [R]** Before running any destructive `find … -exec` command, the recommended verification step is to: +- A. Run it as root. +- B. **Run the `find` with no action first to see exactly which files match.** +- C. Redirect output to `/dev/null`. +- D. Add `-f` to force it. + +**Answer: B.** Dry-run the match before attaching an action — a core rule from the AI-workflow guide. + +--- + +## Lab 03 — Permissions + +**Q03.1 [R]** The octal mode `640` grants which permissions? +- A. Everyone read/write/execute. +- B. **Owner read/write, group read, others nothing.** +- C. Owner read only, group and others read. +- D. Owner all, group all, others read. + +**Answer: B.** `6=rw-`, `4=r--`, `0=---` → `rw-r-----`. Appropriate for a secret readable only by owner and group. + +**Q03.2 [A]** "World-writable" means the *others* class has write permission. Which `find` predicate locates world-writable regular files? +- A. `-perm 777` +- B. `-perm -444` +- C. **`-perm -002 -type f`** +- D. `-writable` + +**Answer: C.** `-perm -002` matches any file whose "others" write bit is set, regardless of the other bits. Exact `-perm 777` would miss `666`, `662`, etc. + +**Q03.3 [R]** Why is `chmod 777` flagged as risky in this module? +- A. It is slower than `chmod 755`. +- B. **It makes a file readable, writable, and executable by *everyone*, including untrusted users — a common security mistake.** +- C. It only works as root. +- D. It removes the file. + +**Answer: B.** `777` is over-permissive; the AI guide explicitly lists suggesting `chmod 777` as a bad/risky AI habit. + +--- + +## Lab 04 — Users & groups + +**Q04.1 [R]** In `/etc/group`, a line looks like `sudo:x:27:alice,bob`. Which field holds the member list? +- A. Field 1 (group name) +- B. Field 3 (GID) +- C. **Field 4 (comma-separated members)** +- D. Field 2 (password placeholder) + +**Answer: C.** Format is `name:passwd:GID:member,member` — members are the 4th colon-separated field. + +**Q04.2 [A]** To add user `bob` to the `docker` group *without removing his other groups*, which is correct? +- A. `usermod -G docker bob` +- B. **`usermod -aG docker bob`** +- C. `usermod -g docker bob` +- D. `groupadd bob docker` + +**Answer: B.** `-aG` *appends*; `-G` alone *replaces* all supplementary groups (a classic footgun the AI guide warns about). `-g` sets the primary group. + +--- + +## Lab 05 — Log investigation + +**Q05.1 [A]** In a combined-format access log, field 1 is the client IP and field 9 is the HTTP status. Which pipeline finds the busiest client IP? +- A. `sort access.log | head -1` +- B. **`awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -1`** +- C. `grep -c . access.log` +- D. `awk '{print $9}' | uniq` + +**Answer: B.** Extract IPs, group-count with `sort | uniq -c`, then sort by count descending. `uniq -c` requires the input be sorted first. + +**Q05.2 [A]** Which condition counts exactly the 4xx and 5xx responses? +- A. `$9 > 400` +- B. **`$9 ~ /^[45][0-9][0-9]$/`** +- C. `$9 == 4 || $9 == 5` +- D. `$9 ~ /4|5/` + +**Answer: B.** Match a 3-digit status beginning with 4 or 5. `$9 ~ /4|5/` would wrongly match `204` or `500`-adjacent noise like `254`. + +**Q05.3 [R]** The AI-workflow guide warns that LLMs are unreliable at one specific task relevant to this lab. Which? +- A. Explaining what a status code means. +- B. **Counting from large files — they eyeball a sample instead of processing every line.** +- C. Suggesting `awk`. +- D. Naming the log format. + +**Answer: B.** Always compute counts with a tool; never trust an AI's "about N" tally. + +--- + +## Lab 06 — Pipelines + +**Q06.1 [A]** You must both display a status-code tally *and* save every 5xx line to `errors.log`. Which command writes to the file while passing data through? +- A. `> errors.log` +- B. **`tee errors.log`** +- C. `cat errors.log` +- D. `cp errors.log` + +**Answer: B.** `tee` writes stdin to a file *and* forwards it down the pipe, so you can log and keep processing in one pass. + +**Q06.2 [A]** In `grep '^5' | tee errors.log | wc -l`, what does `wc -l` count? +- A. Every line in the original log. +- B. **Only the 5xx lines that passed through `tee`.** +- C. The bytes in `errors.log`. +- D. Nothing; `tee` consumes the stream. + +**Answer: B.** `tee` is transparent — the same 5xx lines continue to `wc -l`, which counts them. + +--- + +## Lab 07 — Dotfiles + +**Q07.1 [R]** What does "idempotent" mean for the dotfile-symlink task? +- A. It runs only once ever. +- B. **Running it repeatedly produces the same end state without errors or duplicates.** +- C. It requires root. +- D. It deletes the target each time. + +**Answer: B.** A second run should be a safe no-op, not an error or a doubled link. + +**Q07.2 [A]** Which check makes `ln -s` idempotent so re-running doesn't error with "file exists"? +- A. Always `rm -rf` the home directory first. +- B. **Skip or `-f`/re-create only when the link is missing or points elsewhere (e.g. test with `[ -L "$dest" ]`).** +- C. Run it inside `sudo`. +- D. Redirect stderr to `/dev/null` and ignore it. + +**Answer: B.** Guard the link creation; silencing errors hides real problems and isn't true idempotency. + +--- + +## Lab 08 — Onboarding script + +**Q08.1 [A]** The script must fail early if a required command (e.g. `git`) is missing. Which is the idiomatic check? +- A. `if [ -f git ]` +- B. **`if ! command -v git >/dev/null 2>&1; then fail ...; fi`** +- C. `if git --version` +- D. `which git || true` + +**Answer: B.** `command -v` is the portable "is this command available?" test; the others are fragile or swallow the failure. + +**Q08.2 [R]** The starter begins with `set -euo pipefail`. What does the `-e` do? +- A. Echoes each command. +- B. **Exits the script immediately if any command returns a non-zero status.** +- C. Enables extended globbing. +- D. Encrypts output. + +**Answer: B.** `-e` = exit on error, `-u` = error on unset variables, `pipefail` = a pipeline fails if any stage fails. Together they make scripts fail loudly instead of limping on. + +--- + +## Lab 09 — Process management + +**Q09.1 [A]** From `ps aux` output, which pipeline finds the PID of the highest-`%CPU` process? (`%CPU` is column 3, PID is column 2.) +- A. `sort ps.txt | head -1` +- B. **`sort -rnk3 ps.txt | head -1 | awk '{print $2}'`** (skipping the header) +- C. `awk '{print $2}' ps.txt | sort -rn` +- D. `grep CPU ps.txt` + +**Answer: B.** Sort numerically-descending on the `%CPU` column, take the top data row, then print its PID field. You must exclude the header row. + +**Q09.2 [R]** Why sort with `-n` (numeric) rather than the default? +- A. It is faster. +- B. **A lexical sort would rank `9` above `80` because it compares character by character; numeric sort compares magnitudes.** +- C. `-n` removes duplicates. +- D. It is required by `ps`. + +**Answer: B.** Default `sort` is lexicographic, so `"9" > "80"` — wrong for numbers. + +--- + +## Lab 10 — Networking + +**Q10.1 [R]** The `ss -ltn` flags mean, respectively: +- A. list, tcp, numeric. +- B. **listening sockets, TCP only, numeric ports (no name resolution).** +- C. long, text, network. +- D. loopback, transmit, new. + +**Answer: B.** `-l` listening, `-t` TCP, `-n` numeric (don't resolve service names to strings like `ssh`). + +**Q10.2 [A]** To list the *unique* listening TCP ports from `ss -ltn` output, you need to: +- A. Print the whole file. +- B. **Extract the port from the Local-Address:Port column, then de-duplicate (`sort -u`).** +- C. Count total lines. +- D. Reverse-resolve each IP. + +**Answer: B.** Parse the address column to isolate the port after the last `:`, then unique them. + +--- + +## Lab 11 — SSH + +**Q11.1 [R]** A valid `~/.ssh/config` `Host` block groups connection settings under a host alias. Which is well-formed? +- A. `Host prod HostName 10.0.0.5 User deploy` (all on one line) +- B. **A `Host prod` line followed by indented `HostName`, `User`, and `Port` directives.** +- C. `prod = 10.0.0.5` +- D. `[prod] host=10.0.0.5` + +**Answer: B.** SSH config uses a `Host ` header with indented `Keyword value` lines beneath it; it is not INI or `key=value`. + +**Q11.2 [R]** What is the practical benefit of defining a `Host` alias? +- A. It encrypts the connection more strongly. +- B. **You can type `ssh prod` instead of the full user/host/port/key each time.** +- C. It disables password auth automatically. +- D. It is required for SSH to work. + +**Answer: B.** The alias captures HostName, User, Port, IdentityFile, etc., so connections become a single short command. + +--- + +## Lab 12 — Packages + +**Q12.1 [A]** Given `wanted.txt` (required packages) and `installed.txt` (installed, one per line), which reports packages that are wanted but *not* installed? +- A. `cat wanted.txt installed.txt | sort | uniq` +- B. **`comm -23 <(sort -u wanted.txt) <(sort -u installed.txt)`** (or a `grep -vxf installed.txt wanted.txt`) +- C. `diff wanted.txt installed.txt` +- D. `grep -f wanted.txt installed.txt` + +**Answer: B.** You want set-difference (wanted minus installed). `comm -23` on sorted inputs, or `grep -vxf` (lines in wanted not matching a whole line in installed), both work. Option D finds the *present* ones — the opposite. + +**Q12.2 [R]** Why does a whole-line match (`grep -x`) matter when comparing package names? +- A. It is faster. +- B. **So a wanted package like `git` isn't falsely considered installed because `git-lfs` appears in the list.** +- C. It sorts the output. +- D. It is required by `apt`. + +**Answer: B.** Substring matching would give false "installed" positives; anchor to the full line. + +--- + +## Lab 13 — Scheduling + +**Q13.1 [A]** Which crontab line runs a job at 09:00 on weekdays (Monday–Friday)? +- A. `9 0 * * 1-5` +- B. **`0 9 * * 1-5`** +- C. `0 9 1-5 * *` +- D. `* 9 * * 1-7` + +**Answer: B.** Fields are `minute hour day-of-month month day-of-week`. So `0 9 * * 1-5` = minute 0, hour 9, any date/month, weekdays 1–5. + +**Q13.2 [R]** The AI guide flags a specific cron mistake LLMs make. Which? +- A. Using `*` too often. +- B. **Swapping day-of-month and day-of-week (fields 3 and 5).** +- C. Forgetting the command. +- D. Using 24-hour time. + +**Answer: B.** Always reason through the five fields yourself or use a cron-expression checker before trusting AI output. + +--- + +## Lab 14 — Resources / storage + +**Q14.1 [R]** In `df -P` output, which column is the use percentage you compare against the threshold? +- A. Column 2 (1024-blocks) +- B. Column 3 (Used) +- C. **Column 5 (Use%)** +- D. Column 6 (Mounted on) + +**Answer: C.** `df -P` (POSIX format) guarantees one line per filesystem; field 5 is `Use%` and field 6 is the mount point. + +**Q14.2 [A]** The `%` sign in the Use% field is a problem for a numeric comparison. What must you do before comparing to the threshold? +- A. Multiply by 100. +- B. **Strip the trailing `%` (e.g. `tr -d '%'` or `sub(/%/,"")`) so it is a plain integer.** +- C. Convert to hexadecimal. +- D. Nothing; `[ 85% -gt 80 ]` works. + +**Answer: B.** `85%` is a string; you must remove `%` to compare `85 > 80` numerically. + +**Q14.3 [R]** Why is `df -P` preferred over plain `df` for a script? +- A. It shows more filesystems. +- B. **The POSIX `-P` format keeps each filesystem on a single line with stable columns, so field parsing is reliable.** +- C. It runs faster. +- D. It requires root. + +**Answer: B.** Long device names can wrap onto two lines in plain `df`; `-P` prevents that, keeping `awk`/`cut` parsing correct. + +--- + +## Capstone — CAP-9000 core (server health check) + +**Q15.1 [R]** The gradable capstone core integrates three earlier labs into one report. Which three? +- A. Environment, SSH, scheduling. +- B. **Permissions (world-writable), storage (disk over threshold), and packages (missing).** +- C. Networking, processes, dotfiles. +- D. File recovery, users, pipelines. + +**Answer: B.** It combines lab-03, lab-14, and lab-12 into a `WORLD-WRITABLE / DISK OVER THRESHOLD / MISSING PACKAGES` report. + +**Q15.2 [A]** The tests assert the three section headers appear *in a specific order*. What does this tell you about the spec? +- A. Order never matters in Bash. +- B. **Output format is part of correctness — you must print the exact headers in the required sequence, not just compute the right findings.** +- C. You can print them in any order. +- D. Headers are optional. + +**Answer: B.** A correct health check has a predictable, parseable format; the spec grades structure as well as content. + +**Q15.3 [R]** The README distinguishes the "gradable core" here from the "full CAP-9000" in the LMS box. Why isn't the full capstone (real `useradd`, hardened `sshd`, systemd timers) graded in this repo? +- A. It is too easy. +- B. **Those change real system state and can't be safely or deterministically auto-graded in a shared sandbox; they're verified in your LMS box + engineering notebook.** +- C. Bats cannot run scripts. +- D. It is not part of the module. + +**Answer: B.** The repo grades the deterministic, sandbox-safe core; system-state work is done and documented in the LMS environment. + +--- + +### Answer key (compact) + +Q0.1 C · Q0.2 B · Q0.3 C · Q0.4 B · +Q00.1 B · Q00.2 B · +Q01.1 B · Q01.2 B · +Q02.1 B · Q02.2 B · +Q03.1 B · Q03.2 C · Q03.3 B · +Q04.1 C · Q04.2 B · +Q05.1 B · Q05.2 B · Q05.3 B · +Q06.1 B · Q06.2 B · +Q07.1 B · Q07.2 B · +Q08.1 B · Q08.2 B · +Q09.1 B · Q09.2 B · +Q10.1 B · Q10.2 B · +Q11.1 B · Q11.2 B · +Q12.1 B · Q12.2 B · +Q13.1 B · Q13.2 B · +Q14.1 C · Q14.2 B · Q14.3 B · +Q15.1 B · Q15.2 B · Q15.3 B