Files
FWS-ISO/scripts/test-vm.sh
T
nocode d592b24858 test(vm): add test-vm.sh script for safe gameboot validation
Add test-vm.sh script for VM-based testing of gameboot and dual-boot Windows functionality.

The script sets up a QEMU VM with:
- UEFI firmware (OVMF) with persistent boot entries
- TPM 2.0 emulation (swtpm)
- 3 virtual NVMe disks (sparse qcow2 format)
- Optional Windows ISO mounting for deployment testing

Validates: ISO build/boot, dual-boot Windows spoke, conflict detection, fail-safe mechanisms, carving, wimlib apply, unattend injection, BCD configuration, Windows OOBE and FirstBoot, hibernation cycles.

Does not validate: GPU resume, real Secure Boot activation, VANGUARD (which rejects VMs).
2026-07-09 14:41:01 +02:00

93 lines
4.6 KiB
Bash
Executable File

#!/bin/bash
# ============================================================
# test-vm.sh — VM de test pour gameboot + dual-boot Windows, SANS RISQUE.
#
# Reproduit la machine cible : UEFI (OVMF, avec vars persistantes pour les
# entrées de boot), TPM 2.0 (swtpm), 3 disques NVMe virtuels (vide FWS / faux
# disque « jeux » / cible Windows). Disques qcow2 CREUX → coût disque réel = ce
# qui est écrit, pas la taille nominale. Aucune donnée réelle touchée.
#
# CE QUE ÇA VALIDE : build/boot de l'ISO, spoke « Dual-boot Windows », contrôle
# de conflit du récap, garde-fous fail-closed (choisir le disque FWS comme
# cible Windows → doit ABORTER), carve, wimlib apply, injection unattend, BCD
# (voie WinPE), OOBE Windows + auto-login + FirstBoot, l'aller-retour hibernate.
# CE QUE ÇA NE VALIDE PAS (→ vrai matériel) : resume du GPU RTX 5090, activation
# Secure Boot au firmware réel, et surtout VANGUARD (qui refuse justement la VM).
#
# Usage :
# scripts/test-vm.sh [ISO_FWS] [ISO_WINDOWS]
# ISO_FWS : défaut = la plus récente dans out/ (REBUILD d'abord : ./build-offi.sh !)
# ISO_WINDOWS : optionnelle, montée en 2e CD pour tester le déploiement Windows.
#
# Prérequis (Arch) : sudo pacman -S --needed qemu-full edk2-ovmf swtpm
# ============================================================
set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
WORK="$REPO/out/test-vm"
mkdir -p "$WORK"
# --- ISO FWS (rebuild indispensable pour avoir la feature gameboot) ---------
ISO_FWS="${1:-}"
if [ -z "$ISO_FWS" ]; then
ISO_FWS="$(find "$REPO/out" -name '*.iso' -not -path '*/test-vm/*' -printf '%T@ %p\n' 2>/dev/null \
| sort -rn | head -1 | cut -d' ' -f2-)"
fi
[ -n "$ISO_FWS" ] && [ -f "$ISO_FWS" ] || { echo "ISO FWS introuvable — lance d'abord ./build-offi.sh"; exit 1; }
echo "==> ISO FWS : $ISO_FWS"
echo " (⚠ vérifie que c'est un build RÉCENT, avec gameboot — pas une vieille ISO de out/)"
ISO_WIN="${2:-}"
# --- Outils ---
command -v qemu-system-x86_64 >/dev/null || { echo "installe : sudo pacman -S --needed qemu-full edk2-ovmf swtpm"; exit 1; }
# --- OVMF (firmware UEFI) : code RO + vars RW par-VM ------------------------
OVMF_CODE=""; OVMF_VARS_SRC=""
for c in /usr/share/edk2/x64/OVMF_CODE.4m.fd /usr/share/edk2/x64/OVMF_CODE.fd \
/usr/share/OVMF/OVMF_CODE.fd /usr/share/edk2-ovmf/x64/OVMF_CODE.fd; do
[ -f "$c" ] && { OVMF_CODE="$c"; break; }; done
for v in /usr/share/edk2/x64/OVMF_VARS.4m.fd /usr/share/edk2/x64/OVMF_VARS.fd \
/usr/share/OVMF/OVMF_VARS.fd /usr/share/edk2-ovmf/x64/OVMF_VARS.fd; do
[ -f "$v" ] && { OVMF_VARS_SRC="$v"; break; }; done
[ -n "$OVMF_CODE" ] && [ -n "$OVMF_VARS_SRC" ] || { echo "OVMF introuvable — sudo pacman -S edk2-ovmf"; exit 1; }
[ -f "$WORK/OVMF_VARS.fd" ] || cp "$OVMF_VARS_SRC" "$WORK/OVMF_VARS.fd"
# --- Disques NVMe virtuels CREUX (recréés si absents) -----------------------
# nvme0 = FWS (install) · nvme1 = faux « jeux » (doit rester intact) ·
# nvme2 = cible Windows (assez grand : swap 96 Gio + NTFS + ESP).
mk(){ [ -f "$WORK/$1" ] || qemu-img create -f qcow2 "$WORK/$1" "$2" >/dev/null; }
mk fws.qcow2 64G
mk games.qcow2 32G
mk win.qcow2 300G
echo "==> Disques : $WORK/{fws,games,win}.qcow2 (creux)"
# --- TPM 2.0 (swtpm) --------------------------------------------------------
TPMDIR="$WORK/tpm"; mkdir -p "$TPMDIR"
swtpm socket --tpmstate dir="$TPMDIR" --ctrl type=unixio,path="$TPMDIR/sock" \
--tpm2 --terminate &
SWTPM_PID=$!
trap 'kill "$SWTPM_PID" 2>/dev/null || true' EXIT
sleep 1
# --- CD Windows optionnel ---------------------------------------------------
WINCD=()
if [ -n "$ISO_WIN" ] && [ -f "$ISO_WIN" ]; then
WINCD=(-drive file="$ISO_WIN",media=cdrom,readonly=on)
echo "==> ISO Windows montée en 2e CD (dans le live : la monter, puis la pointer dans le spoke)."
fi
echo "==> Lancement de la VM (UEFI + TPM2 + 3 NVMe). Ferme la fenêtre pour quitter."
exec qemu-system-x86_64 \
-machine q35,smm=on,accel=kvm -cpu host -smp 4 -m 8G \
-drive if=pflash,format=raw,readonly=on,file="$OVMF_CODE" \
-drive if=pflash,format=raw,file="$WORK/OVMF_VARS.fd" \
-chardev socket,id=chrtpm,path="$TPMDIR/sock" \
-tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-crb,tpmdev=tpm0 \
-drive file="$WORK/fws.qcow2",if=none,id=d0 -device nvme,drive=d0,serial=FWS0 \
-drive file="$WORK/games.qcow2",if=none,id=d1 -device nvme,drive=d1,serial=GAMES1 \
-drive file="$WORK/win.qcow2",if=none,id=d2 -device nvme,drive=d2,serial=WIN2 \
-cdrom "$ISO_FWS" "${WINCD[@]}" \
-boot menu=on \
-netdev user,id=n0 -device virtio-net,netdev=n0 \
-vga virtio -display gtk,gl=on