diff options
| author | Craig Jennings <c@cjennings.net> | 2026-10-24 05:52:38 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-10-24 05:52:38 -0500 |
| commit | 1ea3434be0bf6f66f1a3828ef0e4a6e0a6b8a761 (patch) | |
| tree | c8dba3da16d7839efe181f9aad8400d26566333d | |
| parent | 0adcfaa5c7e479e9c433b92836a5548a19168e05 (diff) | |
| download | archangel-1ea3434be0bf6f66f1a3828ef0e4a6e0a6b8a761.tar.gz archangel-1ea3434be0bf6f66f1a3828ef0e4a6e0a6b8a761.zip | |
fix(test): distinguish stale archzfs cache failures
I only blame the archzfs cache when the failure names a supported ZFS
package. Other checksum and signature failures now point at pacoloco.
Stale cache errors no longer enter the transient retry loop.
| -rwxr-xr-x | scripts/test-install.sh | 36 | ||||
| -rw-r--r-- | tests/unit/test_test_install.bats | 98 |
2 files changed, 127 insertions, 7 deletions
diff --git a/scripts/test-install.sh b/scripts/test-install.sh index 7a7f991..3783ce8 100755 --- a/scripts/test-install.sh +++ b/scripts/test-install.sh @@ -622,6 +622,9 @@ save_attempt_log() { # Usage: is_transient_install_failure "$install_log" is_transient_install_failure() { local log="$1" + # A stale archzfs cache fails with a download error too, but every retry + # hits the same cached file. + is_archzfs_cache_corruption "$log" && return 1 # Scope the match to the base-install step. A blip during some later # pacman call shouldn't be read as a pacstrap flake. grep -q "Failed to install packages to new root" <<<"$log" || return 1 @@ -633,14 +636,30 @@ is_transient_install_failure() { # Recognize the archzfs stale-cache corruption: archzfs re-uploads its # GitHub release assets under the same filename, so a zfs-dkms/zfs-utils # cached in the host pacoloco can mismatch the fresh archzfs.db checksum -# and pacstrap aborts with "invalid or corrupted package". Not transient -# (a retry hits the same cached file), so the caller prints a cache-clear -# hint rather than retrying. +# and pacstrap aborts with "invalid or corrupted package". Once the package +# bodies are cleared but the db is still stale, the same cause shows up as +# "Maximum file size exceeded" instead (libalpm's own wording for the same +# limit, hit mid-stream, is "expected download size exceeded"). Not transient (a retry hits the same +# cached file), so the caller prints a cache-clear hint rather than retrying. +# +# The zfs package has to be named on the failing line itself. Every install +# log mentions archzfs during the database sync, Btrfs installs included, so +# a match anywhere in the log blamed this cache for a corrupt openssl. is_archzfs_cache_corruption() { local log="$1" grep -q "Failed to install packages to new root" <<<"$log" || return 1 - grep -Eqi 'invalid or corrupted package|corrupted \(checksum\)' <<<"$log" || return 1 - grep -Eqi 'zfs-dkms|zfs-utils|archzfs' <<<"$log" + grep -Eq "File [^ ]*/zfs-(dkms|utils|linux[^/[:space:]]*)-[^ ]* is corrupted|failed retrieving file 'zfs-(dkms|utils|linux[^']*)-[^']*'.*(Maximum file size exceeded|expected download size exceeded)" <<<"$log" +} + +# Recognize any package that failed its checksum or signature check during +# the base install. The caller only reaches this after ruling out the +# archzfs cache, so it points at the proxy instead: pacoloco appending a +# retried upstream download to a partial body served openssl and gcc corrupt +# on 2026-09-12. +is_package_integrity_failure() { + local log="$1" + grep -q "Failed to install packages to new root" <<<"$log" || return 1 + grep -Eq 'File [^ ]* is corrupted \((invalid or corrupted package|checksum)' <<<"$log" } # Copy config to VM and run install @@ -1201,8 +1220,11 @@ run_test() { else error "Installation failed or timed out" if is_archzfs_cache_corruption "$install_log"; then - warn "Stale archzfs package in the host pacoloco cache (archzfs re-uploads same-filename assets)." - warn "Rebuild the ISO (build.sh clears it) or run: sudo rm -f /var/cache/pacoloco/pkgs/archzfs/zfs-* — then retry." + warn "Stale archzfs cache in the host pacoloco: archzfs re-uploads its release assets under the same filenames." + warn "Clear the whole directory, database included, then re-run: sudo rm -rf /var/cache/pacoloco/pkgs/archzfs" + elif is_package_integrity_failure "$install_log"; then + warn "A package failed its checksum or signature check, and it isn't an archzfs package." + warn "pacoloco may have served a partial download. Check 'journalctl -u pacoloco' for the upstream mirror, then re-run." fi # Save logs BEFORE stopping the VM. The retry loop above already # fetched the in-VM install log into $install_log while the guest was diff --git a/tests/unit/test_test_install.bats b/tests/unit/test_test_install.bats index 3fb7c19..ab3541b 100644 --- a/tests/unit/test_test_install.bats +++ b/tests/unit/test_test_install.bats @@ -60,6 +60,16 @@ setup() { # is_transient_install_failure ############################# +# A stale archzfs cache fails pacstrap with a download error, which reads as +# a mirror flake. It isn't transient: every retry hits the same cached file. +@test "is_transient_install_failure does not retry a stale archzfs cache" { + local log="error: failed retrieving file 'zfs-dkms-2.4.4-1-x86_64.pkg.tar.zst' from 10.0.2.2:9129 : Maximum file size exceeded +warning: failed to retrieve some files +==> ERROR: Failed to install packages to new root" + run is_transient_install_failure "$log" + [ "$status" -eq 1 ] +} + # Normal: a flaky-mirror failure (pacstrap marker + download error) retries. @test "is_transient_install_failure matches a mirror download flake" { local log="==> Installing base system @@ -324,6 +334,13 @@ error: failed to commit transaction (invalid or corrupted package (checksum)) [ "$status" -eq 0 ] } +@test "is_archzfs_cache_corruption matches a zfs-linux checksum corruption" { + local log=":: File /mnt/var/cache/pacman/pkg/zfs-linux-lts-2.4.4-1-x86_64.pkg.tar.zst is corrupted (checksum). +==> ERROR: Failed to install packages to new root" + run is_archzfs_cache_corruption "$log" + [ "$status" -eq 0 ] +} + @test "is_archzfs_cache_corruption ignores a transient mirror flake" { local log="error: failed retrieving file 'core.db' : Operation too slow ==> ERROR: Failed to install packages to new root" @@ -338,6 +355,87 @@ error: failed to commit transaction (invalid or corrupted package (checksum)) [ "$status" -eq 1 ] } +# Every install log names archzfs during the database sync, Btrfs installs +# included, because the harness adds the repo to the live pacman.conf. A +# match anywhere in the log blamed the archzfs cache for a corrupt openssl +# on 2026-09-12. +@test "is_archzfs_cache_corruption ignores a non-archzfs corruption in a log that mentions archzfs" { + local log=":: Synchronizing package databases... + core downloading... + archzfs downloading... +error: openssl: signature from \"Pierre Schmitz <pierre@archlinux.org>\" is invalid +:: File /mnt/var/cache/pacman/pkg/openssl-3.6.4-1-x86_64.pkg.tar.zst is corrupted (invalid or corrupted package (PGP signature)). +error: failed to commit transaction (invalid or corrupted package) +==> ERROR: Failed to install packages to new root" + run is_archzfs_cache_corruption "$log" + [ "$status" -eq 1 ] +} + +# The other face of the same stale cache: once the package bodies are gone +# but archzfs.db is stale, pacoloco refuses the fresh body (2026-09-13). +@test "is_archzfs_cache_corruption matches a zfs package refused as too large" { + local log=" zfs-dkms-2.4.4-1-x86_64 downloading... +error: failed retrieving file 'zfs-dkms-2.4.4-1-x86_64.pkg.tar.zst' from 10.0.2.2:9129 : Maximum file size exceeded +warning: failed to retrieve some files +error: failed to commit transaction (unexpected error) +==> ERROR: Failed to install packages to new root" + run is_archzfs_cache_corruption "$log" + [ "$status" -eq 0 ] +} + +@test "is_archzfs_cache_corruption matches libalpm's mid-stream size-limit wording" { + local log="error: failed retrieving file 'zfs-utils-2.4.4-3-x86_64.pkg.tar.zst' from 10.0.2.2:9129 : expected download size exceeded +warning: failed to retrieve some files +==> ERROR: Failed to install packages to new root" + run is_archzfs_cache_corruption "$log" + [ "$status" -eq 0 ] +} + +############################# +# is_package_integrity_failure +############################# +# Any package that fails its checksum or signature check. The caller uses it +# for the non-archzfs case, where the archzfs cache-clear hint would be wrong. + +@test "is_package_integrity_failure matches a PGP signature failure" { + local log=":: File /mnt/var/cache/pacman/pkg/openssl-3.6.4-1-x86_64.pkg.tar.zst is corrupted (invalid or corrupted package (PGP signature)). +==> ERROR: Failed to install packages to new root" + run is_package_integrity_failure "$log" + [ "$status" -eq 0 ] +} + +@test "is_package_integrity_failure matches a checksum failure" { + local log=":: File /mnt/var/cache/pacman/pkg/glibc-2.43-1-x86_64.pkg.tar.zst is corrupted (invalid or corrupted package (checksum)). +==> ERROR: Failed to install packages to new root" + run is_package_integrity_failure "$log" + [ "$status" -eq 0 ] +} + +@test "is_package_integrity_failure matches pacman's short checksum wording" { + local log=":: File /mnt/var/cache/pacman/pkg/glibc-2.43-1-x86_64.pkg.tar.zst is corrupted (checksum). +==> ERROR: Failed to install packages to new root" + run is_package_integrity_failure "$log" + [ "$status" -eq 0 ] +} + +@test "is_package_integrity_failure ignores a transient mirror flake" { + local log="error: failed retrieving file 'core.db' : Operation too slow +==> ERROR: Failed to install packages to new root" + run is_package_integrity_failure "$log" + [ "$status" -eq 1 ] +} + +@test "is_package_integrity_failure ignores a corruption outside the base install" { + local log=":: File /var/cache/pacman/pkg/openssl-3.6.4-1-x86_64.pkg.tar.zst is corrupted (invalid or corrupted package (PGP signature))." + run is_package_integrity_failure "$log" + [ "$status" -eq 1 ] +} + +@test "is_package_integrity_failure returns 1 on a clean log" { + run is_package_integrity_failure "" + [ "$status" -eq 1 ] +} + @test "is_archzfs_cache_corruption returns 1 on a clean log" { run is_archzfs_cache_corruption "" [ "$status" -eq 1 ] |
