#!/bin/bash # # The nightly's decisions, tried without a runner: which channels a run makes # and where they go (test/vm-image/nightly-plan), what it lays out and what # latest.json then says (test/vm-image/nightly-layout), and two things the # install test decides from what it is given: which Omarchy packages an ISO # installs, and when an install is over. set -euo pipefail ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd) plan="$ROOT/test/vm-image/nightly-plan" layout="$ROOT/test/vm-image/nightly-layout" harness="$ROOT/test/integration.d/base-test.sh" bash -n "$plan" bash -n "$layout" tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT fail() { echo "FAIL: $*" >&2; exit 1; } equal() { [[ $2 == "$3" ]] || fail "$1: got '$2', expected '$3'"; } refused() { # description, command...: it has to fail and say why local what=$1; shift if "$@" >"$tmp/refused.out" 2>"$tmp/refused.err"; then fail "$what was accepted"; fi [[ -s $tmp/refused.err ]] || fail "$what was refused without a word" } # ---------------------------------------------------------------- nightly-plan planned() { "$plan" "$@" 2>/dev/null; } first=$(planned 2026.10.09 431 1 schedule v4.0.4 "") equal "a first run makes both channels" "$(jq -r 'map(.channel) | join(",")' <<<"$first")" "edge,stable" equal "the edge version" "$(jq -r '.[0].version' <<<"$first")" "2026.10.09.431" equal "the edge path" "$(jq -r '.[0].release' <<<"$first")" "edge/2026.10.09.431" equal "the stable version is the release's" "$(jq -r '.[1].version' <<<"$first")" "4.0.4" equal "the stable path has the run number" "$(jq -r '.[1].release' <<<"$first")" "stable/4.0.4/431" again=$(planned 2026.10.09 431 2 schedule v4.0.4 "") equal "a run started again has its own edge version" "$(jq -r '.[0].version' <<<"$again")" "2026.10.09.431.2" equal "a run started again has its own stable path" "$(jq -r '.[1].release' <<<"$again")" "stable/4.0.4/431.2" [[ $(jq -r '.[].release' <<<"$first" | sort) != "$(jq -r '.[].release' <<<"$again" | sort)" ]] || fail "two attempts of one run share a path" equal "a published release is left out of a scheduled run" \ "$(planned 2026.10.09 432 1 schedule v4.0.4 4.0.4 | jq -r 'map(.channel) | join(",")')" "edge" equal "a new release is made on the next scheduled run" \ "$(planned 2026.10.09 432 1 schedule v4.0.5 4.0.4 | jq -r '.[1].version')" "4.0.5" equal "a manual run makes a published release again" \ "$(planned 2026.10.09 432 1 workflow_dispatch v4.0.4 4.0.4 | jq -r 'map(.channel) | join(",")')" "edge,stable" refused "a release tag that is not a version" "$plan" 2026.10.09 431 1 schedule nightly "" refused "an empty release tag" "$plan" 2026.10.09 431 1 schedule "" "" refused "a release tag with a path in it" "$plan" 2026.10.09 431 1 schedule "v4.0.4/../x" "" refused "a run number that is not a number" "$plan" 2026.10.09 "" 1 schedule v4.0.4 "" refused "a date in another form" "$plan" 2026-10-09 431 1 schedule v4.0.4 "" # -------------------------------------------------------------- nightly-layout sealed() { # directory: what vm-seal leaves rm -rf "$1"; mkdir -p "$1" local file for file in base.qcow2 vmlinuz initrd cmdline; do echo "$file of ${1##*/}" >"$1/$file"; done echo "sums of the seal" >"$1/SHA256SUMS" } export SITE=https://nightly.example ISO_SITE=https://iso.example ISO_COMMIT=0123456789abcdef0123456789abcdef01234567 # Edge. pacman answers for omarchy and omarchy-dev with the one installed # package, so its line is there twice. mkdir -p "$tmp/release" echo "an edge iso" >"$tmp/release/omarchy-2026.10.09-x86_64-edge.iso" sealed "$tmp/sealed-edge" printf '%s\n' "omarchy-dev 4.0.0.r6818.gc352b62-2" "omarchy-dev 4.0.0.r6818.gc352b62-2" \ "/usr/lib/modules/7.2.8-5-omarchy-bore/pkgbase is owned by linux-omarchy-bore 7.2.8-5" "7.2.8-5-omarchy-bore" >"$tmp/edge-packages" "$layout" edge 2026.10.09.431 edge/2026.10.09.431 "$tmp/release/omarchy-2026.10.09-x86_64-edge.iso" \ "$tmp/sealed-edge" "$tmp/edge-packages" "$tmp/out" >/dev/null json=$tmp/out/edge/latest.json dir=$tmp/out/edge/2026.10.09.431 field() { jq -r "$1" "$json"; } equal "edge: files published" "$(cd "$tmp/out" && find . -type f | sort | paste -sd' ')" \ "./edge/2026.10.09.431/omarchy-edge-2026.10.09.431.iso ./edge/2026.10.09.431/omarchy-edge-2026.10.09.431.iso.sha256 ./edge/2026.10.09.431/omarchy-edge-2026.10.09.431.qcow2 ./edge/2026.10.09.431/omarchy-edge-2026.10.09.431.qcow2.sha256 ./edge/2026.10.09.431/unpacked/SHA256SUMS ./edge/2026.10.09.431/unpacked/cmdline ./edge/2026.10.09.431/unpacked/initrd ./edge/2026.10.09.431/unpacked/vm-boot ./edge/2026.10.09.431/unpacked/vmlinuz ./edge/latest.json" (cd "$dir" && sha256sum -c --quiet ./*.sha256) || fail "edge: a checksum file does not match the file it is for" equal "edge: the ISO and the image each have a checksum file" "$(cd "$dir" && ls ./*.sha256 | wc -l)" "2" equal "edge: the image is the sealed disk" "$(cat "$dir/omarchy-edge-2026.10.09.431.qcow2")" "base.qcow2 of sealed-edge" (cd "$dir/unpacked" && sha256sum -c --quiet SHA256SUMS) || fail "edge: SHA256SUMS does not match the unpacked files" equal "edge: SHA256SUMS covers every file beside it" \ "$(awk '{ print $2 }' "$dir/unpacked/SHA256SUMS" | sort | paste -sd' ')" "$(cd "$dir/unpacked" && ls | grep -v SHA256SUMS | sort | paste -sd' ')" cmp -s "$dir/unpacked/vm-boot" "$ROOT/test/vm-image/vm-boot" || fail "edge: the published vm-boot is not the repository's" equal "edge: version" "$(field .version)" "2026.10.09.431" equal "edge: channel" "$(field .channel)" "edge" equal "edge: url" "$(field .url)" "https://nightly.example/edge/2026.10.09.431/omarchy-edge-2026.10.09.431.iso" equal "edge: sha256 is the ISO's" "$(field .sha256)" "$(sha256sum "$dir/omarchy-edge-2026.10.09.431.iso" | cut -d' ' -f1)" equal "edge: size is the ISO's" "$(field .size)" "$(stat -c %s "$dir/omarchy-edge-2026.10.09.431.iso")" equal "edge: iso_commit" "$(field .iso_commit)" "$ISO_COMMIT" equal "edge: omarchy_version, once" "$(field .omarchy_version)" "4.0.0.r6818.gc352b62-2" equal "edge: omarchy_commit" "$(field .omarchy_commit)" "c352b62" equal "edge: kernel" "$(field .kernel)" "7.2.8-5-omarchy-bore" equal "edge: image address" "$(field .vm.url)" "https://nightly.example/edge/2026.10.09.431/omarchy-edge-2026.10.09.431.qcow2" equal "edge: image checksum is the image's" "$(field .vm.sha256)" "$(sha256sum "$dir/omarchy-edge-2026.10.09.431.qcow2" | cut -d' ' -f1)" equal "edge: image size is the image's" "$(field .vm.size)" "$(stat -c %s "$dir/omarchy-edge-2026.10.09.431.qcow2")" equal "edge: the ISO and the image differ only in their ending" "$(field .url | sed 's/\.iso$//')" "$(field .vm.url | sed 's/\.qcow2$//')" equal "edge: unpacked folder" "$(field .vm.unpacked)" "https://nightly.example/edge/2026.10.09.431/unpacked/" equal "edge: every unpacked file listed is published" "$(field '.vm.unpacked_files[]' | sort | paste -sd' ')" "$(cd "$dir/unpacked" && ls | sort | paste -sd' ')" [[ $(field .built_at) =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9:]{8}Z$ ]] || fail "edge: built_at is '$(field .built_at)'" # What a consumer does with the ISO's name: the first run of three or more # dotted numbers is the version. [[ $(basename "$(field .url)") =~ [0-9]+(\.[0-9]+){2,} ]] || fail "edge: the ISO's name carries no version" equal "edge: the version read from the ISO's name" "${BASH_REMATCH[0]}" "2026.10.09.431" # Stable: the image is published, the released ISO stays where it is. rm -rf "$tmp/out" echo "a released iso" >"$tmp/release/omarchy-4.0.4.iso" sealed "$tmp/sealed-stable" printf '%s\n' "omarchy 4.0.4-1" "/usr/lib/modules/7.2.5-3-omarchy/pkgbase is owned by linux-omarchy 7.2.5-3" "7.2.5-3-omarchy" >"$tmp/stable-packages" "$layout" stable 4.0.4 stable/4.0.4/431 "$tmp/release/omarchy-4.0.4.iso" "$tmp/sealed-stable" "$tmp/stable-packages" "$tmp/out" >/dev/null json=$tmp/out/stable/latest.json equal "stable: no ISO is published" "$(find "$tmp/out" -name '*.iso*' | wc -l)" "0" [[ -f $tmp/release/omarchy-4.0.4.iso ]] || fail "stable: the released ISO was moved away" equal "stable: url is the release's" "$(field .url)" "https://iso.example/omarchy-4.0.4.iso" equal "stable: sha256 is the ISO's" "$(field .sha256)" "$(sha256sum "$tmp/release/omarchy-4.0.4.iso" | cut -d' ' -f1)" equal "stable: version" "$(field .version)" "4.0.4" equal "stable: omarchy_version" "$(field .omarchy_version)" "4.0.4-1" equal "stable: a release names no commit" "$(field .omarchy_commit)" "" equal "stable: image address has the run number" "$(field .vm.url)" "https://nightly.example/stable/4.0.4/431/omarchy-4.0.4.qcow2" equal "stable: unpacked folder" "$(field .vm.unpacked)" "https://nightly.example/stable/4.0.4/431/unpacked/" (cd "$tmp/out/stable/4.0.4/431" && sha256sum -c --quiet omarchy-4.0.4.qcow2.sha256) || fail "stable: the image's checksum file does not match it" (cd "$tmp/out/stable/4.0.4/431/unpacked" && sha256sum -c --quiet SHA256SUMS) || fail "stable: SHA256SUMS does not match the unpacked files" # Nothing half-made is described. sealed "$tmp/sealed-short"; rm "$tmp/sealed-short/initrd" refused "a sealed image without its initrd" "$layout" stable 4.0.4 stable/4.0.4/9 "$tmp/release/omarchy-4.0.4.iso" "$tmp/sealed-short" "$tmp/stable-packages" "$tmp/out2" sealed "$tmp/sealed-x"; : >"$tmp/no-packages" refused "an image that named no Omarchy package" "$layout" stable 4.0.4 stable/4.0.4/9 "$tmp/release/omarchy-4.0.4.iso" "$tmp/sealed-x" "$tmp/no-packages" "$tmp/out3" sealed "$tmp/sealed-y" refused "a released ISO under another version's name" "$layout" stable 4.0.5 stable/4.0.5/9 "$tmp/release/omarchy-4.0.4.iso" "$tmp/sealed-y" "$tmp/stable-packages" "$tmp/out4" sealed "$tmp/sealed-z" refused "a channel that does not exist" "$layout" rc 4.0.4 rc/4.0.4 "$tmp/release/omarchy-4.0.4.iso" "$tmp/sealed-z" "$tmp/stable-packages" "$tmp/out5" # --------------------------------------------------------------- nightly-fetch # The network is played by three stand-ins: gh lists the artifacts, curl gives # the signed address, aria2c "downloads" a zip made here. fetch="$ROOT/test/vm-image/nightly-fetch" bash -n "$fetch" if command -v zip >/dev/null && command -v unzip >/dev/null; then stubs=$tmp/stubs; mkdir -p "$stubs" "$tmp/payload/edge/1" echo "an image" >"$tmp/payload/edge/1/omarchy-edge-1.qcow2" echo '{"version": "1"}' >"$tmp/payload/edge/latest.json" (cd "$tmp/payload" && zip -qr "$tmp/artifact.zip" .) zip_size=$(stat -c %s "$tmp/artifact.zip") cat >"$stubs/gh" <"$stubs/curl" <<'STUB' #!/bin/bash echo "${@: -1}" >>"$FETCH_LOG"; printf 'https://storage.example/signed' STUB cat >"$stubs/aria2c" <>"\$FETCH_LOG" if [[ -n \${FETCH_FAIL_ONCE:-} && ! -e $tmp/failed ]]; then touch $tmp/failed; exit 1; fi for arg in "\$@"; do case \$arg in --dir=*) dir=\${arg#--dir=} ;; --out=*) out=\${arg#--out=} ;; esac; done cp "$tmp/artifact.zip" "\$dir/\$out" STUB chmod +x "$stubs"/* fetched() { PATH="$stubs:$PATH" TMPDIR="$tmp" FETCH_LOG="$tmp/fetch.log" "$@"; } : >"$tmp/fetch.log" fetched "$fetch" omacom/omarchy-iso 7 nightly-edge-7 "$tmp/fetched" >/dev/null equal "fetch: the files of the artifact" "$(cd "$tmp/fetched" && find . -type f | sort | paste -sd' ')" "./edge/1/omarchy-edge-1.qcow2 ./edge/latest.json" grep -q "/artifacts/12/zip" "$tmp/fetch.log" || fail "fetch: of two artifacts with one name, the newer was not the one fetched" equal "fetch: nothing left behind" "$(ls "$tmp" | grep -c 'nightly-fetch\.')" "0" : >"$tmp/fetch.log"; rm -f "$tmp/failed" FETCH_FAIL_ONCE=1 fetched "$fetch" omacom/omarchy-iso 7 nightly-edge-7 "$tmp/fetched-again" >/dev/null 2>&1 equal "fetch: a failed download is tried again with a new address" "$(grep -c zip "$tmp/fetch.log")" "2" refused "an artifact that does not exist" env FETCH_IDS=" " PATH="$stubs:$PATH" TMPDIR="$tmp" FETCH_LOG="$tmp/fetch.log" "$fetch" omacom/omarchy-iso 7 nightly-edge-7 "$tmp/f3" refused "a download of the wrong size" env FETCH_SIZE=1 PATH="$stubs:$PATH" TMPDIR="$tmp" FETCH_LOG="$tmp/fetch.log" "$fetch" omacom/omarchy-iso 7 nightly-edge-7 "$tmp/f4" [[ ! -e $tmp/f4/edge ]] || fail "fetch: a download of the wrong size was unpacked" refused "an artifact larger than the free space" env FETCH_SIZE=9000000000000000 PATH="$stubs:$PATH" TMPDIR="$tmp" FETCH_LOG="$tmp/fetch.log" "$fetch" omacom/omarchy-iso 7 nightly-edge-7 "$tmp/f5" grep -q "MiB free" "$tmp/refused.err" || fail "fetch: too little room is not what was reported" else echo "nightly-fetch tests skipped: no zip or unzip here" fi # -------------------------------------------------------------- nightly-rclone wrapped="$ROOT/test/vm-image/nightly-rclone" bash -n "$wrapped" mkdir -p "$tmp/rc" rclone_says() { # exit status, output lines...: a stand-in rclone local status=$1; shift { echo '#!/bin/bash'; printf 'echo %q >&2\n' "$@"; echo "exit $status"; } >"$tmp/rc/rclone" chmod +x "$tmp/rc/rclone" } rclone_says 0 "Transferred: 3 / 3, 100%" out=$(PATH="$tmp/rc:$PATH" "$wrapped" copy a b) [[ $out != *::warning::* ]] || fail "rclone: a clean upload was reported as a retry" [[ $out == *"Transferred: 3 / 3"* ]] || fail "rclone: its output was not passed through" rclone_says 0 "<3>ERROR : a.qcow2: Failed to copy: NotImplemented: Not Implemented" \ "<3>ERROR : a.qcow2: Failed to copy: NotImplemented: Not Implemented" \ "<3>ERROR : unpacked/vmlinuz: Failed to copy: NotImplemented: Not Implemented" \ "<3>ERROR : Attempt 2/3 failed with 2 errors" "<3>ERROR : Attempt 3/3 succeeded" out=$(PATH="$tmp/rc:$PATH" "$wrapped" copy a b) [[ $out == *"::warning::rclone needed a retry for 2 file(s): a.qcow2 unpacked/vmlinuz"* ]] || fail "rclone: a file that failed twice is not counted once: $(grep warning <<<"$out")" rclone_says 3 "<3>ERROR : a.qcow2: Failed to copy: AccessDenied" if PATH="$tmp/rc:$PATH" "$wrapped" copy a b >"$tmp/rc/out" 2>&1; then fail "rclone: a failed upload passed"; fi equal "rclone: its exit status is kept" "$(PATH="$tmp/rc:$PATH" "$wrapped" copy a b >/dev/null 2>&1; echo $?)" "3" if grep -q '::warning::' "$tmp/rc/out"; then fail "rclone: a failed upload was reported as a retry"; fi # rclone reads every RCLONE_ variable as that flag: RCLONE_VERSION=v1.75.2 # was "--version=v1.75.2" and stopped the publish before it uploaded anything. # Only its remote's settings, RCLONE_CONFIG_*, belong in a workflow's environment. flags=$(sed -nE 's/^[[:space:]]+(RCLONE_[A-Z0-9_]+):.*/\1/p' "$ROOT"/.github/workflows/*.yml | grep -v '^RCLONE_CONFIG_' | sort -u | paste -sd' ' || true) [[ -z $flags ]] || fail "rclone: a workflow sets $flags, which rclone would read as flags" # ------------------------------------------------------------ the install test # The harness is a script that starts a VM when it is read; take the two # functions out of it. eval "$(sed -n '/^detect_packages() {$/,/^}$/p; /^installed_system_started() {$/,/^}$/p' "$harness")" declare -F detect_packages installed_system_started >/dev/null || fail "the harness no longer has detect_packages and installed_system_started" packages_of() { ISO=$1; detect_packages; echo "$RUNTIME_PACKAGE $SETTINGS_PACKAGE"; } equal "an edge ISO installs the -dev packages" "$(packages_of release/omarchy-2026.10.09-x86_64-edge.iso)" "omarchy-dev omarchy-settings-dev" equal "a dev ISO installs the -dev packages" "$(packages_of release/omarchy-2026.10.09-x86_64-dev.iso)" "omarchy-dev omarchy-settings-dev" equal "a released ISO installs the release packages" "$(packages_of release/omarchy-4.0.4.iso)" "omarchy omarchy-settings" equal "a stable build installs the release packages" "$(packages_of /x/edge/omarchy-2026.10.09-x86_64-stable.iso)" "omarchy omarchy-settings" printf '%s\r\n' 'BdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00011 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x5,0xFFFF,0x0)' \ 'BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00011 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x5,0xFFFF,0x0)' >"$tmp/serial" if installed_system_started "$tmp/serial"; then fail "the installer's own boot counts as the installed system's"; fi printf '%s\r\n' 'BdsDxe: loading Boot0005 "Limine" from HD(1,GPT,774175D2,0x800,0x400000)/\EFI\limine\limine_x64.efi' >>"$tmp/serial" if installed_system_started "$tmp/serial"; then fail "loading Limine counts as having started it"; fi printf '%s\r\n' 'BdsDxe: starting Boot0005 "Limine" from HD(1,GPT,774175D2,0x800,0x400000)/\EFI\limine\limine_x64.efi' >>"$tmp/serial" installed_system_started "$tmp/serial" || fail "the installed system's Limine starting is not noticed" if installed_system_started "$tmp/no-such-log"; then fail "a missing serial log counts as a started system"; fi echo "nightly tests passed"