feat: Add initial chapters and revisions for Assignment 2

This commit is contained in:
Payton Bates committed 2026-09-26 19:10:32 -04:00
1 parent 05fff52f6f
commit 07f65b10e9
8 files changed
+409 -36

No files matched your search

+13
View File
@@ -47,3 +47,16 @@ split of accounts into generated and derived classes.\\
and work-in-progress criteria, and rejected a proposal to create a GitHub
organization as premature while teams remain unformalized. Much of the assistant's
wording, structure, and ambitious ideas were rejected for overcomplication.
\subsection{Record 3 --- Linux Commands}
\textbf{Date:} September 26, 2026.\\
\textbf{Tool and model:} Anthropic Claude (Opus 5).\\
\textbf{Task}: Draft a template for \ChapterRef{LinuxCommands} with appropriate formatting
for terminal inputs and outputs, and a structure for the problem set solutions. Revise
the entire document to reflect the new chapter and team formation.\\
\textbf{Inputs:} The document template and the Linux problem set.\\
\textbf{Output used:} A skeleton of the chapter with its sections, setup figure, and
the problem set headings for each question. Suggested edits to the metadata, abstract, and
introduction for Assignment~2 and the two-person team.\\
\textbf{Human review and corrections:} The authors refined the chapter structure to accommodate
rubric requirements and experimented with different figure formatting for terminal inputs and outputs.
+1
View File
@@ -4,6 +4,7 @@
\newacronym{mfa}{MFA}{multi-factor authentication}
\newacronym{ssh}{SSH}{secure shell}
\newacronym{wip}{WIP}{work in progress}
\newacronym{wsl}{WSL}{Windows Subsystem for Linux}
\newglossaryentry{evidence}{name={evidence},description={A retained record of an
actual execution, observation, or review}}
\newglossaryentry{host}{name={host},description={A named machine in the
+2 -2
View File
@@ -50,8 +50,8 @@ rules govern access to the Linux hosts once they are provisioned.
\item Interactive access is by \gls{ssh} public key only.
Password authentication is disabled in the server configuration.
The local account password recorded in \ChapterRef{Passwords} authenticates \texttt{sudo} only.
\item Inbound \gls{ssh} is restricted by source address to the workstation
listed above rather than opened to the public Internet.
\item Inbound \gls{ssh} is restricted by source address to the local workstation
rather than opened to the public Internet.
\item Day-to-day work is performed by an unprivileged account. Administrative
rights are granted per command rather than by general membership in the
\texttt{sudo} group.
+18 -21
View File
@@ -7,15 +7,10 @@
\section{Purpose}
This document records the configuration of the development environment used for
\CourseNumber\ and the working practices followed to produce it. For
Assignment~\AssignmentNumber\ it covers three subjects: the \gls{kanban} that
plans and tracks the assignment work, the hosts the environment will comprise,
and the passwords that will govern accounts on those hosts.
It is a working record rather than a one-time report. Each subsequent
assignment extends it, and the document history records what changed and when,
so that the state of the environment at any point in the term can be recovered
from this document alone.
\CourseNumber\ and the working practices followed to produce it.
Each chapter covers one subject, and each assignment adds or revises chapters
as recorded in the document history. The latest revision for Assignment~\AssignmentNumber\
adds \ChapterRef{LinuxCommands}.
\section{Scope and Constraints}
\index{scope!constraints}
@@ -23,15 +18,15 @@ The following constraints apply to this revision.
\begin{itemize}[leftmargin=*]
\item The environment is \emph{specified} here, not provisioned. The hosts
chapter names the machines to be configured and their intended roles; it
does not claim that any host exists, and it therefore presents no
execution \gls{evidence}.
chapter names the machines to be configured and their intended roles.
\item Command-line work was performed on a local workstation running
Ubuntu~24.04 under the \gls{wsl}, not on a course
host. Terminal listings are copied from actual executions.
\item No credential, access token, private key, or account secret appears in
this document. Password rules are documented by derivation hint only, as
described in \ChapterRef{Passwords}.
\item This is an individual submission. Teams have not yet been formalized, so
the board described in \ChapterRef{KanbanSetup} is operated by a single
person and every card is assigned to the author.
\item This is a group submission. Chapters written before teams were formed
were prepared individually and are identified as such in the document history.
\item The document is authored in \LaTeX\ and compiled with pdf\LaTeX\ on
Overleaf. The board is hosted in GitHub Projects. The planned environment
targets Amazon EC2.
@@ -42,18 +37,20 @@ The following constraints apply to this revision.
\toprule \textbf{Item} & \textbf{Expectation}\\ \midrule
Due date & \DueDate\\
Instructor & \Instructor\\
Team & \Author\\
Board & GitHub Projects, \texttt{SSW 590} (private; captured as figures in \ChapterRef{KanbanSetup})\\
Required deliverables & Compiled document; Kanban Setup, Passwords, and Hosts chapters; updated document history\\
Team policy & Individual submission pending team formalization\\ \bottomrule
Required deliverables & Compiled document; Linux Commands chapter; updated document history\\
Team policy & Group submission\\ \bottomrule
\end{tabularx}
\section{Document Organization}
\index{document organization}
\ChapterRef{KanbanSetup} describes the tool selected for the board, the steps
taken to configure it, the policy governing each column, and the inventory of
cards. \ChapterRef{Hosts} names the hosts to be configured and
their roles. \ChapterRef{Passwords} defines the account and password rules for those hosts. \ChapterRef{AIPromptLog} records AI assistance used in preparing
this document.
taken to configure it, the policy governing each column, and the inventory of cards.
\ChapterRef{Hosts} names the hosts to be configured and their roles.
\ChapterRef{Passwords} defines the account and password rules for those hosts.
\ChapterRef{LinuxCommands} records the Linux working-directory setup and the problem-set solutions.
\ChapterRef{AIPromptLog} records AI assistance used in preparing this document.
This document is derived from the \CourseNumber\ assignment template credited on
the Template Attribution page. The template's instructional example chapter and
+359
View File
@@ -0,0 +1,359 @@
\chapter{Linux Commands}
\ChapterLabel{LinuxCommands}
\index{Linux}
\index{Linux!command line}
\index{Linux!working directory}
\index{bash}
\index{symbolic link}
\index{file timestamps}
\section{Purpose}
This chapter records a set of Linux shell commands run in the authors' working
user directories, and the solutions to the accompanying problem set.
Terminal input and output are copied directly from the shell, so each listing is
a record of an actual execution and serves as \gls{evidence} for this chapter.
\section{Environment}
\index{Linux!environment}
The commands were run as the unprivileged user \texttt{payton} on Ubuntu~24.04
under the \gls{wsl} on the author's workstation, in a \texttt{bash} shell.
\section{Working Directory Setup}
\index{Linux!working directory setup}
Figure~\ref{Figure:LxTestSetup} shows the executed setup commands in the order given by
the assignment. Figure~{\ref{Figure:LxTestDirectories}} shows the resulting directory structure,
and Figure~{\ref{Figure:LxTestFiles}} shows the resulting file contents.
\subsection{What the Commands Do}
\index{Linux!command explanations}
\begin{sloppypar}
\begin{itemize}[leftmargin=*]
\item \texttt{mkdir -p \textasciitilde/lx-test \&\& cd \textasciitilde/lx-test}
creates the directory, along with any missing parent directories, and does
not fail if it already exists. The \texttt{\&\&} operator runs \texttt{cd}
only if \texttt{mkdir} succeeds.
\item \texttt{printf "\ldots" > \textit{file}} writes the string to a file,
turning each \texttt{\textbackslash n} into a newline. The \texttt{>}
redirection creates the file or overwrites it if it already exists.
\texttt{printf} is used instead of \texttt{echo} because it handles escape
sequences the same way in every shell.
\item \texttt{dd} with \texttt{if=/dev/zero}, \texttt{of=blob.bin},
\texttt{bs=1K}, and \texttt{count=48} copies $48$ blocks of
$1\,\mathrm{KiB}$ from \texttt{/dev/zero}, producing a file of
$48 \times 1024 = 49152$ zero bytes.
\item \texttt{mkdir -p src/lib tmp archive} creates three directories in one
command; \texttt{-p} creates \texttt{src} as the parent of \texttt{lib}.
\item \texttt{ln -s src/file1.txt link-to-file1} creates a symbolic link. The
stored target is the relative path \texttt{src/file1.txt}, which is
resolved relative to the directory that contains the link.
\item \texttt{touch -t 202401020304 old.txt} creates \texttt{old.txt} with a
modification time of 2024-01-02 03:04 in local time.
\item \texttt{ls -lA} lists each named directory in long format, including
hidden entries but omitting \texttt{.} and \texttt{..}.
\texttt{head} prints the first ten lines of each file under a
file name header; every file here is shorter than ten
lines, so each is shown in full.
\end{itemize}
\end{sloppypar}
\subsection{Interpretation of Results}
\index{Linux!result interpretation}
Figure~\ref{Figure:LxTestDirectories} confirms each step of the setup:
\begin{itemize}[leftmargin=*]
\item \textbf{File sizes:} \texttt{blob.bin} is $49152$ bytes, as computed
above. Each text file's size equals its characters plus one byte per newline.
\item \textbf{Symbolic link:} \texttt{link-to-file1} has type \texttt{l} and
points to \texttt{src/file1.txt}.
\item \textbf{Timestamp:} \texttt{old.txt} is empty and shows the modified timestamp (\texttt{Jan~2~2024}).
\item \textbf{Directories:} \texttt{archive}, \texttt{tmp}, and
\texttt{src/lib} report \texttt{total 0}, confirming they exist and are empty.
\item \textbf{Permissions:} New files are \texttt{rw-r--r--} ($644$) and new
directories are \texttt{rwxr-xr-x} ($755$).
\end{itemize}
\begin{figure}[htbp]
\begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true]
payton@paytonpc:~$ mkdir -p ~/lx-test && cd ~/lx-test
payton@paytonpc:~/lx-test$ printf "alpha\nbeta\nGamma\ngamma\nbeta\n" > words.txt
payton@paytonpc:~/lx-test$ printf "id,name,dept\n1,Ada,EE\n2,Linus,CS\n3,Grace,EE\n4,Dennis,CS\n" > people.csv
payton@paytonpc:~/lx-test$ printf "INFO boot ok\nWARN disk low\nERROR fan fail\nINFO shutdown\n" > sys.log
payton@paytonpc:~/lx-test$ dd if=/dev/zero of=blob.bin bs=1K count=48 status=none
payton@paytonpc:~/lx-test$ mkdir -p src/lib tmp archive
payton@paytonpc:~/lx-test$ printf "one two three four\n" > src/file1.txt
payton@paytonpc:~/lx-test$ printf "two three four five\n" > src/file2.txt
payton@paytonpc:~/lx-test$ ln -s src/file1.txt link-to-file1
payton@paytonpc:~/lx-test$ touch -t 202401020304 old.txt
\end{lstlisting}
\caption{Terminal input for setting up the \texttt{lx-test} working directory.}
\label{Figure:LxTestSetup}
\end{figure}
\begin{figure}[htbp]
\begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true]
payton@paytonpc:~/lx-test$ ls -lA . src src/lib archive tmp
.:
total 72
drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 archive
-rw-r--r-- 1 payton payton 49152 Sep 26 15:39 blob.bin
lrwxrwxrwx 1 payton payton 13 Sep 26 15:39 link-to-file1 -> src/file1.txt
-rw-r--r-- 1 payton payton 0 Jan 2 2024 old.txt
-rw-r--r-- 1 payton payton 56 Sep 26 15:39 people.csv
drwxr-xr-x 3 payton payton 4096 Sep 26 15:39 src
-rw-r--r-- 1 payton payton 56 Sep 26 15:39 sys.log
drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 tmp
-rw-r--r-- 1 payton payton 28 Sep 26 15:39 words.txt
archive:
total 0
src:
total 12
-rw-r--r-- 1 payton payton 19 Sep 26 15:39 file1.txt
-rw-r--r-- 1 payton payton 20 Sep 26 15:39 file2.txt
drwxr-xr-x 2 payton payton 4096 Sep 26 15:39 lib
src/lib:
total 0
tmp:
total 0
\end{lstlisting}
\caption{Terminal output showing the resulting directories after \texttt{lx-test} setup.}
\label{Figure:LxTestDirectories}
\end{figure}
\begin{figure}[htbp]
\begin{lstlisting}[numbers=none, columns=fullflexible, keepspaces=true]
payton@paytonpc:~/lx-test$ head words.txt people.csv sys.log src/file1.txt src/file2.txt
==> words.txt <==
alpha
beta
Gamma
gamma
beta
==> people.csv <==
id,name,dept
1,Ada,EE
2,Linus,CS
3,Grace,EE
4,Dennis,CS
==> sys.log <==
INFO boot ok
WARN disk low
ERROR fan fail
INFO shutdown
==> src/file1.txt <==
one two three four
==> src/file2.txt <==
two three four five
\end{lstlisting}
\caption{Terminal output showing the resulting file contents after \texttt{lx-test} setup.}
\label{Figure:LxTestFiles}
\end{figure}
\section{Problem Set Solutions}
\index{Linux!problem set}
\subsection{Navigation and File Operations}
\begin{enumerate}[label=\arabic*., leftmargin=*]
\item Show your present working directory path only.
\begin{lstlisting}[style=cmd]
$ pwd
\end{lstlisting}
\item List all entries in the current directory, one per line, including dotfiles.
\begin{lstlisting}[style=cmd]
$ ls -1a
\end{lstlisting}
\item Copy \texttt{src/file1.txt} to \texttt{tmp/} only if \texttt{tmp} exists; do it verbosely.
\begin{lstlisting}[style=cmd]
$ [ -d tmp ] && cp -v src/file1.txt tmp/
\end{lstlisting}
\item Move \texttt{old.txt} into \texttt{archive/} and keep its original timestamp.
\begin{lstlisting}[style=cmd]
$ mv old.txt archive/
\end{lstlisting}
\item Create a new empty file \texttt{notes.md} only if it doesn't already exist.
\begin{lstlisting}[style=cmd]
$ [ -e notes.md ] || touch notes.md
\end{lstlisting}
\item Show disk usage (human-readable) for the \texttt{src} directory only (not total FS).
\begin{lstlisting}[style=cmd]
$ du -sh src
\end{lstlisting}
\end{enumerate}
\subsection{Viewing and Searching}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item Print line numbers while displaying \texttt{sys.log}.
\begin{lstlisting}[style=cmd]
$ cat -n sys.log
\end{lstlisting}
\item Show only the lines in \texttt{sys.log} that contain \texttt{ERROR} (case-sensitive).
\begin{lstlisting}[style=cmd]
$ grep 'ERROR' sys.log
\end{lstlisting}
\item Count how many distinct words appear in \texttt{words.txt} (case-insensitive).
\begin{lstlisting}[style=cmd]
$ tr '[:upper:]' '[:lower:]' < words.txt | sort -u | wc -l
\end{lstlisting}
\item From \texttt{words.txt}, show lines that start with \texttt{g} or \texttt{G}.
\begin{lstlisting}[style=cmd]
$ grep '^[gG]' words.txt
\end{lstlisting}
\item Display the first 2 lines of \texttt{people.csv} without using an editor.
\begin{lstlisting}[style=cmd]
$ head -n 2 people.csv
\end{lstlisting}
\item Show the last 3 lines of \texttt{sys.log} and keep following if the file grows.
\begin{lstlisting}[style=cmd]
$ tail -n 3 -f sys.log
\end{lstlisting}
\end{enumerate}
\subsection{Text Processing}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item From \texttt{people.csv}, print only the name column (2nd), excluding the header.
\begin{lstlisting}[style=cmd]
$ tail -n +2 people.csv | cut -d, -f2
\end{lstlisting}
\item Sort \texttt{words.txt} case-insensitively and remove duplicates.
\begin{lstlisting}[style=cmd]
$ sort -fu words.txt
\end{lstlisting}
\item Replace every \texttt{three} with \texttt{3} in all files under \texttt{src/} in-place, creating \texttt{.bak} backups.
\begin{lstlisting}[style=cmd]
$ find src -type f -name '*.txt' -exec sed -i.bak 's/three/3/g' {} +
\end{lstlisting}
\item Print the number of lines, words, and bytes for every \texttt{*.txt} file in \texttt{src/}.
\begin{lstlisting}[style=cmd]
$ wc src/*.txt
\end{lstlisting}
\end{enumerate}
\subsection{Permissions and Ownership}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item Make \texttt{tmp/} readable, writable, and searchable only by the owner.
\begin{lstlisting}[style=cmd]
$ chmod 700 tmp/
\end{lstlisting}
\item Give group execute permission to \texttt{src/lib} recursively without touching others/owner bits.
\begin{lstlisting}[style=cmd]
$ chmod -R g+x src/lib
\end{lstlisting}
\item Show the numeric (octal) permissions of \texttt{src/file2.txt}.
\begin{lstlisting}[style=cmd]
$ stat -c '%a' src/file2.txt
\end{lstlisting}
\item Make \texttt{notes.md} append-only for the owner via file attributes (if supported).
\begin{lstlisting}[style=cmd]
$ sudo chattr +a notes.md
\end{lstlisting}
\end{enumerate}
\subsection{Links and Find}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item Verify whether \texttt{link-to-file1} is a symlink and show its target path.
\begin{lstlisting}[style=cmd]
$ [ -L link-to-file1 ] && readlink link-to-file1
\end{lstlisting}
\item Find all regular files under the current tree larger than 40~KiB.
\begin{lstlisting}[style=cmd]
$ find . -type f -size +40k
\end{lstlisting}
\item Find files modified in the last 10 minutes under \texttt{tmp/} and print their sizes.
\begin{lstlisting}[style=cmd]
$ find tmp/ -type f -mmin -10 -printf '%p %s\n'
\end{lstlisting}
\end{enumerate}
\subsection{Processes and Job Control}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item Show your processes in a tree view.
\begin{lstlisting}[style=cmd]
$ pstree -p "$USER"
\end{lstlisting}
\item Start \texttt{sleep 120} in the background and show its PID.
\begin{lstlisting}[style=cmd]
$ sleep 120 & echo $!
\end{lstlisting}
\item Send a TERM signal to all \texttt{sleep} processes owned by you (don't use \texttt{kill -9}).
\begin{lstlisting}[style=cmd]
$ pkill -TERM -u "$USER" -x sleep
\end{lstlisting}
\item Show the top 5 processes by memory usage (one-shot, not interactive).
\begin{lstlisting}[style=cmd]
$ ps aux --sort=-%mem | head -n 6
\end{lstlisting}
\end{enumerate}
\subsection{Archiving and Compression}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item Create a gzipped tar archive \texttt{src.tgz} from \texttt{src/} with relative paths.
\begin{lstlisting}[style=cmd]
$ tar -czf src.tgz src/
\end{lstlisting}
\item List the contents of \texttt{src.tgz} without extracting.
\begin{lstlisting}[style=cmd]
$ tar -tzf src.tgz
\end{lstlisting}
\item Extract only \texttt{file2.txt} from \texttt{src.tgz} into \texttt{tmp/}.
\begin{lstlisting}[style=cmd]
$ tar -xzvf src.tgz -C tmp/ --strip-components=1 src/file2.txt
\end{lstlisting}
\end{enumerate}
\subsection{Networking and System Information}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item Show all listening TCP sockets with associated PIDs (no root assumptions).
\begin{lstlisting}[style=cmd]
$ ss -ltnp
\end{lstlisting}
\item Print your default route (gateway) in a concise form.
\begin{lstlisting}[style=cmd]
$ ip route show default
\end{lstlisting}
\item Display kernel name, release, and machine architecture.
\begin{lstlisting}[style=cmd]
$ uname -srm
\end{lstlisting}
\item Show the last 5 successful logins (or last sessions) on the system.
\begin{lstlisting}[style=cmd]
$ last -n 5
\end{lstlisting}
\end{enumerate}
\subsection{Packages and Services (Debian/Ubuntu)}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item Show the installed version of package \texttt{coreutils}.
\begin{lstlisting}[style=cmd]
$ dpkg-query -W -f='${Version}\n' coreutils
\end{lstlisting}
\item Search available packages whose names contain \texttt{ripgrep}.
\begin{lstlisting}[style=cmd]
$ apt-cache search --names-only ripgrep
\end{lstlisting}
\item Check whether service \texttt{cron} is active and print its status line only.
\begin{lstlisting}[style=cmd]
$ systemctl status cron | grep 'Active:'
\end{lstlisting}
\end{enumerate}
\subsection{Bash and Scripting}
\begin{enumerate}[label=\arabic*., leftmargin=*, resume]
\item Write a one-liner that loops over \texttt{*.txt} in \texttt{src/} and prints each file's name and line count.
\begin{lstlisting}[style=cmd]
$ for f in src/*.txt; do echo "$f: $(wc -l < "$f")"; done
\end{lstlisting}
\item Write a command that exports CSV rows where \texttt{dept == "CS"} to \texttt{cs.txt} (exclude header).
\begin{lstlisting}[style=cmd]
$ awk -F, 'NR>1 && $3=="CS"' people.csv > cs.txt
\end{lstlisting}
\item Create a variable \texttt{X} with value 42, print it, then remove it from the environment.
\begin{lstlisting}[style=cmd]
$ export X=42; echo "$X"; unset X
\end{lstlisting}
\end{enumerate}
+9 -6
View File
@@ -34,17 +34,17 @@
\definecolor{devopsLightBlue}{RGB}{232,240,247}
% Replace these values for each assignment.
\newcommand{\AssignmentTitle}{Compile Overleaf Document and Detail Kanban Setup}
\newcommand{\AssignmentNumber}{1}
\newcommand{\DocumentVersion}{1.0}
\newcommand{\AssignmentTitle}{Linux Commands}
\newcommand{\AssignmentNumber}{2}
\newcommand{\DocumentVersion}{2.0}
\newcommand{\DocumentStatus}{Submitted Document}
\newcommand{\CourseNumber}{SSW 590}
\newcommand{\CourseName}{DevOps}
\newcommand{\Author}{Payton Bates}
\newcommand{\Author}{Payton Bates and Victor Del Rio Foces}
\newcommand{\Instructor}{Darian Muresan, Ph.D.}
\newcommand{\Organization}{Stevens Institute of Technology}
\newcommand{\DocumentDate}{September 18, 2026}
\newcommand{\DueDate}{September 21, 2026 by 11:59pm}
\newcommand{\DocumentDate}{September 26, 2026}
\newcommand{\DueDate}{September 28, 2026 by 11:59pm}
\newcommand{\VERSION}{Version \DocumentVersion}
\hypersetup{
@@ -88,6 +88,8 @@
stringstyle=\color{devopsRed}, tabsize=2
}
\lstdefinestyle{cmd}{numbers=none, columns=fullflexible, upquote=true, belowskip=0pt, xleftmargin=5pt, xrightmargin=0pt}
\changenormalspacing{\singlespacing}
\begin{document}
\pagenumbering{roman}
@@ -112,6 +114,7 @@
\include{chapters/devopsKanbanSetup}
\include{chapters/devopsHosts}
\include{chapters/devopsPasswords}
\include{chapters/devopsLinuxCommands}
\appendix
\include{backmatter/devopsAIPromptLog}
+6 -7
View File
@@ -1,7 +1,6 @@
This document records the development-environment configuration for the first
SSW 590 assignment. It describes the Kanban board used to plan and track the
work, the hosts the environment will comprise, and the password rules that
will govern accounts on those hosts. The environment is specified here as a
plan; provisioning and its supporting evidence are deferred to a later
submission. Password rules are recorded as derivation hints, so that no
credential appears in this document.
This document records the development environment and working practices used
in SSW 590. It is extended with each assignment, and the document history
identifies what each revision changed. Its chapters currently cover planning and tracking
the work, the hosts and accounts that make up the environment, and the
command-line and operational work performed in it. Environments specified here
are plans, and the actual provisioning will be done in the future.
+1
View File
@@ -11,5 +11,6 @@ link each entry to the changed chapter, table, figure, or controlled artifact.
\multicolumn{4}{l}{\small\itshape Document Update History (continued)}\\
\toprule \textbf{Date / Version} & \textbf{Author Initials} & \textbf{Change} & \textbf{Changed At}\\ \midrule
\endhead \bottomrule \endlastfoot
September 26, 2026 / 2.0 & PCB, VDRF & Added the Linux Commands chapter: working-directory setup with terminal input/output figures, command explanations and interpretation of results, and solutions to the Linux problem set. Updated document metadata and authorship for Assignment 2 and the two-person team. & \ChapterRef{LinuxCommands}, \ChapterRef{Introduction}, \ChapterRef{Hosts}, \ChapterRef{AIPromptLog}\\
September 18, 2026 / 1.0 & PCB & Created this document from the \CourseNumber\ assignment template. Removed instructional/example chapters, set document metadata and authorship, and rewrote the abstract and introduction to describe this environment rather than the template. Added the Kanban Setup, Passwords, and Hosts chapters, the account and password rules, and the planned hosts. & \ChapterRef{Introduction}, \ChapterRef{KanbanSetup}, \ChapterRef{Passwords}, \ChapterRef{Hosts}, \ChapterRef{AIPromptLog}\\
\end{tabularx}