qemu and build: review fixes across the rig driver, boot script, and fetch helpers
Bounded waits and validated arguments in run.sh and ui-drive.sh, a seeded settings directory and root-only staged rootfs permissions with their own tests, qmp.py and imgtools.py hardening, the fetch scripts checking what they download, and ASCII typography throughout. Each fix carries its test under qemu/tests or tests/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3G6m9Aw5RyVY4ZowtKzEj
This commit is contained in:
+13
-5
@@ -80,7 +80,10 @@ show up in screendumps at random (issue #18).
|
||||
The guest carries the panel's own `/etc/passwd`, `/etc/shadow` and
|
||||
`/etc/group` (root's md5-crypt of the documented default password), so a
|
||||
screen that verifies the root password against `/etc/shadow` behaves as it
|
||||
does on a panel instead of rejecting every attempt.
|
||||
does on a panel instead of rejecting every attempt. `qemu_stage_rootfs()`
|
||||
(`lib.sh`) forces `etc/shadow` to mode 0600 on every stage: git tracks only
|
||||
the executable bit, so the checked-out source file's own mode depends on the
|
||||
checking-out umask and cannot be trusted to arrive non-world-readable.
|
||||
|
||||
## Scenarios
|
||||
|
||||
@@ -88,6 +91,8 @@ All take the virt-fragment `<zImage>`; `FLARE_EDGE=<checkout>` where noted.
|
||||
|
||||
| Scenario | Needs | Proves |
|
||||
|---|---|---|
|
||||
| `stage-rootfs-perms.sh` | - | offline, no VM: `qemu_stage_rootfs()` always lands `etc/shadow` at 0600, even staged from a source copy deliberately left 0644 |
|
||||
| `seed-dir.sh` | - | offline, no VM: `mkimage.sh`'s `SEED_DIR` hook lands every seeded file under userdata/warden with its original mode (a 0600 secret included), a seeded file beats a same-named `--state` value, a `SEED_DIR` that isn't a directory fails closed, and so does an individual entry that is a symlink, a subdirectory, or named outside `[A-Za-z0-9_.-]+` -- a hyphenated key such as `gas-plant.devices` still seeds cleanly |
|
||||
| `boot-smoke.sh` | - | sentinel-asserting boot; runs in CI inside kernel-build |
|
||||
| `portal-scenario.sh` | `FLARE_EDGE` | real flared against the desk mock portal: authenticated check-in, desired-state pull, signed tier-1 `.wfw` download; verify/stage/APPLYING as a dry run (no `WARDEN_FW_ALLOW_APPLY`) |
|
||||
| `ota-apply.sh` | `FLARE_EDGE` | the FULL apply: the `.wfw`'s bootable rootfs payload is written to rootfs_b (`run.sh --allow-apply` gates it per boot), the AvbABData in `misc` flips, and slot `_b` boots the applied version |
|
||||
@@ -95,6 +100,7 @@ All take the virt-fragment `<zImage>`; `FLARE_EDGE=<checkout>` where noted.
|
||||
| `ui-drive.sh <script>` | - | the same rig for a SEQUENCE: boots once, runs a `qmp.py drive` script of taps/swipes/screenshots in panel pixels, and FAILS if warden-ui died on the way (stage-2 init announces the exit on the console). `tests/scripts/nav-stress.txt` is the navigation regression: it reproduces the s_row_left overflow that segfaulted the UI on returning to Settings > Apps; `tests/scripts/home-leaves-fullscreen.txt` proves the `home` verb clears dashboard fullscreen, the state a hardware wake tap leaves behind (flare-edge #176); `tests/scripts/fullscreen-toggle-tracks-real-state.txt` proves a `fullscreen toggle` right after `home` (or a real tap) reads the dashboard's actual state rather than a belief `home` bypassed -- `test_qmp_drive.py`'s `FullscreenToggleTracksRealState` pins the same contract offline |
|
||||
| `real-image-boot.sh` | matched `rootfs.img` + `oem.img` | an ACTUAL flare-edge build (placed by `mkimage.sh --rootfs-image/--oem-image`) boots its own init chain to getty; binaries predating known fixes reproduce their bugs faithfully, a time machine for field issues |
|
||||
| `test-ui-drive-rs485.sh` | - | offline, no VM: a fake `run.sh` and (for one case) a fake `socat` stand in so `ui-drive.sh --rs485-devices`'s startup fails closed instead of printing a false "== rs485 simulator: ..." over a bus nothing is serving, for each of a qemu rs.sock that never appears, a socat that never links rs.pty, and an mbsim.py that dies before opening rs.ctl; also proves `cleanup()` escalates to SIGKILL for a sim process that ignores SIGTERM |
|
||||
| `run-sh-args-test.sh` | - | offline, no VM: a fake `qemu-system-arm` captures run.sh's own argv and pins the ctl/rs485 pci-serial ordering contract rootfs/sbin/init's ttyS0-vs-ttyS1 alias depends on -- the ctl device always enumerates before rs485, warden.ctl only lands on the cmdline when --ctl is given, and an rs485 pci-serial device (real or null-backed) is always present so the port count never shifts |
|
||||
| watchdog (`run.sh --watchdog`) | - | arm `/dev/watchdog`, don't pet: the VM resets ~30 s later (verified) |
|
||||
|
||||
Scenario fine print:
|
||||
@@ -121,7 +127,9 @@ Scenario fine print:
|
||||
## Requirements
|
||||
|
||||
`qemu-system-arm` (Debian 13 ships QEMU 10), `curl`, `cpio`, `mkfs.ext4`,
|
||||
`gcc-arm-linux-gnueabihf` (kernel build), `python3` (+`cryptography` for the
|
||||
portal scenario's `.wfw` signing). CI: the hosted `qemu-tools` job builds the
|
||||
tooling; the boot smoke runs inside the (also hosted, dispatch-only)
|
||||
`kernel-build` job, which apt-installs its own toolchain and qemu (ADR-0007).
|
||||
`debugfs` (both ship in `e2fsprogs`; `seed-dir.sh` reads a built partition
|
||||
back with it), `gcc-arm-linux-gnueabihf` (kernel build), `python3`
|
||||
(+`cryptography` for the portal scenario's `.wfw` signing). CI: the hosted
|
||||
`qemu-tools` job builds the tooling; the boot smoke runs inside the (also
|
||||
hosted, dispatch-only) `kernel-build` job, which apt-installs its own
|
||||
toolchain and qemu (ADR-0007).
|
||||
|
||||
Reference in New Issue
Block a user