From efe92994f626f54ab099c277ccce449f9f05a223 Mon Sep 17 00:00:00 2001 From: vincentpenalosa Date: Fri, 9 Oct 2026 21:01:49 -0400 Subject: [PATCH] Prepare automated manual build and Chapter 3 draft --- .gitea/workflows/manual.yml | 36 +++ .gitignore | 5 + ci/build_manual.py | 86 ++++++ ci/runner-config.yaml | 13 + ci/setup_runner.sh | 46 +++ ci/smartpark-runner.service | 23 ++ docs/CH3-HANDOFF.md | 304 ++++++++++++++++++++ docs/ch3-evidence.md | 18 ++ latex-manual/devopsAssignment.tex | 20 +- latex-manual/devopsAutomatedManualBuild.tex | 104 +++++++ latex-manual/devopsDocumentHistory.tex | 8 + 11 files changed, 662 insertions(+), 1 deletion(-) create mode 100644 .gitea/workflows/manual.yml create mode 100644 .gitignore create mode 100644 ci/build_manual.py create mode 100644 ci/runner-config.yaml create mode 100644 ci/setup_runner.sh create mode 100644 ci/smartpark-runner.service create mode 100644 docs/CH3-HANDOFF.md create mode 100644 docs/ch3-evidence.md create mode 100644 latex-manual/devopsAutomatedManualBuild.tex diff --git a/.gitea/workflows/manual.yml b/.gitea/workflows/manual.yml new file mode 100644 index 0000000..5cb79a4 --- /dev/null +++ b/.gitea/workflows/manual.yml @@ -0,0 +1,36 @@ +name: Build SmartPark manual +on: + push: + branches: + - main + - chapter3-build-automation + - chapter3-build-test + +jobs: + manual: + runs-on: smartpark-latex + timeout-minutes: 20 + steps: + - name: Check out the triggering revision + uses: https://github.com/actions/checkout@v4.2.2 + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + - name: Build PDF and record source identity + env: + MANUAL_CI: 'true' + MANUAL_COMMIT: ${{ github.sha }} + MANUAL_RUN_NUMBER: ${{ github.run_number }} + run: python3 ci/build_manual.py + - name: Publish PDF + # v3 uses the legacy artifact protocol commonly supported by Gitea. + # Actual upload compatibility and retention must be verified on this server. + uses: https://github.com/actions/upload-artifact@v3.1.3 + with: + name: smartpark-manual-${{ github.run_number }}-${{ github.sha }} + path: | + build/manual/SmartPark-Manual.pdf + build/manual/build-info.txt + if-no-files-found: error + retention-days: 30 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d247ad2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +# Chapter 3 generated outputs and private runner identity +/build/ +.runner +/latex-manual/build-metadata.tex diff --git a/ci/build_manual.py b/ci/build_manual.py new file mode 100644 index 0000000..740b745 --- /dev/null +++ b/ci/build_manual.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +"""Build only from a fresh temporary copy; publish output only on success.""" +from pathlib import Path +import datetime, os, re, shutil, subprocess, tempfile + +ROOT = Path(__file__).resolve().parents[1] +SOURCE = ROOT / 'latex-manual' +OUT = ROOT / 'build' / 'manual' + +def run(args, cwd=ROOT): + print('+ ' + ' '.join(args), flush=True) + subprocess.run(args, cwd=cwd, check=True) + +def git(*args): + return subprocess.check_output(['git', *args], cwd=ROOT, text=True).strip() + +def main(): + OUT.mkdir(parents=True, exist_ok=True) + # Only remove this script's two fixed output files, so a failed run cannot + # leave a stale deliverable looking successful. + for name in ('SmartPark-Manual.pdf', 'build-info.txt'): + (OUT / name).unlink(missing_ok=True) + sha = git('rev-parse', 'HEAD') + expected = os.environ.get('MANUAL_COMMIT', '') + ci = os.environ.get('MANUAL_CI', '') == 'true' + dirty = bool(git('status', '--porcelain', '--untracked-files=normal')) + if ci and (not expected or expected != sha or dirty): + raise RuntimeError('CI checkout must be clean and match MANUAL_COMMIT') + number = os.environ.get('MANUAL_RUN_NUMBER', 'local') + if ci and not number.isdigit(): + raise RuntimeError('Missing numeric Gitea run number') + if not re.fullmatch(r'[A-Za-z0-9.-]+', number): + raise RuntimeError('Unsafe run identifier') + revision = sha[:12] + ('-dirty' if dirty else '') + build_time = datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M UTC') + for tool in ('latexmk', 'pdflatex', 'bibtex', 'makeglossaries', 'makeindex', 'pygmentize'): + if shutil.which(tool) is None: + raise RuntimeError('Missing tool: ' + tool) + with tempfile.TemporaryDirectory(prefix='manual-', dir=ROOT / 'build') as temp: + work = Path(temp) + shutil.copytree(SOURCE, work, dirs_exist_ok=True, + ignore=shutil.ignore_patterns('*.aux', '*.log', '*.pdf', '*.toc', '*.out', + '*.bbl', '*.blg', '*.fdb_latexmk', '*.fls', '*.idx', '*.ind', '*.ilg', + '*.glo', '*.gls', '*.glg', '*.ist', '*.acn', '*.acr', '*.alg', + '*.lof', '*.lot', '_minted-*', 'build-metadata.tex')) + # Do not discard legitimate PDF figures: restore tracked/source PDFs + # except the old root document output. + for source_pdf in SOURCE.rglob('*.pdf'): + if source_pdf == SOURCE / 'devopsAssignment.pdf': + continue + target = work / source_pdf.relative_to(SOURCE) + target.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(source_pdf, target) + (work / 'build-metadata.tex').write_text( + '\\renewcommand{\\BuildRevision}{' + revision + '}\n' + + '\\renewcommand{\\BuildRun}{' + number + '}\n' + + '\\renewcommand{\\BuildUTC}{' + build_time + '}\n', encoding='utf-8') + command = ['latexmk', '-pdf', '-interaction=nonstopmode', '-halt-on-error', + '-file-line-error', '-shell-escape', 'devopsAssignment.tex'] + run(command, work) + run(['makeglossaries', 'devopsAssignment'], work) + if (work / 'devopsAssignment.idx').stat().st_size: + run(['makeindex', 'devopsAssignment.idx'], work) + run(command, work) + pdf = work / 'devopsAssignment.pdf' + if not pdf.is_file() or pdf.stat().st_size < 5 or pdf.read_bytes()[:5] != b'%PDF-': + raise RuntimeError('Expected nonempty PDF was not produced') + log = (work / 'devopsAssignment.log').read_text(errors='replace') + if 'There were undefined references' in log or 'There were undefined citations' in log: + raise RuntimeError('PDF still contains unresolved references/citations; inspect source') + shutil.copy2(pdf, OUT / 'SmartPark-Manual.pdf') + info = f'commit={sha}\nrevision={revision}\nrun={number}\nutc={build_time}\n' + info += 'mode=' + ('Gitea Actions' if ci else 'LOCAL TEST - not Actions evidence') + '\n' + for tool, flag in [('latexmk','-v'), ('pdflatex','--version'), ('pygmentize','-V')]: + result = subprocess.check_output([tool, flag], text=True) + info += result + packages = subprocess.check_output(['dpkg-query', '-W', + '-f=${Package}\t${Version}\n', 'latexmk', 'texlive-base', + 'texlive-latex-extra', 'texlive-fonts-recommended', 'lmodern', 'python3-pygments'], text=True) + info += '\nUbuntu package versions:\n' + packages + (OUT / 'build-info.txt').write_text(info, encoding='utf-8') + print(info) + print('SUCCESS: ' + str(OUT / 'SmartPark-Manual.pdf')) + +if __name__ == '__main__': + main() diff --git a/ci/runner-config.yaml b/ci/runner-config.yaml new file mode 100644 index 0000000..2c67a3b --- /dev/null +++ b/ci/runner-config.yaml @@ -0,0 +1,13 @@ +log: + level: info +runner: + file: /var/lib/smartpark-runner/.runner + capacity: 1 + timeout: 20m + shutdown_timeout: 25m + labels: + - smartpark-latex:host +cache: + enabled: false +host: + workdir_parent: /var/lib/smartpark-runner/work diff --git a/ci/setup_runner.sh b/ci/setup_runner.sh new file mode 100644 index 0000000..83230d5 --- /dev/null +++ b/ci/setup_runner.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# Run as your normal Ubuntu user, not as root. Uses sudo for installation. +set -euo pipefail +[[ $(uname -m) == x86_64 ]] || { echo 'This installer targets x86_64 only'; exit 1; } +base=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +[[ ! -e /etc/smartpark-runner/config.yaml ]] || { echo 'Runner already configured; inspect it rather than overwrite.'; exit 1; } +sudo apt-get update +sudo apt-get install --no-install-recommends curl ca-certificates xz-utils +downloads=$(mktemp -d) +cd "$downloads" +# Resolve the current Node 22 release from its official checksum list, then +# install and record that exact release. No downloaded install script is run. +curl -fSLO https://nodejs.org/dist/latest-v22.x/SHASUMS256.txt +node_archive=$(awk '$2 ~ /^node-v22\.[0-9]+\.[0-9]+-linux-x64\.tar\.xz$/ {print $2}' SHASUMS256.txt) +[[ -n "$node_archive" && "$node_archive" != *$'\n'* ]] +node_version=${node_archive#node-} +node_version=${node_version%-linux-x64.tar.xz} +curl -fSLO "https://nodejs.org/dist/$node_version/$node_archive" +awk -v f="$node_archive" '$2 == f' SHASUMS256.txt | sha256sum -c - +tar -xf "$node_archive" +[[ ! -e /opt/smartpark-node ]] || { echo '/opt/smartpark-node exists; inspect before continuing'; exit 1; } +sudo mv "${node_archive%.tar.xz}" /opt/smartpark-node +sudo chown -R root:root /opt/smartpark-node + +runner_version=2.3.0 +runner_file="gitea-runner-$runner_version-linux-amd64" +curl -fSLO "https://dl.gitea.com/gitea-runner/$runner_version/$runner_file" +curl -fSLO "https://dl.gitea.com/gitea-runner/$runner_version/$runner_file.sha256" +sha256sum -c "$runner_file.sha256" +sudo install -m 0755 "$runner_file" /usr/local/bin/gitea-runner +if id smartpark-runner >/dev/null 2>&1; then + echo 'smartpark-runner account already exists; inspect its permissions before continuing.' + exit 1 +fi +sudo useradd --system --create-home --home-dir /var/lib/smartpark-runner --shell /usr/sbin/nologin smartpark-runner +sudo chmod 700 /var/lib/smartpark-runner +sudo install -d -o smartpark-runner -g smartpark-runner -m 700 /var/lib/smartpark-runner/work +sudo install -d -o root -g smartpark-runner -m 750 /etc/smartpark-runner +sudo install -o root -g smartpark-runner -m 640 "$base/runner-config.yaml" /etc/smartpark-runner/config.yaml +sudo install -m 644 "$base/smartpark-runner.service" /etc/systemd/system/smartpark-runner.service +sudo systemctl daemon-reload +sudo -u smartpark-runner /opt/smartpark-node/bin/node --version +sudo -u smartpark-runner /usr/local/bin/gitea-runner --version +sudo -u smartpark-runner latexmk -v +echo 'Installed, but NOT registered or started. Registration requires an authorized token.' +echo "Verified downloads remain in $downloads; remove those files later using the Files app if desired." diff --git a/ci/smartpark-runner.service b/ci/smartpark-runner.service new file mode 100644 index 0000000..9f208d9 --- /dev/null +++ b/ci/smartpark-runner.service @@ -0,0 +1,23 @@ +[Unit] +Description=SmartPark Gitea manual runner +After=network-online.target +Wants=network-online.target + +[Service] +User=smartpark-runner +Group=smartpark-runner +WorkingDirectory=/var/lib/smartpark-runner +Environment=HOME=/var/lib/smartpark-runner +Environment=PATH=/opt/smartpark-node/bin:/usr/local/bin:/usr/bin:/bin +ExecStart=/usr/local/bin/gitea-runner daemon --config /etc/smartpark-runner/config.yaml +Restart=on-failure +RestartSec=10 +UMask=0077 +NoNewPrivileges=true +PrivateTmp=true +ProtectHome=true +ProtectSystem=full +TimeoutStopSec=30min + +[Install] +WantedBy=multi-user.target diff --git a/docs/CH3-HANDOFF.md b/docs/CH3-HANDOFF.md new file mode 100644 index 0000000..eff81e5 --- /dev/null +++ b/docs/CH3-HANDOFF.md @@ -0,0 +1,304 @@ +# SmartPark Chapter 3: local preparation and Gitea handoff + +Prepared October 9, 2026. This kit is a draft implementation, not proof that +Gitea Actions is working. The original documentation was reported to compile +successfully in Vincent's Ubuntu VM. The new build script and edited manual +must be tested there. Registration, checkout in Actions, metadata, artifact +upload, retention, and required demonstrations remain pending. + +## 1. Apply to Vincent's clean feature branch + +Copy this ZIP into Ubuntu's Downloads folder and extract it there. The folder +must contain apply_to_repo.py and payload/. Hidden .gitea files are included +by the installer; do not copy the payload manually. + +```bash +cd ~/smartpark-ch3-work/smartpark-app +python3 ~/Downloads/smartpark-ch3-kit/apply_to_repo.py "$PWD" +git diff --stat +git status --short +python3 ci/build_manual.py +``` + +The installer expects branch chapter3-build-automation, a clean checkout, +and the original version 1.8 source. It refuses changed layouts or existing +target files rather than overwriting them. If it refuses, preserve your work +and inspect the message. It is intended to run once. + +Open build/manual/SmartPark-Manual.pdf. Check the new build identification +page, all original chapters, the new eight-section chapter, references, +glossary and index. A first local build should say local and dirty because +your new edits are not committed. It must not show a fabricated Actions run. +The new chapter number follows the existing manual; it addresses assignment +Chapter 3 even if it becomes Chapter 7 in your team's document. + +The script removes only its two fixed prior deliverables and builds in a +fresh temporary directory. TeX failures return nonzero, leaving no prior +successful PDF in the publish directory. Console output includes the error; +temporary TeX files are removed after the attempt. Preserve terminal output +if troubleshooting is needed. Do not fix an error by ignoring its exit code. + +## 2. Commit locally + +Review all new files, including the workflow, before committing. If Git asks +for your identity, set your real name and your chosen Git commit email with +git config user.name and git config user.email (repository-local settings). + +```bash +git diff --check +git add .gitignore .gitea/workflows/manual.yml ci docs/ch3-evidence.md docs/CH3-HANDOFF.md latex-manual/devopsAssignment.tex latex-manual/devopsDocumentHistory.tex latex-manual/devopsAutomatedManualBuild.tex +git commit -m "Prepare automated manual build and Chapter 3 draft" +python3 ci/build_manual.py +git status --short +``` + +After committing, the local PDF should identify that commit without dirty. +git status should be empty. The PDF remains local evidence only. +If using a log with tee, preserve failures with `set -o pipefail` first. + +## 3. Prepare a runner (optional now; can be done by Nica later) + +This installer targets only the dedicated Ubuntu x86_64 VM. It does not +configure the shared DigitalOcean Droplet. It downloads Node 22 from the +official release server, verifies its listed checksum, and records its exact +version in terminal output. It installs Gitea Runner 2.3.0 with its official +checksum. It creates an unprivileged service account, host-mode label +smartpark-latex:host, capacity one, and a system service. It neither registers +nor starts the runner. Node remains at /opt/smartpark-node/bin/node, not on +your normal user's PATH; the service PATH includes it. + +Read ci/setup_runner.sh, then run: + +```bash +bash ci/setup_runner.sh +df -h / +``` + +No Docker, exposed runner port, or Droplet login is needed. If setup fails, +stop at the actual error. It deliberately refuses to replace existing +accounts/configurations, so a partial installation must be inspected before +retrying. Do not blindly delete an existing service account or registration. + +The source build tools installed by Vincent are: + +```bash +sudo apt-get update +sudo apt-get install --no-install-recommends git python3 latexmk texlive-latex-extra texlive-fonts-recommended lmodern python3-pygments +``` + +Nica needs those packages if reproducing on her own dedicated Ubuntu host. +Record the actual installed package versions from build-info.txt. A fresh +apt installation may differ from Vincent's; rebuild and verify accordingly. + +## 4. Registration: only after authorized Gitea admin help + +Have the repository administrator confirm Actions is enabled and provide a +new repository-scoped registration token securely, or assist interactively. +Do not use a personal access token in place of a runner registration token. +Do not share the old Droplet's .runner identity. Registration is performed +on the machine that will execute jobs, with its own new identity. + +Run in the Ubuntu VM: + +```bash +sudo -u smartpark-runner sh -c 'umask 077; cd /var/lib/smartpark-runner && /usr/local/bin/gitea-runner --config /etc/smartpark-runner/config.yaml register' +``` + +Interactive answers: + +- Instance URL: https://git.137-184-97-250.nip.io (not the repository URL). +- Token: enter it privately at the prompt; do not include it in screenshots. +- Name: vincent-ubuntu-manual (or the actual replacement owner's name). +- Labels: smartpark-latex:host. The supplied config already specifies it. + +After successful registration: + +```bash +sudo chmod 600 /var/lib/smartpark-runner/.runner +sudo systemctl enable --now smartpark-runner +sudo systemctl status smartpark-runner --no-pager +``` + +The administrator should confirm the runner appears online and is scoped to +smartpark-app. Review all workflows that may target this runner: push-only +triggers in this file do not prevent another workflow from using its label. +Host-mode jobs are not mutually isolated and can read the service account's +runner identity. Restrict workflow authors to trusted teammates. The service +account has no sudo or Docker group. Do not grant either just to fix a build. + +NoNewPrivileges and other service restrictions help limit the account but +are not a sandbox against hostile jobs. Use a dedicated VM without personal +shared folders/keys. Workflow job tokens also require suitable permissions. + +## 5. Push the prepared branch + +```bash +cd ~/smartpark-ch3-work/smartpark-app +git push -u origin chapter3-build-automation +``` + +This requires branch write access, not repository Settings access. If denied, +use the handoff in section 9. If a push happened while Actions was disabled, +make a real source correction and push again once enabled. A push-triggered +build is the required evidence, not merely pressing a rerun button. + +The workflow must be present on the branch that receives the push. If the +Actions page opens on main, select the branch/run list for your feature +branch. Do not assume an empty main view proves feature workflows are absent. +PR #8 does not have to be merged first. Coordinate eventual merge order so +the documentation and automation are both retained. + +In the Actions run, verify checkout SHA, successful compile, and successful +artifact upload. Download the artifact, extract its PDF, and inspect the +visible run number and short SHA against the run and commit. The workflow +requests 30-day retention; ask the administrator what was actually applied. +If upload fails, the assignment is not complete even if the compile is green. + +The workflow records checkout v4.2.2 and upload-artifact v3.1.3 as exact tags. +Tags are not immutable commit-SHA pins. The upload action uses the legacy +artifact protocol; its compatibility with this server still needs an actual +test. Do not change blindly to GitHub upload-artifact v4 to fix an error: +check the server's supported protocol/action and preserve the failure log. + +## 6. Required success, failure and repair sequence + +Use only the dedicated test branch. Start with a clean working tree and a +committed successful preparation. The following changes are intentional, +reviewable source changes. Record each run BEFORE the next push. + +```bash +git switch -c chapter3-build-test +printf '\nFirst automated source-change demonstration.\\par\n' >> latex-manual/devopsAutomatedManualBuild.tex +git add latex-manual/devopsAutomatedManualBuild.tex +git commit -m "Document first manual build demonstration" +git push -u origin chapter3-build-test +``` + +Wait for success. Download PDF #1 and record the commit/run/version/artifact. + +```bash +printf '\nSecond automated source-change demonstration.\\par\n' >> latex-manual/devopsAutomatedManualBuild.tex +git add latex-manual/devopsAutomatedManualBuild.tex +git commit -m "Document second manual build demonstration" +git push +``` + +Wait for success. Download PDF #2 and record matching evidence. Now create +the controlled error on this test branch: + +```bash +printf '\n\\SmartParkIntentionalBuildFailure\n' >> latex-manual/devopsAutomatedManualBuild.tex +git add latex-manual/devopsAutomatedManualBuild.tex +git commit -m "Demonstrate controlled LaTeX compilation failure" +git push +``` + +Wait for the failed compile, preserve the error/run/commit and confirm the +upload step did not publish a successful PDF. Then repair by reverting only +that latest failure commit. Run the following ONLY while that failure commit +is still HEAD and the working tree is clean: + +```bash +git log -1 --oneline +git status --short +git revert --no-edit HEAD +git push +``` + +Capture the repaired successful run and PDF. Fill docs/ch3-evidence.md with +real results and transfer them into the manual chapter. Replace demonstration +sentences with the actual findings in a later editorial commit. + +## 7. Complete the manual + +The eight sections are skeletons. Keep earlier chapters and fill actual +runner, network and security details, source/run/artifact links, dated +screenshots, expected/actual outcomes, and failed-build troubleshooting. +Update Hosts and Passwords-hints tables and explicitly record their changes. +Review document version, date, title and assignment number (the older title +and assignment number were deliberately preserved for team decision), add +bibliography/glossary entries, and log AI assistance per team conventions. +The added history row is a draft with human review pending. + +Arrange peer review and merge through the normal process. Do not bypass +Jenkins required checks or branch protections. After integration into main, +confirm its push-triggered run and download the final artifact. Submit only +the PDF extracted from that successful Actions artifact, not this kit or a +local PDF. The source/script preparation alone is not submission-ready. + +## 8. Availability and troubleshooting + +- A user service terminal is not needed: systemd starts the runner when Ubuntu + boots. The VM and Windows computer must still be awake and connected. +- Disable automatic suspend in Ubuntu's Power settings while running jobs; + keep Windows awake during agreed build/grading periods. A laptop is not + an always-on server unless you actually keep it available. +- Reboot the VM after initial success, check service status and online state, + and push a harmless source correction to verify recovery. +- Queued: check online status, repository scope and exact smartpark-latex label. +- Checkout: check network/TLS and job-token repository permissions. Do not + disable certificate checks or insert a personal token into the workflow. +- JavaScript/action error: confirm the service's /opt/smartpark-node/bin/node + exists; inspect the action's compatibility and runner logs. +- TeX: fix the first real error. Undefined references may be inherited source + problems; resolve them rather than remove the quality check. +- Artifact: inspect the separate upload step, server protocol and access. +- Logs: sudo journalctl -u smartpark-runner -n 80 --no-pager (review/redact + before sharing). Never dump all environment variables or the .runner file. +- Stop: sudo systemctl stop smartpark-runner. Retire: disable service and ask + an administrator to remove the registration; never send identity files. + +## 9. Handoff to Nica if access is unavailable + +Commit the prepared files before packaging. Use the branch containing the +latest completed, repaired work. This archives tracked source only and +excludes runner credentials, build output and your Git login settings: + +```bash +git status --short +git log -1 --oneline +git archive --format=zip --output="$HOME/Downloads/smartpark-ch3-source-handoff.zip" HEAD +``` + +Also create a Git bundle of the current branch so Nica can retain commit +identity (the build script requires a Git checkout): + +```bash +git bundle create "$HOME/Downloads/smartpark-ch3.git.bundle" HEAD +git bundle verify "$HOME/Downloads/smartpark-ch3.git.bundle" +``` + +Send that ZIP and Git bundle plus a short factual status: commit ID, actual local test +result, who will host the runner, what needs registration, and which Gitea +checks remain pending. The ZIP includes docs/CH3-HANDOFF.md and the evidence +worksheet. If Nica will host it, she follows the same setup and registers a +new identity on her host; do not copy /var/lib/smartpark-runner/.runner. +If branch access works, prefer a pushed branch and PR link for review. + +If Nica receives only these files, she can start a NEW checkout (destination +must not already exist) from the bundle without depending on your laptop: + +```bash +git clone ~/Downloads/smartpark-ch3.git.bundle ~/smartpark-ch3-takeover +cd ~/smartpark-ch3-takeover +git switch -c chapter3-nica-takeover +git remote set-url origin https://git.137-184-97-250.nip.io/stevens-smartpark/smartpark-app.git +``` + +This already includes the applied changes; do not run the kit installer again. +She must add chapter3-nica-takeover to the workflow's push branch list if +testing pushes on that branch. She should inspect the bundle/source contents +before running scripts. The source ZIP is for browsing/import only; a plain +unpacked ZIP does not provide the Git commit information the build requires. + +## Official references and verification limits + +- https://docs.gitea.com/runner/2/installation/binary/ +- https://docs.gitea.com/runner/2/registration/ +- https://docs.gitea.com/runner/2/labels/ +- https://docs.gitea.com/usage/actions/artifacts/ +- https://nodejs.org/dist/latest-v22.x/ + +The local Ubuntu VM is separate from the assistant's Windows workspace. +This kit was prepared there; actual TeX compilation, Linux installation, +service operation and Gitea behavior must be verified in the real environment. diff --git a/docs/ch3-evidence.md b/docs/ch3-evidence.md new file mode 100644 index 0000000..ae801eb --- /dev/null +++ b/docs/ch3-evidence.md @@ -0,0 +1,18 @@ +# Chapter 3 evidence worksheet + +Prepared 2026-10-09. This table is deliberately unfilled. Record real results. + +| Date/time | Branch | Full commit | Run URL and number | Expected | Actual | PDF visible ID | Artifact/download proof | +|---|---|---|---|---|---|---|---| +| Pending | chapter3-build-test | Pending | Pending | Success 1 | Pending | Pending | Pending | +| Pending | chapter3-build-test | Pending | Pending | Success 2 | Pending | Pending | Pending | +| Pending | chapter3-build-test | Pending | Pending | Controlled TeX failure | Pending | No new successful PDF | Pending | +| Pending | chapter3-build-test | Pending | Pending | Repair success | Pending | Pending | Pending | + +Also retain: runner online/assigned job, nonsecret config, package versions, +actual retention policy, resource measurements, service restart test, +permissions review, PDF visual review, review/merge links and final artifact. + +User reported the original source compiled locally on Ubuntu with latexmk +4.76, pdfTeX 1.40.22, Pygments 2.11.2 and makeglossaries 4.49. +That is not proof of this new script or any Gitea execution. diff --git a/latex-manual/devopsAssignment.tex b/latex-manual/devopsAssignment.tex index 4c9e2d4..c283b27 100644 --- a/latex-manual/devopsAssignment.tex +++ b/latex-manual/devopsAssignment.tex @@ -41,7 +41,14 @@ % Replace these values for each assignment. \newcommand{\AssignmentTitle}{Domain Names, SSL, and Versioning} \newcommand{\AssignmentNumber}{\#4} -\newcommand{\DocumentVersion}{1.8} +\newcommand{\DocumentVersion}{1.9-draft} + +% Generated only in the disposable build workspace; never committed. +\newcommand{\BuildRevision}{unrecorded} +\newcommand{\BuildRun}{local} +\newcommand{\BuildUTC}{unrecorded} +\InputIfFileExists{build-metadata.tex}{}{} + \newcommand{\DocumentStatus}{Draft} \newcommand{\CourseNumber}{SSW 590} \newcommand{\CourseName}{DevOps} @@ -97,6 +104,16 @@ \pagenumbering{roman} \singlespacing \include{prologue} +\clearpage +\section*{Build identification} +\noindent Manual version: \DocumentVersion\par +\noindent Build identifier: \texttt{\DocumentVersion+build.\BuildRun.\BuildRevision}\par +\noindent Source revision: \texttt{\BuildRevision}\par +\noindent Workflow run: \texttt{\BuildRun}\par +\noindent Built: \BuildUTC\par +\noindent A run marked local or a revision marked dirty is a local test, +not evidence of a successful Gitea Actions run.\par +\clearpage \setcounter{page}{1} \pagenumbering{arabic} @@ -119,6 +136,7 @@ \include{devopsLaTeXDocker} \include{devopsProjectProposal} \include{devopsGitea} +\include{devopsAutomatedManualBuild} diff --git a/latex-manual/devopsAutomatedManualBuild.tex b/latex-manual/devopsAutomatedManualBuild.tex new file mode 100644 index 0000000..08af7ea --- /dev/null +++ b/latex-manual/devopsAutomatedManualBuild.tex @@ -0,0 +1,104 @@ +\chapter{Automated Manual Build} +\ChapterLabel{AutomatedManualBuild} +\index{Gitea Actions}\index{runner}\index{build artifact} +\begin{devopsNote}[Draft: verification incomplete] +This chapter addresses course assignment Chapter 3. Its chapter number in +this living manual may differ. Vincent reported a successful local build +of the original manual in an Ubuntu VM on October 9, 2026. The new automated +build script, runner registration, Gitea execution and artifact upload require +their own verification. No pending check below is claimed to have passed. +\end{devopsNote} + +\section{Source and trigger} +Source repository: \url{https://git.137-184-97-250.nip.io/stevens-smartpark/smartpark-app}. +Main source: \texttt{latex-manual/devopsAssignment.tex}. +Workflow: \texttt{.gitea/workflows/manual.yml}. Configured push branches are +\texttt{main}, \texttt{chapter3-build-automation} and \texttt{chapter3-build-test}. +HTTPS Git traffic uses public port 443 at the proxy; the handoff reports +private Gitea port 3000. The external VM uses the public HTTPS hostname, +not the Droplet's private container DNS. The runner needs no public inbound +submission port. \textbf{Pending:} source/workflow commit links, actual push +event and run link, verified network diagram and access path. + +\section{Runner setup} +Proposed host: Vincent's Ubuntu 22.04.5 LTS VirtualBox VM, x86\_64, +approximately 4 GB allocated RAM and 25 GB virtual disk. These are +user-reported observations, not a fresh resource measurement. +Proposed repository-scoped runner: Gitea Runner 2.3.0, label +\texttt{smartpark-latex:host}, capacity one, dedicated unprivileged Linux +account. It uses installed tools directly in the VM and does not use Docker. +\textbf{Pending:} final owner/location, installed version, online screenshot, +job assignment, resource measurements, reboot/service test and availability +agreement for grading. Update this section if Nica hosts the runner instead. + +\section{Reproducible compilation} +Run \texttt{python3 ci/build\_manual.py} from a checkout. The script copies +the source into a fresh temporary directory, invokes \texttt{latexmk -pdf} +with error stopping and shell escape, generates glossary and index, and +finishes the PDF. BibTeX is coordinated by latexmk. Shell escape permits +minted to invoke Pygments; source and workflow authors must be trusted. +Output: \texttt{build/manual/SmartPark-Manual.pdf}. +Nonzero tool exit status, missing PDF and unresolved reference/citation +summaries fail the build. A previous deliverable is removed before building. +\textbf{Pending:} actual command output, successful clean-build log, package +versions from \texttt{build-info.txt}, and reproduction by another teammate. + +\section{PDF version traceability} +The build identification page retains the human-maintained document version +and displays the triggering revision and run number. Local runs display +\texttt{local}; modified local working trees display \texttt{dirty}. +The generated metadata exists only in the temporary build directory. +The workflow never commits or pushes generated metadata. +\textbf{Pending:} screenshot of a real Actions PDF and its matching commit +and run. Local identifiers are not Gitea evidence. + +\section{Downloadable artifact} +The workflow requests an artifact named with the run number and commit, +containing the manual PDF and nonsecret build metadata. It requests 30 days +retention. This request is not proof of the server's applied retention policy. +\textbf{Pending:} verified artifact upload compatibility, actual retention, +run/artifact link, download and visual inspection. Artifacts are not backups. + +\section{Change, failure, and repair evidence} +\textbf{Pending:} fill the evidence worksheet in +\texttt{docs/ch3-evidence.md}, then summarize the real results here. +Include two successive source changes producing successful PDFs and a +controlled LaTeX syntax error followed by repair on a workflow-covered +test branch. Record date, expected and actual result, full commit, run URL, +visible PDF identifier and artifact link. A failed compile must not publish +a successful PDF. Do not substitute Chapter 4 Jenkins tests for these runs. + +\section{Runner and secret boundary} +Only reviewed team workflows should reach this runner. No pull-request +event is configured in this draft. Push-only triggers are not complete +access control: restrict who may push or modify workflows, and review other +workflows that can target the runner label. Host jobs share an account and +environment and can access that account's runner credentials; this is not +isolation between jobs. Use a dedicated VM and unprivileged service account, +no Docker group, no passwordless sudo, no personal Windows shared folders +or SSH keys, and no untrusted jobs. Registration credentials stay outside Git. +\textbf{Pending:} actual edit rights, repository scope, credential storage +controls and nonsecret configuration links. + +\section{Manual quality and controls} +This is a draft addition, not a completed assignment submission. The draft +history entry identifies the new chapter; existing Hosts and Passwords +tables have not been changed by the installer and require review before +submission. Add the actual runner host, owner, role, outbound access and +availability; document credential ownership and storage hints only. +\textbf{Pending:} table updates, final version/title/date, glossary terms, +citations, dated figures, run hyperlinks, AI assistance review and removal +of every completed placeholder. Preserve truthful notes about any failures. + +Troubleshooting: for a queued job check online status and label; for checkout +failure check DNS, HTTPS and repository permissions; for TeX failure inspect +the first compiler error; for upload failure inspect the artifact step and +server/action compatibility. A successful compiler run alone does not prove +artifact upload. The operator checks the runner service, corrects the cause, +and pushes a source correction to produce a new traceable run. + +References: \url{https://docs.gitea.com/runner/2/}, +\url{https://docs.gitea.com/runner/2/labels/}, +\url{https://docs.gitea.com/usage/actions/artifacts/}. +Replace or supplement these links with the manual's normal bibliography +entries during editorial review. diff --git a/latex-manual/devopsDocumentHistory.tex b/latex-manual/devopsDocumentHistory.tex index e07af6d..278f779 100644 --- a/latex-manual/devopsDocumentHistory.tex +++ b/latex-manual/devopsDocumentHistory.tex @@ -22,6 +22,14 @@ link each entry to the changed chapter, table, figure, or controlled artifact. \bottomrule \endlastfoot +October 9, 2026 / 1.9-draft & CDX; VP review pending & +Prepared host-mode manual build automation, generated build identification +and an eight-section Automated Manual Build draft. Execution and Gitea +evidence remain pending. Existing Hosts and Passwords tables are unchanged; +runner entries and credential hints still require review. & +\ChapterRef{AutomatedManualBuild}\\ + + September 30, 2026 / 1.8 & NS, VP, CDX & Merged the team's supplied Gitea Sections 6.1--6.4 with the documented Sections 6.5--6.8. Preserved the reported Student Pack approval and pending