#!/bin/sh set -eu umask 077 : "${NORDVPN_PACKAGE_PATH:?Set NORDVPN_PACKAGE_PATH to the package under test.}" : "${OPNSENSE_VM_IMAGE:?Set OPNSENSE_VM_IMAGE to the OPNsense qcow2 base image.}" : "${OPNSENSE_TRANSFER_IMAGE:?Set OPNSENSE_TRANSFER_IMAGE to the OPNsense transfer disk.}" script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) runtime_dir="$script_dir/.runtime" ui_port=${OPNSENSE_UI_PORT:-18443} credentials_file="$runtime_dir/credentials.env" launcher_file="$runtime_dir/launcher.pid" test -r "$NORDVPN_PACKAGE_PATH" test -r "$OPNSENSE_VM_IMAGE" test -r "$OPNSENSE_TRANSFER_IMAGE" mkdir -p "$runtime_dir" if [ -r "$launcher_file" ]; then read -r previous_launcher < "$launcher_file" case "$previous_launcher" in *[!0-9]* | '') ;; *) if kill -0 "$previous_launcher" 2>/dev/null; then echo "An OPNsense UI fixture is already running." >&2 exit 1 fi ;; esac fi rm -f "$runtime_dir/opnsense.qcow2" "$runtime_dir/serial.in" "$runtime_dir/serial.out" \ "$runtime_dir/serial.log" "$runtime_dir/transfer.img" "$runtime_dir/ready" \ "$credentials_file" "$runtime_dir/ui-password" password=$(openssl rand -hex 32) printf '%s\n' "$password" > "$runtime_dir/ui-password" printf '%s\n' "OPNSENSE_UI_BASE_URL=https://127.0.0.1:$ui_port" > "$credentials_file" printf '%s\n' 'OPNSENSE_UI_USERNAME=root' >> "$credentials_file" printf '%s\n' "OPNSENSE_UI_PASSWORD=$password" >> "$credentials_file" printf '%s\n' 'OPNSENSE_UI_TEST_ALLOW_MUTATION=1' >> "$credentials_file" chmod 600 "$credentials_file" "$runtime_dir/ui-password" printf '%s\n' "$$" > "$launcher_file" mkfifo "$runtime_dir/serial.in" "$runtime_dir/serial.out" qemu-img create -q -f qcow2 -F qcow2 -b "$OPNSENSE_VM_IMAGE" "$runtime_dir/opnsense.qcow2" cp "$OPNSENSE_TRANSFER_IMAGE" "$runtime_dir/transfer.img" mcopy -o -i "$runtime_dir/transfer.img" "$NORDVPN_PACKAGE_PATH" ::os-nordvpn.pkg mcopy -o -i "$runtime_dir/transfer.img" "$script_dir/guest-setup.php" ::guest-setup.php mcopy -o -i "$runtime_dir/transfer.img" "$runtime_dir/ui-password" ::ui-password cleanup() { set +e [ -n "${qemu_pid:-}" ] && kill "$qemu_pid" 2>/dev/null [ -n "${serial_log_pid:-}" ] && kill "$serial_log_pid" 2>/dev/null rm -f "$runtime_dir/credentials.env" "$runtime_dir/ui-password" "$runtime_dir/ready" \ "$runtime_dir/transfer.img" "$runtime_dir/opnsense.qcow2" "$launcher_file" \ "$runtime_dir/serial.in" "$runtime_dir/serial.out" "$runtime_dir/serial.log" } trap cleanup EXIT INT TERM qemu-system-x86_64 \ -machine q35,accel=tcg \ -smp 2 \ -m 2048 \ -display none \ -monitor none \ -drive file="$runtime_dir/opnsense.qcow2",if=virtio,format=qcow2 \ -drive file="$runtime_dir/transfer.img",if=virtio,format=raw,readonly=on \ -netdev user,id=wan,net=192.168.1.0/24,dhcpstart=192.168.1.100,host=192.168.1.254,hostfwd=tcp:127.0.0.1:"$ui_port"-192.168.1.1:443 \ -device virtio-net-pci,netdev=wan \ -chardev pipe,id=console,path="$runtime_dir/serial" \ -serial chardev:console & qemu_pid=$! cat "$runtime_dir/serial.out" >> "$runtime_dir/serial.log" & serial_log_pid=$! wait_for() { pattern=$1 attempts=${2:-300} while ! grep -Fq "$pattern" "$runtime_dir/serial.log" 2>/dev/null; do attempts=$((attempts - 1)) [ "$attempts" -gt 0 ] || { echo "timed out waiting for: $pattern" >&2 exit 1 } sleep 1 done } send() { printf '%b' "$1" > "$runtime_dir/serial.in" } wait_for 'Autoboot in' 180 send ' ' sleep 1 send '2\n' wait_for 'Enter full pathname of shell' 180 send '\n' wait_for '# ' 60 send "mount -uw /\n" sleep 2 send "sh /etc/rc\n" wait_for 'root@OPNsense:/ #' 300 send "mount -o ro -t msdosfs /dev/vtbd1 /mnt && pkg add -f /mnt/os-nordvpn.pkg && php /mnt/guest-setup.php && umount /mnt && (pfctl -d >/dev/null 2>&1 || true) && echo UI_VM_READY\n" wait_for 'UI_VM_READY' 120 touch "$runtime_dir/ready" printf '%s\n' "OPNSENSE_UI_CREDENTIALS_FILE=$credentials_file" wait "$qemu_pid"