From 1da64394f637347414ffc4954daf9c72d180e2d0 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 2 Aug 2026 22:20:55 -0500 Subject: fix(test): stop one failed scenario from failing every scenario after it run_test exported INSTALLED_PASSWORD after the reboot step but cleared it only on the success path. Any failure after that point leaked the installed system's password into the next scenario, where ssh_cmd offered it to the live ISO and every call failed instantly. Six ZFS scenarios died that way behind one flaky check. I made it a local, so bash clears it on every return path. Install logs were written after stop_vm, so the fetch always reached a stopped guest. Every *-install.log this harness produced was empty, which is why the April mirror failure went 96 days undiagnosed. I write the captured log first now, then stop the VM. verify_rollback rolls back the mounted root underneath the running system. The wrapper check that ran next inherited the damage and failed at random. I put the fatal check first on a clean guest and left the destabilising one last, where it can only warn. Rebooting between them is the real fix. It needs the encrypted-pool passphrase re-sent through the QEMU monitor, so it stays filed. Both installer pushes in run_install are checked now. An unreported failure left the guest with no installer. The run then died at exit 127 with no output, which reads exactly like a real regression. --- tests/unit/test_test_install.bats | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'tests') diff --git a/tests/unit/test_test_install.bats b/tests/unit/test_test_install.bats index f339baf..bf43dd8 100644 --- a/tests/unit/test_test_install.bats +++ b/tests/unit/test_test_install.bats @@ -300,3 +300,53 @@ error: failed to commit transaction (invalid or corrupted package (checksum)) run is_archzfs_cache_corruption "" [ "$status" -eq 1 ] } + +############################# +# INSTALLED_PASSWORD scoping +############################# +# After the reboot step, run_test switches ssh_cmd over to the installed +# system's root password. That value must not outlive the test. When it leaks +# into the next scenario, ssh_cmd presents the installed password to the *live +# ISO* — whose password is different — so every SSH call fails instantly and +# the install dies with no output and no package requests. +# +# That is exactly what happened on 2026-08-01: the reset was a single `unset` +# on the success path, three failure paths returned early past it, and one +# flaky check cascaded into six silent ZFS install failures. The fix declares +# it `local` in run_test so bash clears it on every return path. + +@test "ssh_cmd picks up a caller-scoped INSTALLED_PASSWORD" { + # Proves local-instead-of-export still reaches ssh_cmd: bash's dynamic + # scoping exposes a caller's local to the functions it calls. + sshpass() { echo "$2"; } + ssh() { :; } + caller_with_local() { + local INSTALLED_PASSWORD="installed-secret" + ssh_cmd true + } + run caller_with_local + [[ "$output" == *"installed-secret"* ]] +} + +@test "a caller-scoped INSTALLED_PASSWORD does not leak past a failed return" { + sshpass() { echo "$2"; } + ssh() { :; } + SSH_PASSWORD="live-iso-password" + failing_caller() { + local INSTALLED_PASSWORD="installed-secret" + return 1 + } + failing_caller || true + run ssh_cmd true + [[ "$output" == *"live-iso-password"* ]] + [[ "$output" != *"installed-secret"* ]] +} + +@test "run_test declares INSTALLED_PASSWORD local and never exports it" { + # Structural guard: run_test itself drives qemu and ssh, so this file + # can't exercise it directly. An export here would silently restore the + # cascade, so pin the shape that prevents it. + local src="${BATS_TEST_DIRNAME}/../../scripts/test-install.sh" + grep -qE '^[[:space:]]*local INSTALLED_PASSWORD=' "$src" + ! grep -qE '^[[:space:]]*export INSTALLED_PASSWORD' "$src" +} -- cgit v1.2.3