diff --git a/tests/smoke-rootfs.sh b/tests/smoke-rootfs.sh new file mode 100755 index 0000000..c7e62b4 --- /dev/null +++ b/tests/smoke-rootfs.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# Per-flavor rootfs smoke test (NAROS.md §10.3). +# +# smoke-rootfs.sh +# +# is the build-rootfs.sh tier: base | vm | vm-desktop. +# is an ALREADY-IMPORTED docker image (the caller runs `docker import` on the +# tarball, because it usually wants the named image for later steps too). +# amd64 | arm64 — passed to --platform. +# +# Assertions run inside the image under nash. They live here rather than inline in +# naros.yml because the vm and vm-desktop jobs are one matrix over a single set of steps: +# the flavors differ ONLY in what is asserted, and inlining that difference is what forced +# the two near-identical jobs the matrix replaced. +# +# Exit: 0 all assertions hold, non-zero on the first failure (the container shell is `set -e`). +set -euo pipefail + +FLAVOR="${1:?usage: smoke-rootfs.sh }" +IMAGE="${2:?missing image}" +ARCH="${3:?missing arch}" + +run() { docker run --rm --platform "linux/$ARCH" "$IMAGE" /usr/bin/nash -lc "$1"; } + +# Sourced by every flavor: narOS identity plus the forced-nash /bin/sh with the real bash kept +# aside. Leaves os-release variables ($VARIANT_ID, $VERSION_ID) in scope for the flavor blocks. +COMMON=' + set -e + . /etc/os-release; test "$ID" = naros + readlink /bin/sh | grep -q nash + test -x /usr/bin/bash.real +' + +# A runtime-clean sources.list (no build-time copy:// pool left in), scoped away from +# sources.list.d so the not-yet-live hosted-repo entry (naros-keyring) cannot fail this +# before the apt domain is provisioned. +APT_CLEAN=' + apt-get update -q -o Dir::Etc::SourceParts=- +' + +case "$FLAVOR" in + base) + echo "smoke: base rootfs ($ARCH)" + run "$COMMON"' + naros version + naros info --json > /dev/null + # Kernel identity shim (NAROS.md §2.3). Every command in this smoke test already runs + # under the global preload, so a broken .so fails the job long before here; these assert + # the tag is actually applied and correctly scoped. + grep -qxF /usr/lib/naros/libnaros-uname.so /etc/ld.so.preload + # VERSION_ID comes from the os-release sourced above. + uname -r | grep -q -- "-naros$VERSION_ID" + # sysname must stay "Linux" — build tooling switches on it. + test "$(uname -s)" = Linux + # The escape hatch /lib/modules consumers depend on must really bypass. Compare against + # procfs, which the shim cannot touch (a file read, not a syscall). + test "$(NAROS_UNAME_PASSTHROUGH=1 uname -r)" = "$(cat /proc/sys/kernel/osrelease)" + '"$APT_CLEAN" + ;; + + vm) + echo "smoke: vm rootfs — identity + forced shell + systemd present ($ARCH)" + # nash directly (systemd is PID 1 only under a real boot); assert the bootable base is sane. + run "$COMMON"' + test "$VARIANT_ID" = vm + test -x /usr/lib/systemd/systemd || test -x /lib/systemd/systemd + command -v systemctl > /dev/null + naros version + # The control-plane agent IS baked (from the local pool): it is the only way the host can + # reach the guest, and the phase-1 bootstrap no longer overlays a GHCR copy on top. The + # rest of the tier still arrives at firstboot via `apt install naros-tier-vm`. + test -x /usr/local/bin/nucleic-linux-agent + test -L /etc/systemd/system/multi-user.target.wants/nucleic-linux-agent.service + '"$APT_CLEAN" + ;; + + vm-desktop) + echo "smoke: vm-desktop rootfs — GNOME 50 + agent user + semantic surface ($ARCH)" + run "$COMMON"' + test "$VARIANT_ID" = vm + naros info --json | jq -e ".variant == \"vm\" and .flavor == \"desktop\"" > /dev/null + test "$(id -u agent)" = 501 + test -x /usr/lib/systemd/systemd || test -x /lib/systemd/systemd + command -v gnome-shell > /dev/null + gnome-shell --version | grep -qE "GNOME Shell 5[0-9]" + command -v gdm3 > /dev/null || test -x /usr/sbin/gdm3 + test -x /usr/local/bin/nucleic-a11y-agent + test -x /usr/local/bin/nucleic-linux-agent + test -f /usr/share/gnome-shell/extensions/nucleic-geometry@nucleic.xyz/metadata.json + grep -q "AutomaticLogin=agent" /etc/gdm3/daemon.conf' + ;; + + *) + echo "unknown flavor: $FLAVOR (expected base, vm, or vm-desktop)" >&2 + exit 2 + ;; +esac + +echo "smoke OK ($FLAVOR/$ARCH)"