Skip to content

Hito 0.3 — ISO Test Plan

Synced read-only from /home/synnet/mirrors/synvirt-product/docs/testing/hito-0.3-test-plan.md. Edit at the source, not here.

Last updated: 2026-04-19 Applies to: SynVirt-0.3.3-amd64.iso (Debian 13.4.0 Trixie, dual-pool ZFS) SHA256: 4fa78abfdac79faa57929a0318a239936fb05252aa11050cdc303aacad3c782e


The ISO now boots with a single entry (“Install SynVirt”) and integrates the SynVirt setup wizard as a debian-installer component (udeb, Installer-Menu-Item priority 4500). The TUI runs after network detection and before partman; it pushes the operator’s choices into debconf as preseeds, then exits. The standard installer steps (partman, passwd, netcfg final write) consume those preseeds and run unattended. After reboot, the daemon is up and the web wizard authenticates the first request with a one-time token written by the udeb at install time.

Three scenarios cover the surfaces that matter for the Hito 0.3 release. Passing all three is the acceptance gate before declaring the ISO shippable.

# Scenario Firmware Disk layout
1 UEFI + paravirtual SCSI single-disk happy path UEFI 1 × 80 GiB
2 UEFI + multi-disk operator selection UEFI 3 × mixed size
3 First-boot setup token lifecycle (validity + expiry) UEFI reuse #1 image

Scenario 1 — UEFI + SCSI paravirtual, single-disk happy path

Section titled “Scenario 1 — UEFI + SCSI paravirtual, single-disk happy path”

Validates the end-to-end udeb flow: the TUI runs inside d-i, debconf consumes the preseeds, partman lays out the dual-pool GPT layout under strict UEFI, the late_command relocates the setup token, and the daemon comes up after reboot ready for the first wizard request.

  • Host has a local VM runtime that supports strict UEFI (Secure Boot may be off) and a paravirtual SCSI disk bus.
  • test-iso-vm-uefi.bat is configured for UEFI firmware + SCSI bus.
  • No prior test VM is running.
  1. From a Windows terminal in the repo root, run:
    scripts\test-iso-vm-uefi.bat
  2. Let the VM power on. Default boot entry “Install SynVirt” auto-selects after the 5-second timeout.
  3. When the SynVirt setup wizard appears on tty1, walk through every screen with realistic values:
    • Language selection
    • Welcome
    • Target disk (single disk shown; select it)
    • Hostname (e.g. synvirt-test-1)
    • Network mode: DHCP
    • Root password (matching confirmation)
    • Review summary
    • Apply → wait for “Pushing preseeds to debconf…” then automatic exit
  4. The TUI exits and control returns to the d-i menu. Watch partman, passwd and the rest of the install run unattended. Expected total duration: 8–12 min from menu confirm to reboot.
  5. After reboot, log in on tty1 as root with the password set during the wizard.
Checkpoint Expected result
Boot menu Single entry “Install SynVirt”, countdown 5 s
TUI launch point TUI appears after “Detect network hardware”, before partman
TUI exit behaviour Apply screen reaches “Handing off to installer…” then closes; menu returns to d-i main menu
Partman output 4 partitions created: biosgrub (1 MB), ESP (538 MB), rpool ext4 (40 GB), localdata (rest)
Late setup log /var/log/synvirt-late-setup.log ends with === SynVirt late setup completed at ... ===
Setup token file /var/lib/synvirt/setup-token exists, mode 0400, owner root:root, non-empty
Token mtime Within a few minutes of install completion (drives the 60-minute web-wizard window)
ZFS pool status zpool list localdata returns ONLINE; 5 datasets present (vms, iso-cache, backups, ai-models, logs-archive)
Deferred ZFS unit (only if d-i kernel could not modprobe zfs) systemctl status synvirt-zfs-init.service reports active (exited) and /var/lib/synvirt/zfs-init.completed exists
Hostname applied hostnamectl returns the value entered in the TUI
Network applied ip -br addr matches the TUI selection (DHCP lease on the chosen interface)
Daemon reachability curl -k https://<vm-ip>/api/v1/health returns JSON with status "ok"
First wizard request authenticates curl -k -H "X-Setup-Token: $(cat /var/lib/synvirt/setup-token)" https://<vm-ip>/api/v1/setup/status returns 200

