aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-10-24 05:52:38 -0500
committerCraig Jennings <c@cjennings.net>2026-10-24 05:52:38 -0500
commit1ea3434be0bf6f66f1a3828ef0e4a6e0a6b8a761 (patch)
treec8dba3da16d7839efe181f9aad8400d26566333d
parent0adcfaa5c7e479e9c433b92836a5548a19168e05 (diff)
downloadarchangel-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-xscripts/test-install.sh36
-rw-r--r--tests/unit/test_test_install.bats98
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 ]