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.
Hito 0.3 — ISO Test Plan
Section titled “Hito 0.3 — ISO Test Plan”Last updated: 2026-04-19
Applies to: SynVirt-0.3.3-amd64.iso (Debian 13.4.0 Trixie, dual-pool ZFS)
SHA256: 4fa78abfdac79faa57929a0318a239936fb05252aa11050cdc303aacad3c782e
Purpose
Section titled “Purpose”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”Why this scenario exists
Section titled “Why this scenario exists”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.
Preconditions
Section titled “Preconditions”- 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.batis configured for UEFI firmware + SCSI bus.- No prior test VM is running.
- From a Windows terminal in the repo root, run:
scripts\test-iso-vm-uefi.bat
- Let the VM power on. Default boot entry “Install SynVirt” auto-selects after the 5-second timeout.
- 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
- 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.
- After reboot, log in on
tty1asrootwith the password set during the wizard.
Expected observations
Section titled “Expected observations”| 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 |
Pass criteria
Section titled “Pass criteria”All checkpoints green. After the operator confirms the TUI summary, the install runs unattended and the daemon is reachable on first boot.
Fail triage
Section titled “Fail triage”- TUI never appears on tty1 — udeb not picked up by d-i. Check that the
ISO contains
pool/main/v/synvirt-installer/synvirt-installer_*.udeband thatdists/trixie/main/debian-installer/binary-amd64/Packages.gzcontains aPackage: synvirt-installerstanza withInstaller-Menu-Item: 4500. - TUI runs but partman ignores the disk choice — the udeb did not push
partman-auto/diskto debconf. Inspect/var/log/syslogfrom inside d-i (Alt+F4) fordebconf-set-selectionserrors. - 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 reboot —
late_commanddid not see/tmp/synvirt-setup-token. The preseed copies it into/target/tmpfrom the d-i tmpfs; if the udeb crashed before writing it, this step is a no-op and the late_command logsWARN: ... not present.
Scenario 2 — UEFI + multi-disk operator selection
Section titled “Scenario 2 — UEFI + multi-disk operator selection”Why this scenario exists
Section titled “Why this scenario exists”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.
Preconditions
Section titled “Preconditions”- 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-aanddisk-bwith a recognizable partition table (e.g. a single ext4 partition each) so you can verify they remain untouched.
- Boot the VM from the ISO. The boot menu has a single entry — let it auto-select.
- When the TUI reaches the target-disk screen, verify the list contents and note them in the test record.
- Select
disk-c(100 GiB). Continue through the rest of the TUI with any valid hostname / network / root password. - Confirm the summary; let d-i finish unattended and reboot.
- After reboot, log in and inspect disk layout.
Expected observations
Section titled “Expected observations”| 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 |
Pass criteria
Section titled “Pass criteria”- 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).
Fail triage
Section titled “Fail triage”- 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+F2in d-i and runlsblk -ndo NAME,SIZE,TYPEto 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/diskdebconf value. Confirm withdebconf-show partman-autofrom a d-i shell. disk-aordisk-bwas rewritten — partman recipe escaped its disk scope. Recheck the recipe’s$iflabel{ gpt }/$reusemethod{ }clauses insynvirt.preseedand the udeb’s per-disk wipe predicate.
Scenario 3 — First-boot setup token lifecycle
Section titled “Scenario 3 — First-boot setup token lifecycle”Why this scenario exists
Section titled “Why this scenario exists”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.
Preconditions
Section titled “Preconditions”- 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”- Boot the cloned VM. Log in as
root. - Capture the token mtime:
stat -c '%Y' /var/lib/synvirt/setup-token. - From the host (or from inside the VM): submit the first wizard request
with the token in the
X-Setup-Tokenheader againsthttps://<vm-ip>/api/v1/setup/status. - Expected: HTTP 200, JSON body with daemon reporting
setup-pending. - 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”- Re-clone the post-install image (do not reuse Part A’s VM — that token is now consumed).
- Boot the clone. Log in as
root. - Advance the system clock by 65 minutes:
timedatectl set-ntp falsedate -s "$(date -d '+65 minutes' +'%Y-%m-%d %H:%M:%S')"
- Submit the same
X-Setup-Tokenrequest as in Part A step 3. - Expected: HTTP 401 (or the daemon’s documented “token expired” response). Daemon log records the rejection with the elapsed delta.
Expected observations
Section titled “Expected observations”| 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) |
Pass criteria
Section titled “Pass criteria”- 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.
Fail triage
Section titled “Fail triage”- 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 -ufrom 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-tokenafter Part A step 4.
Summary table
Section titled “Summary table”| 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.