All checkpoints green. After the operator confirms the TUI summary, the install runs unattended and the daemon is reachable on first boot.

  • TUI never appears on tty1 — udeb not picked up by d-i. Check that the ISO contains pool/main/v/synvirt-installer/synvirt-installer_*.udeb and that dists/trixie/main/debian-installer/binary-amd64/Packages.gz contains a Package: synvirt-installer stanza with Installer-Menu-Item: 4500.
  • TUI runs but partman ignores the disk choice — the udeb did not push partman-auto/disk to debconf. Inspect /var/log/syslog from inside d-i (Alt+F4) for debconf-set-selections errors.
  • Daemon up but /api/v1/setup/* rejects a valid token — token mtime drift or daemon clock skew. Inspect /var/log/synvirt/daemon.log.
  • Token file missing after rebootlate_command did not see /tmp/synvirt-setup-token. The preseed copies it into /target/tmp from the d-i tmpfs; if the udeb crashed before writing it, this step is a no-op and the late_command logs WARN: ... not present.

Scenario 2 — UEFI + multi-disk operator selection

Section titled “Scenario 2 — UEFI + multi-disk operator selection”

Physical deployment hosts frequently have more than one disk. The TUI’s disk-picker screen must enumerate every eligible disk, filter out anything under the installer floor, persist the operator’s choice through debconf so partman targets the right device, and leave the unselected disks completely untouched.

  • Local VM runtime capable of attaching multiple virtual disks to a UEFI VM.
  • Create a VM (or adapt test-iso-vm-uefi.bat) with three disks attached via the same bus:
    • disk-a: 10 GiB (must be filtered out — below the installer floor)
    • disk-b: 60 GiB (eligible)
    • disk-c: 100 GiB (eligible; operator will pick this one)
  • Pre-populate disk-a and disk-b with a recognizable partition table (e.g. a single ext4 partition each) so you can verify they remain untouched.
  1. Boot the VM from the ISO. The boot menu has a single entry — let it auto-select.
  2. When the TUI reaches the target-disk screen, verify the list contents and note them in the test record.
  3. Select disk-c (100 GiB). Continue through the rest of the TUI with any valid hostname / network / root password.
  4. Confirm the summary; let d-i finish unattended and reboot.
  5. After reboot, log in and inspect disk layout.
Checkpoint Expected result
TUI disk list disk-a (10 GiB) absent; disk-b and disk-c both present
Persisted operator choice /var/lib/synvirt/target-disk.conf contains the device path of disk-c
Root filesystem location findmnt / points at a partition on disk-c
localdata pool vdev zpool status localdata lists partition 4 of disk-c
Other disks untouched disk-a and disk-b retain their original partition tables (sgdisk --print or parted -ms ... print matches the pre-install snapshot)
Late setup log /var/log/synvirt-late-setup.log reports the chosen disk in the Target disk: line
  • Installer uses the operator-selected disk end to end.
  • Ineligible disks (below the installer floor) are not offered.
  • Untouched disks remain bit-identical (partition table unchanged).
  • TUI list empty or only shows the first disk — inspect the udeb’s block-device enumeration and the size-floor predicate. Drop to a shell via Alt+F2 in d-i and run lsblk -ndo NAME,SIZE,TYPE to confirm what the kernel sees.
  • Install lands on a disk other than the one selected — the udeb did not push the operator’s choice as the partman-auto/disk debconf value. Confirm with debconf-show partman-auto from a d-i shell.
  • disk-a or disk-b was rewritten — partman recipe escaped its disk scope. Recheck the recipe’s $iflabel{ gpt } / $reusemethod{ } clauses in synvirt.preseed and the udeb’s per-disk wipe predicate.

Scenario 3 — First-boot setup token lifecycle

Section titled “Scenario 3 — First-boot setup token lifecycle”

The web wizard’s first POST is authenticated by a single-use token written by the udeb during install. The daemon accepts the token only inside a 60-minute window measured from the token file’s mtime. This scenario verifies both the happy path (token accepted within the window) and the expiry path (token refused after the window). It guards the boundary that keeps an unconfigured node from being adopted by an unauthorized operator.

  • A VM freshly installed from Scenario 1 (clone the disk image right after reboot, before any web-wizard request).
  • Two boots from this image will be needed: one immediate, one with a forced clock advance.

Part A — token accepted inside the window

Section titled “Part A — token accepted inside the window”
  1. Boot the cloned VM. Log in as root.
  2. Capture the token mtime: stat -c '%Y' /var/lib/synvirt/setup-token.
  3. From the host (or from inside the VM): submit the first wizard request with the token in the X-Setup-Token header against https://<vm-ip>/api/v1/setup/status.
  4. Expected: HTTP 200, JSON body with daemon reporting setup-pending.
  5. Submit a follow-up wizard step (e.g. cluster-name registration). Expected: HTTP 200; daemon transitions out of setup-pending.

Part B — token refused outside the window

Section titled “Part B — token refused outside the window”
  1. Re-clone the post-install image (do not reuse Part A’s VM — that token is now consumed).
  2. Boot the clone. Log in as root.
  3. Advance the system clock by 65 minutes:
    timedatectl set-ntp false
    date -s "$(date -d '+65 minutes' +'%Y-%m-%d %H:%M:%S')"
  4. Submit the same X-Setup-Token request as in Part A step 3.
  5. Expected: HTTP 401 (or the daemon’s documented “token expired” response). Daemon log records the rejection with the elapsed delta.
Checkpoint Expected result
Token file (post-install) /var/lib/synvirt/setup-token mode 0400, owner root:root
Token presence in daemon log on first request Log line records “setup token validated, age=
Part A — request inside window HTTP 200; daemon advances state
Part B — request after 65-minute clock advance HTTP 401; daemon log records “setup token expired, age=
Token reuse after consumption After Part A’s successful first request, a second request with the same token is rejected (single-use semantics)
  • A request inside the 60-minute window with the correct token succeeds.
  • A request outside the window is refused with a deterministic error.
  • A token consumed by a successful request cannot be reused.
  • Token accepted past the window — the daemon is comparing the wrong field (e.g. file ctime instead of mtime) or the window constant is wrong. Inspect the setup-token validator in the daemon’s auth layer.
  • Token rejected inside the window — clock skew between the udeb’s token write and the running daemon. Verify both with date -u from the installer shell (during Scenario 1) and from the booted system.
  • Single-use semantics broken — daemon does not delete or invalidate the token after a successful first request. Confirm by listing /var/lib/synvirt/setup-token after Part A step 4.

Scenario Firmware Disks Exercises
1. UEFI + SCSI happy path UEFI 1 × 80 GiB SCSI udeb TUI → debconf → partman → late_command → daemon online
2. UEFI multi-disk operator selection UEFI 3 × mixed sizes TUI disk enumeration + size floor + per-disk scope of partman recipe
3. Setup token lifecycle UEFI reuse #1 image token mode/ownership, 60-minute window, single-use semantics

All three must pass before the 0.3.x ISO is declared shippable.