diff --git a/.gitignore b/.gitignore index 2c88040..95ca464 100644 --- a/.gitignore +++ b/.gitignore @@ -70,7 +70,6 @@ scripts/ # Web UI auth database and SSL certs frontends/web/instance/ frontends/web/certs/ -rpi/inject-wifi.sh # RPi image build artifacts *.img diff --git a/PLAN-4.1.2.md b/PLAN-4.1.2.md index ab04ce8..dbdea5b 100644 --- a/PLAN-4.1.2.md +++ b/PLAN-4.1.2.md @@ -249,7 +249,7 @@ Polish and UX improvements after the 4.1.1 stability release. ## 9. Smoke Test Docker Support -**Status:** Planned +**Status:** Done **Problem:** Smoke test expects systemd service, doesn't auto-create admin for Docker. @@ -260,13 +260,18 @@ Polish and UX improvements after the 4.1.1 stability release. - Auto-detect fresh Docker (no users) and create admin via /setup - Add `--docker` flag to skip Pi-specific checks -### Files to Modify +### Implementation +- Added `--docker` flag that sets localhost and skips SSH/systemd checks +- Docker health check verifies container responds with HTTP 200/302 +- Header shows "Docker Smoke Test" in Docker mode + +### Files Modified - `rpi/smoke-test.sh` --- ## Notes -- Keep 4.1.2 focused - 9 features (1 done) +- Keep 4.1.2 focused - 9 features (2 done) - Don't break DCT compatibility (4.1.1 RS format is stable) - Test on Pi before release diff --git a/rpi/inject-wifi.sh b/rpi/inject-wifi.sh new file mode 100755 index 0000000..09489cf --- /dev/null +++ b/rpi/inject-wifi.sh @@ -0,0 +1,200 @@ +#!/bin/bash +# +# Inject WiFi credentials into SD card for Raspberry Pi +# Supports both Bookworm (NetworkManager) and older (wpa_supplicant) +# +# First-time setup: +# ./inject-wifi.sh --setup +# +# Then after flashing: +# sudo ./inject-wifi.sh # auto-detect partitions +# sudo ./inject-wifi.sh /dev/sdb # specify device (finds partitions) +# + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +CONFIG_DIR="$HOME/.config/stegasoo" +CONFIG_FILE="$CONFIG_DIR/wifi.conf" + +# Setup mode - save credentials +if [ "$1" == "--setup" ]; then + echo -e "${BLUE}Stegasoo WiFi Config Setup${NC}" + echo "" + + read -p "WiFi SSID: " WIFI_SSID + read -s -p "WiFi Password: " WIFI_PASS + echo "" + read -p "Country code [US]: " WIFI_COUNTRY + WIFI_COUNTRY=${WIFI_COUNTRY:-US} + + # Generate hashed PSK for wpa_supplicant (legacy) + if command -v wpa_passphrase &> /dev/null; then + HASHED_PSK=$(wpa_passphrase "$WIFI_SSID" "$WIFI_PASS" | grep -E "^\s+psk=" | tr -d '\t' | cut -d= -f2) + else + HASHED_PSK="" + echo -e "${YELLOW}Note: wpa_passphrase not found, legacy mode disabled${NC}" + fi + + # Save config (includes plaintext for NetworkManager) + mkdir -p "$CONFIG_DIR" + chmod 700 "$CONFIG_DIR" + + cat > "$CONFIG_FILE" << EOF +# Stegasoo WiFi config +WIFI_SSID="$WIFI_SSID" +WIFI_PASS="$WIFI_PASS" +WIFI_PSK_HASH="$HASHED_PSK" +WIFI_COUNTRY="$WIFI_COUNTRY" +EOF + chmod 600 "$CONFIG_FILE" + + echo "" + echo -e "${GREEN}Config saved to $CONFIG_FILE${NC}" + exit 0 +fi + +# Normal mode - inject credentials +if [ "$EUID" -ne 0 ]; then + echo -e "${RED}Error: Must run as root (sudo)${NC}" + echo "Usage: sudo $0 [/dev/sdX]" + echo "" + echo "First-time setup (no sudo): $0 --setup" + exit 1 +fi + +# Load config +if [ -n "$SUDO_USER" ]; then + USER_HOME=$(getent passwd "$SUDO_USER" | cut -d: -f6) + CONFIG_FILE="$USER_HOME/.config/stegasoo/wifi.conf" +fi + +if [ ! -f "$CONFIG_FILE" ]; then + echo -e "${RED}Config not found: $CONFIG_FILE${NC}" + echo "" + echo "Run setup first (without sudo):" + echo " ./inject-wifi.sh --setup" + exit 1 +fi + +source "$CONFIG_FILE" + +if [ -z "$WIFI_SSID" ] || [ -z "$WIFI_PASS" ]; then + echo -e "${RED}Invalid config. Run --setup again.${NC}" + exit 1 +fi + +# Find partitions +MANUAL_DEV="$1" + +if [ -n "$MANUAL_DEV" ]; then + # Strip partition number if given (e.g., /dev/sdb1 -> /dev/sdb) + BASE_DEV=$(echo "$MANUAL_DEV" | sed 's/[0-9]*$//') + BOOT_DEV="${BASE_DEV}1" + ROOT_DEV="${BASE_DEV}2" +else + # Auto-detect by label + BOOT_PART=$(lsblk -o NAME,FSTYPE,LABEL -rn | grep -E "vfat.*(bootfs|boot)" | head -1 | awk '{print $1}') + ROOT_PART=$(lsblk -o NAME,FSTYPE,LABEL -rn | grep -E "ext4.*rootfs" | head -1 | awk '{print $1}') + + if [ -z "$BOOT_PART" ] || [ -z "$ROOT_PART" ]; then + echo -e "${RED}Could not find boot/root partitions. Is the SD card inserted?${NC}" + echo "" + lsblk -o NAME,SIZE,FSTYPE,LABEL + echo "" + echo -e "${YELLOW}Tip: Specify device manually: sudo $0 /dev/sdX${NC}" + exit 1 + fi + + BOOT_DEV="/dev/$BOOT_PART" + ROOT_DEV="/dev/$ROOT_PART" +fi + +echo -e "${GREEN}Found partitions:${NC}" +echo -e " Boot: ${YELLOW}$BOOT_DEV${NC}" +echo -e " Root: ${YELLOW}$ROOT_DEV${NC}" + +# Mount points +BOOT_MNT="/tmp/stegasoo-boot-$$" +ROOT_MNT="/tmp/stegasoo-root-$$" + +cleanup() { + umount "$BOOT_MNT" 2>/dev/null || true + umount "$ROOT_MNT" 2>/dev/null || true + rmdir "$BOOT_MNT" "$ROOT_MNT" 2>/dev/null || true +} +trap cleanup EXIT + +mkdir -p "$BOOT_MNT" "$ROOT_MNT" + +# Mount partitions +mount "$BOOT_DEV" "$BOOT_MNT" +mount "$ROOT_DEV" "$ROOT_MNT" + +echo "" + +# 1. Write NetworkManager config (Bookworm+) +NM_DIR="$ROOT_MNT/etc/NetworkManager/system-connections" +if [ -d "$ROOT_MNT/etc/NetworkManager" ]; then + mkdir -p "$NM_DIR" + + # NetworkManager connection file + NM_FILE="$NM_DIR/stegasoo-wifi.nmconnection" + cat > "$NM_FILE" << EOF +[connection] +id=$WIFI_SSID +type=wifi +autoconnect=true + +[wifi] +mode=infrastructure +ssid=$WIFI_SSID + +[wifi-security] +auth-alg=open +key-mgmt=wpa-psk +psk=$WIFI_PASS + +[ipv4] +method=auto + +[ipv6] +method=auto +EOF + chmod 600 "$NM_FILE" + echo -e "${GREEN}Created NetworkManager config (Bookworm)${NC}" +fi + +# 2. Write wpa_supplicant.conf (legacy, boot partition) +if [ -n "$WIFI_PSK_HASH" ]; then + cat > "$BOOT_MNT/wpa_supplicant.conf" << EOF +ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev +update_config=1 +country=$WIFI_COUNTRY + +network={ + ssid="$WIFI_SSID" + psk=$WIFI_PSK_HASH +} +EOF + echo -e "${GREEN}Created wpa_supplicant.conf (legacy)${NC}" +fi + +# 3. Set WiFi country in boot config +if [ -f "$BOOT_MNT/config.txt" ]; then + if ! grep -q "^dtparam=cfg80211" "$BOOT_MNT/config.txt"; then + echo "" >> "$BOOT_MNT/config.txt" + echo "# WiFi country" >> "$BOOT_MNT/config.txt" + echo "dtparam=cfg80211" >> "$BOOT_MNT/config.txt" + fi +fi + +echo -e " SSID: ${YELLOW}$WIFI_SSID${NC}" + +echo "" +echo -e "${GREEN}Done! WiFi credentials injected for Bookworm + legacy.${NC}" diff --git a/rpi/smoke-test.sh b/rpi/smoke-test.sh index 7581521..5993705 100755 --- a/rpi/smoke-test.sh +++ b/rpi/smoke-test.sh @@ -3,11 +3,12 @@ # Stegasoo Pi Image Smoke Test # Automated testing of a fresh Pi image # -# Usage: ./smoke-test.sh [ip] [--https] [--443] [--port=PORT] -# Default IP: 192.168.0.4 +# Usage: ./smoke-test.sh [ip] [--https] [--443] [--port=PORT] [--docker] +# Default IP: 192.168.0.4 (or localhost for --docker) # --https Use HTTPS (port 5000) # --443 Use HTTPS on port 443 # --port=N Specify custom port +# --docker Docker mode: skip systemd/SSH checks, use localhost # set -e @@ -23,6 +24,7 @@ NC='\033[0m' PI_IP="192.168.0.4" HTTPS=false PORT=5000 +DOCKER_MODE=false # Parse arguments for arg in "$@"; do @@ -30,6 +32,7 @@ for arg in "$@"; do --https) HTTPS=true ;; --443) HTTPS=true; PORT=443 ;; --port=*) PORT="${arg#*=}" ;; + --docker) DOCKER_MODE=true; PI_IP="localhost" ;; --*) ;; # Ignore other flags *) # If it looks like an IP, use it @@ -113,10 +116,17 @@ skip() { echo "" echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}" +if [ "$DOCKER_MODE" = true ]; then +echo -e "${CYAN}║ Stegasoo Docker Smoke Test ║${NC}" +else echo -e "${CYAN}║ Stegasoo Pi Image Smoke Test ║${NC}" +fi echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" echo -e "Target: ${YELLOW}$BASE_URL${NC}" +if [ "$DOCKER_MODE" = true ]; then + echo -e "Mode: ${YELLOW}Docker${NC}" +fi echo "" # ============================================================================= @@ -483,32 +493,45 @@ fi echo "" echo -e "${BOLD}[8/9] System Health${NC}" -# Check if stegasoo CLI works via SSH (optional) -if command -v sshpass &>/dev/null; then - CLI_VERSION=$(sshpass -p 'stegasoo' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ - admin@$PI_IP "stegasoo --version" 2>/dev/null || echo "") - - if [ -n "$CLI_VERSION" ]; then - pass "CLI accessible: $CLI_VERSION" +if [ "$DOCKER_MODE" = true ]; then + # Docker mode: skip SSH/systemd checks, just verify container is responding + HEALTH_CHECK=$(curl $CURL_OPTS -s -o /dev/null -w "%{http_code}" "$BASE_URL/" 2>/dev/null || echo "000") + if [ "$HEALTH_CHECK" = "200" ] || [ "$HEALTH_CHECK" = "302" ]; then + pass "Docker container healthy (HTTP $HEALTH_CHECK)" else - skip "CLI check (SSH failed or CLI not in PATH)" + fail "Docker container not responding (HTTP $HEALTH_CHECK)" fi + skip "CLI check (Docker mode)" + skip "Service check (Docker mode)" else - skip "CLI check (sshpass not installed)" -fi + # Pi mode: check via SSH + # Check if stegasoo CLI works via SSH (optional) + if command -v sshpass &>/dev/null; then + CLI_VERSION=$(sshpass -p 'stegasoo' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ + admin@$PI_IP "stegasoo --version" 2>/dev/null || echo "") -# Check service status via SSH -if command -v sshpass &>/dev/null; then - SERVICE_STATUS=$(sshpass -p 'stegasoo' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ - admin@$PI_IP "systemctl is-active stegasoo" 2>/dev/null || echo "unknown") - - if [ "$SERVICE_STATUS" = "active" ]; then - pass "Stegasoo service is active" + if [ -n "$CLI_VERSION" ]; then + pass "CLI accessible: $CLI_VERSION" + else + skip "CLI check (SSH failed or CLI not in PATH)" + fi else - fail "Stegasoo service status: $SERVICE_STATUS" + skip "CLI check (sshpass not installed)" + fi + + # Check service status via SSH + if command -v sshpass &>/dev/null; then + SERVICE_STATUS=$(sshpass -p 'stegasoo' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ + admin@$PI_IP "systemctl is-active stegasoo" 2>/dev/null || echo "unknown") + + if [ "$SERVICE_STATUS" = "active" ]; then + pass "Stegasoo service is active" + else + fail "Stegasoo service status: $SERVICE_STATUS" + fi + else + skip "Service check (sshpass not installed)" fi -else - skip "Service check (sshpass not installed)" fi # =============================================================================