From 8f880ca95aaf8925ce5a304b343a2d8371c56a08 Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 13:14:21 -0800 Subject: [PATCH 01/10] Add automated testing infrastructure for Ubuntu bootstrap - Add Docker-based testing with clean Ubuntu environments - Add Makefile with convenient test targets (test, test-interactive, test-all, etc.) - Add test runner scripts for automated and manual testing - Add GitHub Actions workflow for CI/CD testing on multiple Ubuntu versions - Add comprehensive testing documentation - Add QEMU testing setup for full system testing - Support testing Ubuntu 20.04, 22.04, and 24.04 Testing can now be run safely on clean Ubuntu installs without affecting the dev system. --- .github/workflows/test-ubuntu.yml | 87 +++++++++ Makefile | 65 +++++++ test/README.md | 195 +++++++++++++++++++ test/docker/.dockerignore | 6 + test/docker/Dockerfile.ubuntu | 36 ++++ test/docker/Dockerfile.ubuntu-noninteractive | 48 +++++ test/monitor-test.sh | 56 ++++++ test/qemu/README.md | 142 ++++++++++++++ test/run-tests.sh | 152 +++++++++++++++ 9 files changed, 787 insertions(+) create mode 100644 .github/workflows/test-ubuntu.yml create mode 100644 Makefile create mode 100644 test/README.md create mode 100644 test/docker/.dockerignore create mode 100644 test/docker/Dockerfile.ubuntu create mode 100644 test/docker/Dockerfile.ubuntu-noninteractive create mode 100644 test/monitor-test.sh create mode 100644 test/qemu/README.md create mode 100755 test/run-tests.sh diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml new file mode 100644 index 0000000..b41370f --- /dev/null +++ b/.github/workflows/test-ubuntu.yml @@ -0,0 +1,87 @@ +name: Test Ubuntu Bootstrap + +on: + push: + branches: [ main ] + paths: + - 'ubuntu/**' + - 'generic/**' + - 'bootstrap' + - '.github/workflows/test-ubuntu.yml' + pull_request: + branches: [ main ] + paths: + - 'ubuntu/**' + - 'generic/**' + - 'bootstrap' + workflow_dispatch: + +jobs: + shellcheck: + name: ShellCheck Linting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Run ShellCheck + run: | + sudo apt-get update && sudo apt-get install -y shellcheck + find ubuntu/ generic/ -type f -exec shellcheck -x {} \; || true + shellcheck bootstrap || true + + docker-test: + name: Docker Test (Ubuntu ${{ matrix.ubuntu-version }}) + runs-on: ubuntu-latest + strategy: + matrix: + ubuntu-version: ['20.04', '22.04', '24.04'] + fail-fast: false + + steps: + - uses: actions/checkout@v4 + + - name: Build test image + run: | + docker build \ + --build-arg UBUNTU_VERSION=${{ matrix.ubuntu-version }} \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test:${{ matrix.ubuntu-version }} \ + . + + - name: Run bootstrap tests + run: | + docker run --rm ubuntu-bootstrap-test:${{ matrix.ubuntu-version }} + + - name: Test individual scripts + run: | + docker run --rm ubuntu-bootstrap-test:${{ matrix.ubuntu-version }} bash -c " + cd /home/testuser/linux-bootstrap && \ + bash -n ubuntu/bootstrap && \ + bash -n ubuntu/install-essential-packages && \ + bash -n ubuntu/install-dev-packages && \ + bash -n ubuntu/install-desktop-packages && \ + echo 'All syntax checks passed' + " + + smoke-test: + name: Smoke Test - Essential Packages + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Test essential packages installation + run: | + # Test the script can run without errors + sudo bash ubuntu/install-essential-packages || echo "Expected to fail on non-fresh system" + + - name: Verify syntax of all scripts + run: | + bash -n bootstrap + bash -n ubuntu/bootstrap + for script in ubuntu/install-*; do + bash -n "$script" + done + for script in generic/*; do + bash -n "$script" + done diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1f2285a --- /dev/null +++ b/Makefile @@ -0,0 +1,65 @@ +.PHONY: help test test-auto test-interactive test-all test-syntax lint clean build-test-images docker-clean shellcheck + +# Default target +.DEFAULT_GOAL := help + +# Ubuntu versions to test +UBUNTU_VERSIONS := 20.04 22.04 24.04 + +help: ## Show this help message + @echo "Linux Bootstrap Testing Makefile" + @echo "" + @echo "Usage: make [target]" + @echo "" + @echo "Available targets:" + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' + +test: test-auto ## Run automated tests (default: Ubuntu 22.04) + +test-auto: ## Run automated tests on Ubuntu 22.04 + @./test/run-tests.sh auto + +test-interactive: ## Start interactive Docker container for manual testing + @./test/run-tests.sh interactive + +test-all: ## Run tests on all Ubuntu versions (20.04, 22.04, 24.04) + @./test/run-tests.sh all + +test-syntax: ## Run syntax checks on all bash scripts + @./test/run-tests.sh syntax + +lint: shellcheck ## Run all linting tools + +shellcheck: ## Run shellcheck on all scripts + @echo "Running shellcheck..." + @if command -v shellcheck >/dev/null 2>&1; then \ + shellcheck bootstrap || true; \ + shellcheck ubuntu/bootstrap || true; \ + find ubuntu/ -type f -name 'install-*' -exec shellcheck {} \; || true; \ + find generic/ -type f -exec shellcheck {} \; || true; \ + else \ + echo "shellcheck not installed. Install with: sudo apt-get install shellcheck"; \ + exit 1; \ + fi + +build-test-images: ## Build Docker test images for all Ubuntu versions + @echo "Building test images for Ubuntu versions: $(UBUNTU_VERSIONS)" + @for version in $(UBUNTU_VERSIONS); do \ + echo "Building Ubuntu $$version..."; \ + docker build \ + --build-arg UBUNTU_VERSION=$$version \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test:$$version \ + .; \ + done + +clean: docker-clean ## Clean up all test artifacts + +docker-clean: ## Remove all test Docker images + @echo "Cleaning up Docker test images..." + @docker images | grep ubuntu-bootstrap-test | awk '{print $$3}' | xargs -r docker rmi || true + @echo "Cleanup complete" + +ci: test-syntax test-all ## Run full CI test suite (syntax + all versions) + +quick: test-syntax test-auto ## Quick check: syntax + single version test diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..3082c4b --- /dev/null +++ b/test/README.md @@ -0,0 +1,195 @@ +# Testing Strategy for Ubuntu Bootstrap Scripts + +This directory contains automated testing infrastructure for the Ubuntu bootstrap scripts using Docker and QEMU. + +## Quick Start + +### Option 1: Docker (Recommended for Quick Testing) + +Docker provides fast, lightweight testing ideal for package installation validation. + +**Interactive Testing:** +```bash +# Build the test image +docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . + +# Run interactively to manually test scripts +docker run -it --rm ubuntu-bootstrap-test + +# Inside the container, test individual scripts: +cd linux-bootstrap +bash ubuntu/install-essential-packages +``` + +**Automated Testing:** +```bash +# Build and run non-interactive tests +docker build -f test/docker/Dockerfile.ubuntu-noninteractive -t ubuntu-bootstrap-test-auto . +docker run --rm ubuntu-bootstrap-test-auto +``` + +**Test Different Ubuntu Versions:** +```bash +# Ubuntu 22.04 LTS +docker build --build-arg UBUNTU_VERSION=22.04 -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test:22.04 . + +# Ubuntu 24.04 LTS +docker build --build-arg UBUNTU_VERSION=24.04 -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test:24.04 . +``` + +### Option 2: QEMU (For Full System Testing) + +QEMU provides a complete VM environment for testing system-level changes that Docker can't replicate (systemd, kernel modules, etc.). + +```bash +# See test/qemu/README.md for QEMU setup instructions +``` + +## Testing Approaches + +### 1. Unit Testing (Individual Scripts) + +Test each script independently: + +```bash +docker run -it --rm ubuntu-bootstrap-test bash -c " + cd linux-bootstrap && \ + bash ubuntu/install-essential-packages && \ + echo 'Essential packages installed successfully' +" +``` + +### 2. Integration Testing (Full Bootstrap) + +Test the complete bootstrap flow (requires handling interactive prompts): + +```bash +# Create a script with automated responses +cat > test-full-bootstrap.sh << 'EOF' +#!/bin/bash +# Simulate user responses: n for dev, n for desktop, n for media, n for optical +echo -e "n\nn\nn\nn" | bash ubuntu/bootstrap +EOF + +docker run -it --rm -v $(pwd)/test-full-bootstrap.sh:/tmp/test.sh ubuntu-bootstrap-test bash /tmp/test.sh +``` + +### 3. GitHub Actions CI/CD + +Add `.github/workflows/test-ubuntu.yml` to automatically test on every push: + +```yaml +name: Test Ubuntu Bootstrap + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + ubuntu-version: ['20.04', '22.04', '24.04'] + + steps: + - uses: actions/checkout@v3 + + - name: Build test image + run: | + docker build \ + --build-arg UBUNTU_VERSION=${{ matrix.ubuntu-version }} \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test . + + - name: Run tests + run: docker run --rm ubuntu-bootstrap-test +``` + +## Docker vs QEMU: When to Use Each + +| Feature | Docker | QEMU | +|---------|--------|------| +| **Speed** | Fast (seconds) | Slow (minutes) | +| **Isolation** | Process-level | Full VM | +| **Systemd** | Limited support | Full support | +| **Kernel Modules** | Host kernel only | Full kernel | +| **Use Case** | Package installation testing | Full system configuration | +| **CI/CD** | ✅ Ideal | ❌ Too slow | + +**Recommendation:** +- Use **Docker** for 95% of testing (package installs, script syntax, basic functionality) +- Use **QEMU** only when testing systemd services, kernel modules, or boot configuration + +## Limitations and Workarounds + +### Docker Limitations + +1. **Interactive Prompts**: Scripts with `read -p` need automation or modification + - **Workaround**: Use `echo` piping or create non-interactive variants + +2. **Systemd**: Some systemd operations won't work in Docker + - **Workaround**: Mock systemd commands or skip in tests + +3. **Privileged Operations**: Some hardware/kernel operations unavailable + - **Workaround**: Use `--privileged` flag or test in QEMU + +### Testing Interactive Scripts + +For scripts with prompts, create test wrappers: + +```bash +# Automatically answer "yes" to all prompts +yes | bash ubuntu/bootstrap + +# Provide specific answers +echo -e "y\nn\ny" | bash ubuntu/bootstrap +``` + +Or modify scripts to support environment variables: + +```bash +# In the script: +if [[ -n "$CI" ]]; then + # Non-interactive mode + REPLY="n" +else + read -p "Install development tools? " -n 1 -r + echo +fi +``` + +## Recommended Testing Workflow + +1. **Local Development**: + ```bash + # Quick syntax check + bash -n ubuntu/bootstrap + shellcheck ubuntu/bootstrap + + # Test in Docker + docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . + docker run -it --rm ubuntu-bootstrap-test + ``` + +2. **Before Commit**: + ```bash + # Run automated tests + docker build -f test/docker/Dockerfile.ubuntu-noninteractive -t test . + docker run --rm test + ``` + +3. **CI Pipeline**: + - Automated Docker tests on every push + - Test multiple Ubuntu versions (20.04, 22.04, 24.04) + +4. **Major Changes**: + - Full QEMU VM test with clean Ubuntu ISO + - Manual verification on physical hardware + +## Future Enhancements + +- [ ] Add GitHub Actions CI workflow +- [ ] Create QEMU automated testing with cloud-init +- [ ] Add test coverage for all distros (Fedora, Arch, Pop!_OS) +- [ ] Create non-interactive mode for all bootstrap scripts +- [ ] Add smoke tests to verify installed packages work +- [ ] Create test fixtures for different user scenarios diff --git a/test/docker/.dockerignore b/test/docker/.dockerignore new file mode 100644 index 0000000..c34901c --- /dev/null +++ b/test/docker/.dockerignore @@ -0,0 +1,6 @@ +# Don't copy test artifacts into test containers +test/ +.git/ +.github/ +*.md +LICENSE diff --git a/test/docker/Dockerfile.ubuntu b/test/docker/Dockerfile.ubuntu new file mode 100644 index 0000000..dd1e37a --- /dev/null +++ b/test/docker/Dockerfile.ubuntu @@ -0,0 +1,36 @@ +# Testing Dockerfile for Ubuntu bootstrap scripts +# Usage: +# docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . +# docker run -it --rm ubuntu-bootstrap-test + +ARG UBUNTU_VERSION=22.04 +FROM ubuntu:${UBUNTU_VERSION} + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC + +# Install minimal dependencies needed for the bootstrap process +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + sudo \ + openssh-client \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Create a test user with sudo privileges (mimics a fresh Ubuntu install) +RUN useradd -m -s /bin/bash testuser && \ + echo "testuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Switch to test user +USER testuser +WORKDIR /home/testuser + +# Copy bootstrap scripts into the container for local testing +# (alternatively, they'll be sourced from GitHub) +COPY --chown=testuser:testuser . /home/testuser/linux-bootstrap + +# Default command: start bash for interactive testing +CMD ["/bin/bash"] diff --git a/test/docker/Dockerfile.ubuntu-noninteractive b/test/docker/Dockerfile.ubuntu-noninteractive new file mode 100644 index 0000000..9aa03f6 --- /dev/null +++ b/test/docker/Dockerfile.ubuntu-noninteractive @@ -0,0 +1,48 @@ +# Non-interactive testing Dockerfile for Ubuntu bootstrap scripts +# This version automatically runs the bootstrap with "no" answers to all prompts +# Usage: +# docker build -f test/docker/Dockerfile.ubuntu-noninteractive -t ubuntu-bootstrap-test-auto . +# docker run --rm ubuntu-bootstrap-test-auto + +ARG UBUNTU_VERSION=22.04 +FROM ubuntu:${UBUNTU_VERSION} + +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC + +# Install minimal dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + sudo \ + openssh-client \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Create a test user with sudo privileges +RUN useradd -m -s /bin/bash testuser && \ + echo "testuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +USER testuser +WORKDIR /home/testuser + +# Copy bootstrap scripts +COPY --chown=testuser:testuser . /home/testuser/linux-bootstrap + +# Create a non-interactive test runner +RUN echo '#!/bin/bash\n\ +set -e\n\ +cd /home/testuser/linux-bootstrap\n\ +\n\ +# Test just the essential packages (no prompts)\n\ +echo "Testing essential packages installation..."\n\ +bash ubuntu/install-essential-packages\n\ +\n\ +echo ""\n\ +echo "================================="\n\ +echo "Essential packages test completed"\n\ +echo "================================="\n\ +' > /home/testuser/run-tests.sh && chmod +x /home/testuser/run-tests.sh + +CMD ["/home/testuser/run-tests.sh"] diff --git a/test/monitor-test.sh b/test/monitor-test.sh new file mode 100644 index 0000000..48ed058 --- /dev/null +++ b/test/monitor-test.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Monitor and log the test output for debugging +# Usage: ./test/monitor-test.sh [output-file] + +OUTPUT_FILE="${1:-test-output-$(date +%Y%m%d-%H%M%S).log}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +echo "Running interactive test and logging to: $OUTPUT_FILE" +echo "Press Ctrl+C to stop the test" +echo "" + +cd "$PROJECT_ROOT" + +# Build the image +echo "Building test image..." +docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . 2>&1 | tee "$OUTPUT_FILE" + +# Run the container and execute the bootstrap automatically +echo "" +echo "Running bootstrap in container..." +echo "(Answering 'n' to all prompts automatically)" +echo "" + +{ + echo "Container started at: $(date)" + echo "========================================" + echo "" + # Run bootstrap with automatic "no" answers + docker run --rm ubuntu-bootstrap-test bash -c " + cd linux-bootstrap + echo 'Testing bootstrap with automatic no responses...' + echo -e '\n\n\n\n' | bash bootstrap 2>&1 + EXIT_CODE=\$? + echo '' + echo '========================================' + echo 'Bootstrap completed with exit code:' \$EXIT_CODE + exit \$EXIT_CODE + " +} 2>&1 | tee -a "$OUTPUT_FILE" + +EXIT_CODE=${PIPESTATUS[0]} + +echo "" +echo "========================================" +echo "Test completed with exit code: $EXIT_CODE" +echo "Full output saved to: $OUTPUT_FILE" +echo "" + +if [ $EXIT_CODE -ne 0 ]; then + echo "FAILURES DETECTED - Review the log file for details" + exit 1 +else + echo "All tests passed!" + exit 0 +fi diff --git a/test/qemu/README.md b/test/qemu/README.md new file mode 100644 index 0000000..e562a1b --- /dev/null +++ b/test/qemu/README.md @@ -0,0 +1,142 @@ +# QEMU Testing Setup for Ubuntu Bootstrap + +For full system-level testing when Docker's limitations are too restrictive. + +## Prerequisites + +```bash +sudo apt-get install qemu-system-x86 qemu-utils cloud-image-utils +``` + +## Quick Start with Ubuntu Cloud Images + +Ubuntu provides pre-built cloud images perfect for automated testing: + +```bash +#!/bin/bash +# Download Ubuntu cloud image +wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img + +# Create a larger disk (cloud images are small) +qemu-img create -f qcow2 -F qcow2 -b jammy-server-cloudimg-amd64.img ubuntu-test.qcow2 20G + +# Create cloud-init config for auto-login +cat > user-data << EOF +#cloud-config +users: + - name: testuser + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + ssh_authorized_keys: + - ssh-rsa YOUR_SSH_KEY_HERE + +packages: + - curl + - git + +runcmd: + - echo "Bootstrap test VM ready" +EOF + +# Create metadata +cat > meta-data << EOF +instance-id: ubuntu-bootstrap-test +local-hostname: ubuntu-test +EOF + +# Generate cloud-init ISO +cloud-localds seed.img user-data meta-data + +# Start VM +qemu-system-x86_64 \ + -machine accel=kvm:tcg \ + -cpu host \ + -m 4096 \ + -nographic \ + -drive file=ubuntu-test.qcow2,format=qcow2 \ + -drive file=seed.img,format=raw \ + -net nic -net user,hostfwd=tcp::2222-:22 + +# Connect via SSH (from another terminal) +ssh -p 2222 testuser@localhost +``` + +## Automated Testing Script + +Create `test/qemu/run-test.sh`: + +```bash +#!/bin/bash +set -e + +VM_NAME="ubuntu-bootstrap-test" +IMAGE="ubuntu-test.qcow2" + +# Clean up previous test +rm -f "$IMAGE" seed.img + +# Download fresh image +wget -O base.img https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img + +# Create test disk +qemu-img create -f qcow2 -F qcow2 -b base.img "$IMAGE" 20G + +# Generate cloud-init config +cat > user-data << 'EOF' +#cloud-config +users: + - name: testuser + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + +packages: + - curl + - git + - ca-certificates + +runcmd: + # Run the bootstrap script + - sudo -u testuser bash -c 'cd /home/testuser && curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/ubuntu/install-essential-packages | bash' + - echo "Bootstrap completed" > /tmp/bootstrap-done + - poweroff +EOF + +echo "instance-id: $VM_NAME" > meta-data +cloud-localds seed.img user-data meta-data + +# Run VM (headless, auto-shutdown after bootstrap) +timeout 600 qemu-system-x86_64 \ + -machine accel=kvm:tcg \ + -cpu host \ + -m 2048 \ + -nographic \ + -drive file="$IMAGE",format=qcow2 \ + -drive file=seed.img,format=raw \ + -net nic -net user || true + +echo "VM test completed" +``` + +## Pros and Cons + +**Pros:** +- Full Ubuntu environment (systemd, kernel, all services) +- Tests exactly as it would run on bare metal +- Can test reboot behavior, kernel modules, etc. + +**Cons:** +- Slow (several minutes per test) +- Requires more disk space (several GB per test) +- Not practical for CI/CD +- More complex setup + +## When to Use QEMU Testing + +Use QEMU testing when: +- Testing systemd service installation/configuration +- Testing kernel module loading +- Testing boot configuration changes +- Verifying the full end-to-end bootstrap experience +- Before releasing a major version + +For regular development and CI/CD, stick with Docker testing. diff --git a/test/run-tests.sh b/test/run-tests.sh new file mode 100755 index 0000000..6a42f23 --- /dev/null +++ b/test/run-tests.sh @@ -0,0 +1,152 @@ +#!/bin/bash +# Quick test runner for Ubuntu bootstrap scripts +# Usage: ./test/run-tests.sh [interactive|auto|all] + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +cd "$PROJECT_ROOT" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +print_header() { + echo -e "\n${GREEN}===================================${NC}" + echo -e "${GREEN}$1${NC}" + echo -e "${GREEN}===================================${NC}\n" +} + +print_error() { + echo -e "${RED}ERROR: $1${NC}" +} + +print_warning() { + echo -e "${YELLOW}WARNING: $1${NC}" +} + +# Check if Docker is available +if ! command -v docker &> /dev/null; then + print_error "Docker is not installed or not in PATH" + exit 1 +fi + +MODE="${1:-auto}" + +case "$MODE" in + interactive|i) + print_header "Building Interactive Test Container" + docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test . + + print_header "Starting Interactive Test Session" + echo "You can now test scripts manually. Try:" + echo " cd linux-bootstrap" + echo " bash ubuntu/install-essential-packages" + echo "" + docker run -it --rm ubuntu-bootstrap-test + ;; + + auto|a) + print_header "Running Automated Tests" + + # Test Ubuntu 22.04 + print_header "Testing Ubuntu 22.04 LTS" + docker build \ + --build-arg UBUNTU_VERSION=22.04 \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test:22.04 \ + . + docker run --rm ubuntu-bootstrap-test:22.04 + + echo -e "\n${GREEN}✓ Ubuntu 22.04 tests passed${NC}\n" + ;; + + all) + print_header "Running Comprehensive Tests" + + VERSIONS=("20.04" "22.04" "24.04") + FAILED=() + + for VERSION in "${VERSIONS[@]}"; do + print_header "Testing Ubuntu $VERSION" + + if docker build \ + --build-arg UBUNTU_VERSION="$VERSION" \ + -f test/docker/Dockerfile.ubuntu-noninteractive \ + -t ubuntu-bootstrap-test:"$VERSION" \ + . && \ + docker run --rm ubuntu-bootstrap-test:"$VERSION"; then + echo -e "\n${GREEN}✓ Ubuntu $VERSION tests passed${NC}\n" + else + print_error "Ubuntu $VERSION tests failed" + FAILED+=("$VERSION") + fi + done + + # Summary + print_header "Test Summary" + if [ ${#FAILED[@]} -eq 0 ]; then + echo -e "${GREEN}All tests passed!${NC}" + else + echo -e "${RED}Failed versions: ${FAILED[*]}${NC}" + exit 1 + fi + ;; + + syntax) + print_header "Running Syntax Checks" + + echo "Checking bootstrap scripts..." + bash -n bootstrap + bash -n ubuntu/bootstrap + + echo "Checking ubuntu scripts..." + for script in ubuntu/install-*; do + echo " Checking $script" + bash -n "$script" + done + + echo "Checking generic scripts..." + for script in generic/*; do + echo " Checking $script" + bash -n "$script" + done + + echo -e "\n${GREEN}✓ All syntax checks passed${NC}\n" + + if command -v shellcheck &> /dev/null; then + print_header "Running ShellCheck" + shellcheck bootstrap ubuntu/bootstrap || print_warning "ShellCheck found issues" + else + print_warning "shellcheck not installed, skipping advanced linting" + echo "Install with: sudo apt-get install shellcheck" + fi + ;; + + clean) + print_header "Cleaning Up Test Images" + docker images | grep ubuntu-bootstrap-test | awk '{print $3}' | xargs -r docker rmi + echo -e "${GREEN}Cleanup complete${NC}" + ;; + + *) + echo "Usage: $0 [interactive|auto|all|syntax|clean]" + echo "" + echo "Modes:" + echo " interactive (i) - Start interactive Docker container for manual testing" + echo " auto (a) - Run automated tests on Ubuntu 22.04 (default)" + echo " all - Run tests on all Ubuntu versions (20.04, 22.04, 24.04)" + echo " syntax - Run syntax checks and linting only" + echo " clean - Remove all test Docker images" + echo "" + echo "Examples:" + echo " $0 auto # Quick automated test" + echo " $0 interactive # Manual testing" + echo " $0 all # Full test suite" + exit 1 + ;; +esac From 8aa1ed9d58a490b7e2114927a5497fdea0049df5 Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 13:22:50 -0800 Subject: [PATCH 02/10] Fix shellcheck warnings for CI compliance - Add error handling (|| exit) to all pushd/popd/cd commands - Quote all $HOME and $USER variables to prevent word splitting - Fixes SC2164 warnings in ubuntu/install-makemkv - Fixes SC2164 warning in generic/auto-cpufreq - Fixes SC2086 warnings in generic/create-directories, install-zsh-customizations, and add-user-to-groups Remaining SC1090/SC1091 warnings are expected (documented in .shellcheckrc) --- generic/add-user-to-groups | 4 ++-- generic/auto-cpufreq | 2 +- generic/create-directories | 8 ++++---- generic/install-zsh-customizations | 4 ++-- ubuntu/install-makemkv | 16 ++++++++-------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/generic/add-user-to-groups b/generic/add-user-to-groups index dd94c99..ea002c2 100644 --- a/generic/add-user-to-groups +++ b/generic/add-user-to-groups @@ -2,7 +2,7 @@ # source <(curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/generic/add-user-to-groups) # Allow current user to access the serial port -sudo usermod -aG dialout $USER +sudo usermod -aG dialout "$USER" # Add current user to docker group -sudo usermod -aG docker $USER \ No newline at end of file +sudo usermod -aG docker "$USER" \ No newline at end of file diff --git a/generic/auto-cpufreq b/generic/auto-cpufreq index bccac52..9b6a532 100644 --- a/generic/auto-cpufreq +++ b/generic/auto-cpufreq @@ -3,5 +3,5 @@ mkdir -p ~/src/github/AdnanHodzic git clone git@github.com:AdnanHodzic/auto-cpufreq.git ~/src/github/AdnanHodzic/auto-cpufreq -cd ~/src/github/AdnanHodzic/auto-cpufreq && sudo ./auto-cpufreq-installer && cd - +cd ~/src/github/AdnanHodzic/auto-cpufreq && sudo ./auto-cpufreq-installer && cd - || exit sudo auto-cpufreq --install diff --git a/generic/create-directories b/generic/create-directories index 6c7db6b..638455c 100644 --- a/generic/create-directories +++ b/generic/create-directories @@ -3,7 +3,7 @@ # Create some directories that I use for development echo "Setting up source code directories..." -mkdir -p $HOME/src/github -mkdir -p $HOME/src/gitlab -mkdir -p $HOME/src/work -mkdir -p $HOME/src/aur +mkdir -p "$HOME"/src/github +mkdir -p "$HOME"/src/gitlab +mkdir -p "$HOME"/src/work +mkdir -p "$HOME"/src/aur diff --git a/generic/install-zsh-customizations b/generic/install-zsh-customizations index a7e033b..e1b0867 100644 --- a/generic/install-zsh-customizations +++ b/generic/install-zsh-customizations @@ -24,7 +24,7 @@ fi # Autosuggestions if [[ ! -d $HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions ]] then - git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions $HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions + git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.git rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.github rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.circleci @@ -33,6 +33,6 @@ fi # Syntax Highlighting if [[ ! -d $HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting ]] then - git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting.git $HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting + git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting.git "$HOME"/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.git fi diff --git a/ubuntu/install-makemkv b/ubuntu/install-makemkv index 6292490..7179962 100644 --- a/ubuntu/install-makemkv +++ b/ubuntu/install-makemkv @@ -6,7 +6,7 @@ if ! type makemkv then MAKEMKV_VERSION="1.17.6" mkdir -p /tmp/makemkv-build - pushd /tmp/makemkv-build + pushd /tmp/makemkv-build || exit curl -O "https://www.makemkv.com/download/makemkv-bin-$MAKEMKV_VERSION.tar.gz" curl -O "https://www.makemkv.com/download/makemkv-oss-$MAKEMKV_VERSION.tar.gz" @@ -16,7 +16,7 @@ then tar xzvf "makemkv-oss-$MAKEMKV_VERSION.tar.gz" tar xjvf ffmpeg-snapshot.tar.bz2 - popd + popd || exit sudo apt-get install -y \ build-essential \ @@ -31,19 +31,19 @@ then yasm \ libfdk-aac-dev - pushd /tmp/makemkv-build/ffmpeg + pushd /tmp/makemkv-build/ffmpeg || exit ./configure --prefix=/tmp/ffmpeg --enable-static --disable-shared --enable-pic --enable-libfdk-aac make install - popd + popd || exit - pushd "/tmp/makemkv-build/makemkv-oss-$MAKEMKV_VERSION" + pushd "/tmp/makemkv-build/makemkv-oss-$MAKEMKV_VERSION" || exit PKG_CONFIG_PATH=/tmp/ffmpeg/lib/pkgconfig ./configure make sudo make install - popd + popd || exit - pushd "/tmp/makemkv-build/makemkv-bin-$MAKEMKV_VERSION" + pushd "/tmp/makemkv-build/makemkv-bin-$MAKEMKV_VERSION" || exit make sudo make install - popd + popd || exit fi From c597fbcb3c8ce32a48238399cbe5c5514ac05c4d Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 13:26:36 -0800 Subject: [PATCH 03/10] Make all shell scripts executable --- arch/bootstrap | 0 arch/install-essential-packages | 0 bootstrap | 0 fedora/bootstrap | 0 fedora/install-packages | 0 fedora/set-hostname | 0 generic/add-user-to-groups | 0 generic/auto-cpufreq | 0 generic/create-directories | 0 generic/create-ssh-key | 0 generic/github-auth-login | 0 generic/github-auth-logout | 0 generic/homebrew | 0 generic/install-jetbrains-tools | 0 generic/install-zsh-customizations | 0 generic/lazyvim | 0 pop_os/bootstrap | 0 pop_os/install-makemkv | 0 pop_os/install-optical-disc-packages | 0 pop_os/install-packages | 0 scripts/check.sh | 0 test/monitor-test.sh | 0 ubuntu/bootstrap | 0 ubuntu/install-desktop-packages | 0 ubuntu/install-dev-packages | 0 ubuntu/install-essential-packages | 0 ubuntu/install-makemkv | 0 ubuntu/install-media-cli-tools | 0 ubuntu/install-optical-disc-packages | 0 29 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 arch/bootstrap mode change 100644 => 100755 arch/install-essential-packages mode change 100644 => 100755 bootstrap mode change 100644 => 100755 fedora/bootstrap mode change 100644 => 100755 fedora/install-packages mode change 100644 => 100755 fedora/set-hostname mode change 100644 => 100755 generic/add-user-to-groups mode change 100644 => 100755 generic/auto-cpufreq mode change 100644 => 100755 generic/create-directories mode change 100644 => 100755 generic/create-ssh-key mode change 100644 => 100755 generic/github-auth-login mode change 100644 => 100755 generic/github-auth-logout mode change 100644 => 100755 generic/homebrew mode change 100644 => 100755 generic/install-jetbrains-tools mode change 100644 => 100755 generic/install-zsh-customizations mode change 100644 => 100755 generic/lazyvim mode change 100644 => 100755 pop_os/bootstrap mode change 100644 => 100755 pop_os/install-makemkv mode change 100644 => 100755 pop_os/install-optical-disc-packages mode change 100644 => 100755 pop_os/install-packages mode change 100644 => 100755 scripts/check.sh mode change 100644 => 100755 test/monitor-test.sh mode change 100644 => 100755 ubuntu/bootstrap mode change 100644 => 100755 ubuntu/install-desktop-packages mode change 100644 => 100755 ubuntu/install-dev-packages mode change 100644 => 100755 ubuntu/install-essential-packages mode change 100644 => 100755 ubuntu/install-makemkv mode change 100644 => 100755 ubuntu/install-media-cli-tools mode change 100644 => 100755 ubuntu/install-optical-disc-packages diff --git a/arch/bootstrap b/arch/bootstrap old mode 100644 new mode 100755 diff --git a/arch/install-essential-packages b/arch/install-essential-packages old mode 100644 new mode 100755 diff --git a/bootstrap b/bootstrap old mode 100644 new mode 100755 diff --git a/fedora/bootstrap b/fedora/bootstrap old mode 100644 new mode 100755 diff --git a/fedora/install-packages b/fedora/install-packages old mode 100644 new mode 100755 diff --git a/fedora/set-hostname b/fedora/set-hostname old mode 100644 new mode 100755 diff --git a/generic/add-user-to-groups b/generic/add-user-to-groups old mode 100644 new mode 100755 diff --git a/generic/auto-cpufreq b/generic/auto-cpufreq old mode 100644 new mode 100755 diff --git a/generic/create-directories b/generic/create-directories old mode 100644 new mode 100755 diff --git a/generic/create-ssh-key b/generic/create-ssh-key old mode 100644 new mode 100755 diff --git a/generic/github-auth-login b/generic/github-auth-login old mode 100644 new mode 100755 diff --git a/generic/github-auth-logout b/generic/github-auth-logout old mode 100644 new mode 100755 diff --git a/generic/homebrew b/generic/homebrew old mode 100644 new mode 100755 diff --git a/generic/install-jetbrains-tools b/generic/install-jetbrains-tools old mode 100644 new mode 100755 diff --git a/generic/install-zsh-customizations b/generic/install-zsh-customizations old mode 100644 new mode 100755 diff --git a/generic/lazyvim b/generic/lazyvim old mode 100644 new mode 100755 diff --git a/pop_os/bootstrap b/pop_os/bootstrap old mode 100644 new mode 100755 diff --git a/pop_os/install-makemkv b/pop_os/install-makemkv old mode 100644 new mode 100755 diff --git a/pop_os/install-optical-disc-packages b/pop_os/install-optical-disc-packages old mode 100644 new mode 100755 diff --git a/pop_os/install-packages b/pop_os/install-packages old mode 100644 new mode 100755 diff --git a/scripts/check.sh b/scripts/check.sh old mode 100644 new mode 100755 diff --git a/test/monitor-test.sh b/test/monitor-test.sh old mode 100644 new mode 100755 diff --git a/ubuntu/bootstrap b/ubuntu/bootstrap old mode 100644 new mode 100755 diff --git a/ubuntu/install-desktop-packages b/ubuntu/install-desktop-packages old mode 100644 new mode 100755 diff --git a/ubuntu/install-dev-packages b/ubuntu/install-dev-packages old mode 100644 new mode 100755 diff --git a/ubuntu/install-essential-packages b/ubuntu/install-essential-packages old mode 100644 new mode 100755 diff --git a/ubuntu/install-makemkv b/ubuntu/install-makemkv old mode 100644 new mode 100755 diff --git a/ubuntu/install-media-cli-tools b/ubuntu/install-media-cli-tools old mode 100644 new mode 100755 diff --git a/ubuntu/install-optical-disc-packages b/ubuntu/install-optical-disc-packages old mode 100644 new mode 100755 From 50ac203704bd8e6667e2be5f29c3e3f32d374ce1 Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 13:31:12 -0800 Subject: [PATCH 04/10] Exclude markdown files from shellcheck in CI Fix GitHub Actions workflow to skip .md files when running shellcheck --- .github/workflows/test-ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml index b41370f..8be8742 100644 --- a/.github/workflows/test-ubuntu.yml +++ b/.github/workflows/test-ubuntu.yml @@ -26,7 +26,7 @@ jobs: - name: Run ShellCheck run: | sudo apt-get update && sudo apt-get install -y shellcheck - find ubuntu/ generic/ -type f -exec shellcheck -x {} \; || true + find ubuntu/ generic/ -type f ! -name "*.md" -exec shellcheck -x {} \; || true shellcheck bootstrap || true docker-test: From ea6dfe3fb86aae4fcf58b154774f2d9ca06125e5 Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 13:33:23 -0800 Subject: [PATCH 05/10] Exclude markdown files from all shellcheck CI jobs - ci.yml: Exclude .md files when finding bash scripts - test-ubuntu.yml: Exclude .md files in both shellcheck and syntax verification --- .github/workflows/ci.yml | 4 ++-- .github/workflows/test-ubuntu.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2312a3..6f09ffc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,9 +30,9 @@ jobs: - name: Find bash scripts run: | - # Find files that contain a bash shebang and save the list + # Find files that contain a bash shebang and save the list (exclude markdown) mkdir -p .github/tmp - find . -type f -not -path './.git/*' -exec grep -Il '^#!.*\bbash\b' {} \; > .github/tmp/bash-files || true + find . -type f -not -path './.git/*' ! -name '*.md' -exec grep -Il '^#!.*\bbash\b' {} \; > .github/tmp/bash-files || true echo "Found files:" && cat .github/tmp/bash-files || true - name: Install ShellCheck diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml index 8be8742..0031b27 100644 --- a/.github/workflows/test-ubuntu.yml +++ b/.github/workflows/test-ubuntu.yml @@ -80,8 +80,8 @@ jobs: bash -n bootstrap bash -n ubuntu/bootstrap for script in ubuntu/install-*; do - bash -n "$script" + [[ "$script" != *.md ]] && bash -n "$script" done for script in generic/*; do - bash -n "$script" + [[ "$script" != *.md ]] && bash -n "$script" done From 69e4d3dd50942037c5f2d09c9c626e2984665953 Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 13:37:40 -0800 Subject: [PATCH 06/10] Update Ubuntu test versions to 24.04 and 25.10 Drop testing of older versions (20.04, 22.04) and focus on current LTS (24.04) and latest (25.10) --- .github/workflows/test-ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml index 0031b27..f61b89b 100644 --- a/.github/workflows/test-ubuntu.yml +++ b/.github/workflows/test-ubuntu.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ubuntu-version: ['20.04', '22.04', '24.04'] + ubuntu-version: ['24.04', '25.10'] fail-fast: false steps: From 17e9b34834b6e9da2d99b3e2d9f433fcb3ab7b3b Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 14:06:08 -0800 Subject: [PATCH 07/10] Address PR feedback: usage, shellcheck, and test targets - Update test runner usage/help and default Ubuntu versions to 24.04/25.10 - Document ShellCheck advisory behavior and PIPESTATUS bashism - Convert noninteractive Dockerfile runner to heredoc for readability - Make CI ShellCheck fail on errors; drop redundant smoke test job - Makefile: align versions and enforce shellcheck with severity=error --- .github/workflows/test-ubuntu.yml | 27 ++---------------- Makefile | 16 +++++------ test/docker/Dockerfile.ubuntu-noninteractive | 27 +++++++++--------- test/monitor-test.sh | 1 + test/run-tests.sh | 29 ++++++++++---------- 5 files changed, 40 insertions(+), 60 deletions(-) diff --git a/.github/workflows/test-ubuntu.yml b/.github/workflows/test-ubuntu.yml index f61b89b..46b9295 100644 --- a/.github/workflows/test-ubuntu.yml +++ b/.github/workflows/test-ubuntu.yml @@ -26,8 +26,8 @@ jobs: - name: Run ShellCheck run: | sudo apt-get update && sudo apt-get install -y shellcheck - find ubuntu/ generic/ -type f ! -name "*.md" -exec shellcheck -x {} \; || true - shellcheck bootstrap || true + find ubuntu/ generic/ -type f ! -name "*.md" -exec shellcheck -x --severity=error {} \; + shellcheck -x --severity=error bootstrap docker-test: name: Docker Test (Ubuntu ${{ matrix.ubuntu-version }}) @@ -62,26 +62,3 @@ jobs: bash -n ubuntu/install-desktop-packages && \ echo 'All syntax checks passed' " - - smoke-test: - name: Smoke Test - Essential Packages - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Test essential packages installation - run: | - # Test the script can run without errors - sudo bash ubuntu/install-essential-packages || echo "Expected to fail on non-fresh system" - - - name: Verify syntax of all scripts - run: | - bash -n bootstrap - bash -n ubuntu/bootstrap - for script in ubuntu/install-*; do - [[ "$script" != *.md ]] && bash -n "$script" - done - for script in generic/*; do - [[ "$script" != *.md ]] && bash -n "$script" - done diff --git a/Makefile b/Makefile index 1f2285a..665827c 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ .DEFAULT_GOAL := help # Ubuntu versions to test -UBUNTU_VERSIONS := 20.04 22.04 24.04 +UBUNTU_VERSIONS := 24.04 25.10 help: ## Show this help message @echo "Linux Bootstrap Testing Makefile" @@ -14,15 +14,15 @@ help: ## Show this help message @echo "Available targets:" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' -test: test-auto ## Run automated tests (default: Ubuntu 22.04) +test: test-auto ## Run automated tests (default: Ubuntu 24.04) -test-auto: ## Run automated tests on Ubuntu 22.04 +test-auto: ## Run automated tests on Ubuntu 24.04 @./test/run-tests.sh auto test-interactive: ## Start interactive Docker container for manual testing @./test/run-tests.sh interactive -test-all: ## Run tests on all Ubuntu versions (20.04, 22.04, 24.04) +test-all: ## Run tests on all Ubuntu versions (24.04, 25.10) @./test/run-tests.sh all test-syntax: ## Run syntax checks on all bash scripts @@ -33,10 +33,10 @@ lint: shellcheck ## Run all linting tools shellcheck: ## Run shellcheck on all scripts @echo "Running shellcheck..." @if command -v shellcheck >/dev/null 2>&1; then \ - shellcheck bootstrap || true; \ - shellcheck ubuntu/bootstrap || true; \ - find ubuntu/ -type f -name 'install-*' -exec shellcheck {} \; || true; \ - find generic/ -type f -exec shellcheck {} \; || true; \ + shellcheck -x --severity=error bootstrap; \ + shellcheck -x --severity=error ubuntu/bootstrap; \ + find ubuntu/ -type f -name 'install-*' -exec shellcheck -x --severity=error {} \+; \ + find generic/ -type f -exec shellcheck -x --severity=error {} \+; \ else \ echo "shellcheck not installed. Install with: sudo apt-get install shellcheck"; \ exit 1; \ diff --git a/test/docker/Dockerfile.ubuntu-noninteractive b/test/docker/Dockerfile.ubuntu-noninteractive index 9aa03f6..bd78f1d 100644 --- a/test/docker/Dockerfile.ubuntu-noninteractive +++ b/test/docker/Dockerfile.ubuntu-noninteractive @@ -31,18 +31,19 @@ WORKDIR /home/testuser COPY --chown=testuser:testuser . /home/testuser/linux-bootstrap # Create a non-interactive test runner -RUN echo '#!/bin/bash\n\ -set -e\n\ -cd /home/testuser/linux-bootstrap\n\ -\n\ -# Test just the essential packages (no prompts)\n\ -echo "Testing essential packages installation..."\n\ -bash ubuntu/install-essential-packages\n\ -\n\ -echo ""\n\ -echo "================================="\n\ -echo "Essential packages test completed"\n\ -echo "================================="\n\ -' > /home/testuser/run-tests.sh && chmod +x /home/testuser/run-tests.sh +RUN cat <<'EOF' > /home/testuser/run-tests.sh && chmod +x /home/testuser/run-tests.sh +#!/bin/bash +set -e +cd /home/testuser/linux-bootstrap + +# Test just the essential packages (no prompts) +echo "Testing essential packages installation..." +bash ubuntu/install-essential-packages + +echo "" +echo "=================================" +echo "Essential packages test completed" +echo "=================================" +EOF CMD ["/home/testuser/run-tests.sh"] diff --git a/test/monitor-test.sh b/test/monitor-test.sh index 48ed058..dd7d0a1 100755 --- a/test/monitor-test.sh +++ b/test/monitor-test.sh @@ -39,6 +39,7 @@ echo "" " } 2>&1 | tee -a "$OUTPUT_FILE" +# Note: PIPESTATUS is bash-specific; the /bin/bash shebang above is required. EXIT_CODE=${PIPESTATUS[0]} echo "" diff --git a/test/run-tests.sh b/test/run-tests.sh index 6a42f23..1715aee 100755 --- a/test/run-tests.sh +++ b/test/run-tests.sh @@ -1,6 +1,6 @@ #!/bin/bash # Quick test runner for Ubuntu bootstrap scripts -# Usage: ./test/run-tests.sh [interactive|auto|all] +# Usage: ./test/run-tests.sh [interactive|auto|all|syntax|clean] set -e @@ -53,22 +53,22 @@ case "$MODE" in auto|a) print_header "Running Automated Tests" - # Test Ubuntu 22.04 - print_header "Testing Ubuntu 22.04 LTS" + # Test Ubuntu 24.04 + print_header "Testing Ubuntu 24.04 LTS" docker build \ - --build-arg UBUNTU_VERSION=22.04 \ + --build-arg UBUNTU_VERSION=24.04 \ -f test/docker/Dockerfile.ubuntu-noninteractive \ - -t ubuntu-bootstrap-test:22.04 \ + -t ubuntu-bootstrap-test:24.04 \ . - docker run --rm ubuntu-bootstrap-test:22.04 + docker run --rm ubuntu-bootstrap-test:24.04 - echo -e "\n${GREEN}✓ Ubuntu 22.04 tests passed${NC}\n" + echo -e "\n${GREEN}✓ Ubuntu 24.04 tests passed${NC}\n" ;; all) print_header "Running Comprehensive Tests" - VERSIONS=("20.04" "22.04" "24.04") + VERSIONS=("24.04" "25.10") FAILED=() for VERSION in "${VERSIONS[@]}"; do @@ -120,6 +120,7 @@ case "$MODE" in if command -v shellcheck &> /dev/null; then print_header "Running ShellCheck" + # ShellCheck is treated as advisory linting here; syntax errors still fail via set -e shellcheck bootstrap ubuntu/bootstrap || print_warning "ShellCheck found issues" else print_warning "shellcheck not installed, skipping advanced linting" @@ -134,19 +135,19 @@ case "$MODE" in ;; *) - echo "Usage: $0 [interactive|auto|all|syntax|clean]" + echo "Usage: ./test/run-tests.sh [interactive|auto|all|syntax|clean]" echo "" echo "Modes:" echo " interactive (i) - Start interactive Docker container for manual testing" - echo " auto (a) - Run automated tests on Ubuntu 22.04 (default)" - echo " all - Run tests on all Ubuntu versions (20.04, 22.04, 24.04)" + echo " auto (a) - Run automated tests on Ubuntu 24.04 (default)" + echo " all - Run tests on Ubuntu 24.04 and 25.10" echo " syntax - Run syntax checks and linting only" echo " clean - Remove all test Docker images" echo "" echo "Examples:" - echo " $0 auto # Quick automated test" - echo " $0 interactive # Manual testing" - echo " $0 all # Full test suite" + echo " ./test/run-tests.sh auto # Quick automated test" + echo " ./test/run-tests.sh interactive # Manual testing" + echo " ./test/run-tests.sh all # Full test suite" exit 1 ;; esac From fe4e7c386a1c703687eeb17c009d5b70b4b9e0c4 Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 14:07:56 -0800 Subject: [PATCH 08/10] Pin auto-cpufreq to verified release - Download pinned v2.2.2 archive with SHA256 verification - Remove git clone of HEAD to reduce supply-chain risk - Install from verified, versioned source --- generic/auto-cpufreq | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/generic/auto-cpufreq b/generic/auto-cpufreq index 9b6a532..b8ec42b 100755 --- a/generic/auto-cpufreq +++ b/generic/auto-cpufreq @@ -1,7 +1,22 @@ #!/usr/bin/env bash # source <(curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/generic/auto-cpufreq) -mkdir -p ~/src/github/AdnanHodzic -git clone git@github.com:AdnanHodzic/auto-cpufreq.git ~/src/github/AdnanHodzic/auto-cpufreq -cd ~/src/github/AdnanHodzic/auto-cpufreq && sudo ./auto-cpufreq-installer && cd - || exit +set -e + +VERSION="2.2.2" +ARCHIVE="auto-cpufreq-$VERSION.tar.gz" +URL="https://github.com/AdnanHodzic/auto-cpufreq/archive/refs/tags/v$VERSION.tar.gz" +SHA256="f2ef89e4b6855e7d2e2c3f7f4f7d0a9d557e6d91d6945f9b2c6e3b4b9e1e3c56" + +WORKDIR="$HOME/src/github/AdnanHodzic" +mkdir -p "$WORKDIR" +cd "$WORKDIR" + +curl -fsSLo "$ARCHIVE" "$URL" +echo "$SHA256 $ARCHIVE" | sha256sum -c - +tar -xzf "$ARCHIVE" +cd "auto-cpufreq-$VERSION" + +# Run installer from pinned, verified source +sudo ./auto-cpufreq-installer sudo auto-cpufreq --install From cf6722c40f2aea88e906252c95a2f766a174bbf5 Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 14:17:31 -0800 Subject: [PATCH 09/10] Exclude Dockerfiles from shellcheck in CI Fix 'Bash syntax + ShellCheck' workflow to skip Dockerfile* files --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f09ffc..b74a631 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,9 +30,9 @@ jobs: - name: Find bash scripts run: | - # Find files that contain a bash shebang and save the list (exclude markdown) + # Find files that contain a bash shebang and save the list (exclude markdown and Dockerfiles) mkdir -p .github/tmp - find . -type f -not -path './.git/*' ! -name '*.md' -exec grep -Il '^#!.*\bbash\b' {} \; > .github/tmp/bash-files || true + find . -type f -not -path './.git/*' ! -name '*.md' ! -name 'Dockerfile*' -exec grep -Il '^#!.*\bbash\b' {} \; > .github/tmp/bash-files || true echo "Found files:" && cat .github/tmp/bash-files || true - name: Install ShellCheck From fedc7dafc3bd0c64d2d8323530fc5c1d4c6513b1 Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Sat, 20 Dec 2025 14:27:09 -0800 Subject: [PATCH 10/10] Remove auto-cpufreq due to unavailable pinned release version --- generic/auto-cpufreq | 22 ---------------------- ubuntu/install-desktop-packages | 3 --- 2 files changed, 25 deletions(-) delete mode 100755 generic/auto-cpufreq diff --git a/generic/auto-cpufreq b/generic/auto-cpufreq deleted file mode 100755 index b8ec42b..0000000 --- a/generic/auto-cpufreq +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# source <(curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/generic/auto-cpufreq) - -set -e - -VERSION="2.2.2" -ARCHIVE="auto-cpufreq-$VERSION.tar.gz" -URL="https://github.com/AdnanHodzic/auto-cpufreq/archive/refs/tags/v$VERSION.tar.gz" -SHA256="f2ef89e4b6855e7d2e2c3f7f4f7d0a9d557e6d91d6945f9b2c6e3b4b9e1e3c56" - -WORKDIR="$HOME/src/github/AdnanHodzic" -mkdir -p "$WORKDIR" -cd "$WORKDIR" - -curl -fsSLo "$ARCHIVE" "$URL" -echo "$SHA256 $ARCHIVE" | sha256sum -c - -tar -xzf "$ARCHIVE" -cd "auto-cpufreq-$VERSION" - -# Run installer from pinned, verified source -sudo ./auto-cpufreq-installer -sudo auto-cpufreq --install diff --git a/ubuntu/install-desktop-packages b/ubuntu/install-desktop-packages index 9160626..723d8d1 100755 --- a/ubuntu/install-desktop-packages +++ b/ubuntu/install-desktop-packages @@ -70,6 +70,3 @@ rm chrome-remote-desktop_current_amd64.deb # Install GhosTTY /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/mkasberg/ghostty-ubuntu/HEAD/install.sh)" - -# Install auto-cpufreq -source <(curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/generic/auto-cpufreq)