93 lines
5.8 KiB
Markdown
93 lines
5.8 KiB
Markdown
# Disposable laptop acceptance
|
|
|
|
`dev/laptop-smoke.py` exercises the packaged installer, doctor, ASCII branding,
|
|
signed runtime updater and offline base recovery in one new UEFI/KVM VM. It accepts
|
|
only trusted ISO and firmware inputs. It creates a private scratch directory and a
|
|
new 40 GiB qcow2, copies both firmware files, and retains the disk, serial logs and
|
|
`report.json` after success or failure. It never accepts an existing disk or host
|
|
block device. Run it where QEMU/KVM, Python and OpenSSL are already available; on
|
|
this development machine that is the normal-user Ubuntu development workspace.
|
|
|
|
```sh
|
|
python3 dev/laptop-smoke.py \
|
|
--iso /absolute/path/to/new-hydra.iso \
|
|
--ovmf-code /absolute/path/to/OVMF_CODE.fd \
|
|
--ovmf-vars /absolute/path/to/OVMF_VARS.fd \
|
|
--scratch-parent /tmp
|
|
```
|
|
|
|
The separate `dev/iso-smoke.py` whole-disk regression remains required. This harness
|
|
adds the following real guest operations:
|
|
|
|
1. Seed fresh GPT with an ESP, foreign data partition and selected root. Record
|
|
partition GUIDs/boundaries, the complete foreign partition hash, foreign EFI and
|
|
fallback bytes, and firmware BootOrder. Install Btrfs into `/dev/vda3` while
|
|
retaining `/dev/vda1`, explicitly register a HydraOS entry, then verify those
|
|
invariants before the harness deliberately sets BootNext to choose that entry.
|
|
Subsequent live boots also use verified one-shot BootNext selection. The same
|
|
SATA DVD drive stays attached throughout, empty during installed boots; no ISO
|
|
is available to those boots. OVMF can prune the empty DVD's automatic boot entry
|
|
despite that stable topology. The first live boot captures its verified EFI
|
|
load-option bytes; before returning to live, the harness restores those exact
|
|
bytes into an unused Boot#### variable only, verifies readback and unchanged
|
|
BootOrder, then selects BootNext. Existing variables are never overwritten. If
|
|
OVMF prunes HydraOS's create-only entry after consuming BootNext, the harness
|
|
similarly recreates only that known ESP/loader entry before later selections.
|
|
Initial installed selection still requires the installer's entry to exist.
|
|
Every deliberate registration and BootNext write is checked against unchanged
|
|
BootOrder. Live test consoles
|
|
reduce kernel console verbosity so asynchronous mount messages cannot corrupt
|
|
framed JSON; the messages remain in the guest kernel log.
|
|
2. Boot without ISO, verify the packaged Fastfetch art and doctor, install version
|
|
1.0 of a locally created EAPI 8 Portage package, and create a real qcow2 plus
|
|
profile/data sentinels under HOME. The fixture has no sources or dependencies;
|
|
`emerge --nodeps` runs in a private guest network namespace with no interfaces,
|
|
so it cannot fetch a package.
|
|
3. Temporarily pin a disposable TEST public key in that guest and verify signed
|
|
passive local artifacts through the packaged CLI. Apply and roll back a runtime
|
|
change, refuse a tampered archive without mutation, SIGKILL a child after an
|
|
actual runtime replacement, damage the CLI, then invoke the independently
|
|
installed `/usr/bin/hydra-update-recover` in a fresh process. Verify exact original
|
|
runtime bytes, the monotonic replay floor and unchanged VM data. Restore the
|
|
guest's original public key. The production signing key is never read.
|
|
4. Boot live with installed filesystems offline. Record kernel/boot, fixture Portage
|
|
database, world and owned EFI hashes, then create and list a real Btrfs checkpoint
|
|
through `hydra-system`. Boot the installed system, upgrade the fixture to 2.0
|
|
through Portage in a private network namespace and modify HOME and world.
|
|
5. Boot live again, deliberately damage actual installed kernels and the owned EFI
|
|
loader, and SIGKILL a real restore after its durable `root-retained` transition.
|
|
Resume the same checkpoint through a fresh `hydra-system` process. Compare exact
|
|
base, package database, world and EFI hashes and all preserved foreign invariants.
|
|
Boot without ISO and verify version 1.0, current HOME and unchanged VM disk/profile
|
|
data. The previous failed root and checkpoint remain on the disposable disk.
|
|
Installed checks read the existing `/boot/efi` mount after verifying its device,
|
|
filesystem and UUID against the storage marker; they never remount it read-only.
|
|
|
|
BootOrder preservation is checked immediately around each installer, checkpoint,
|
|
restore and harness selection operation. It is not compared across firmware boots:
|
|
OVMF itself removes empty-media entries from BootOrder. GPT, foreign partition
|
|
bytes and foreign/fallback EFI bytes remain strict invariants across the entire
|
|
sequence, including all reboots. Both scopes are explicit in `report.json`.
|
|
|
|
The loopback HTTP fixture serves only explicitly named in-memory TEST artifacts
|
|
and their public key. It exposes no host directory, build tree, private key or
|
|
credentials. The disposable private key is deleted before the VM boots. This HTTP
|
|
transport tests offline artifact delivery, not production HTTPS discovery or its
|
|
redirect policy. Neither runtime nor base recovery receives production signing
|
|
material or existing VM disks.
|
|
|
|
Only an actual `report.json` with `status: "passed"`, input SHA-256 identities and
|
|
all guest phases establishes acceptance. Source tests verify harness construction,
|
|
real signatures, narrow sharing, byte comparisons and guest script compilation;
|
|
they do not prove UEFI, Btrfs, Portage or installed boot. This sequence restores an
|
|
exact kernel after damage and upgrades a real minimal fixture package; it does not
|
|
claim an upgrade between two kernel versions. Physical ASUS Wi-Fi, audio, suspend,
|
|
brightness and refresh-rate checks still require live laptop verification.
|
|
|
|
Run the focused source checks without booting a VM:
|
|
|
|
```sh
|
|
python3 -m unittest tests.test_laptop_smoke
|
|
python3 -m py_compile dev/laptop-smoke.py tests/test_laptop_smoke.py
|
|
```
|