#!/usr/bin/env bash
# Per-flavor rootfs smoke test (NAROS.md §10.3).
#
#   smoke-rootfs.sh <flavor> <image> <arch>
#
# <flavor> is the build-rootfs.sh tier: base | vm | vm-desktop.
# <image>  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).
# <arch>   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 <flavor> <image> <arch>}"
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
  # nash trusted policy (NASH.md §4.3): present, root-owned, not group/other-writable —
  # the three properties nash checks before it honors an operator lever. A packaging
  # slip on any of them silently returns the levers to nobody (or, worse, to the agent).
  test -f /etc/nucleic/nash.conf
  grep -q "^require_observation=1" /etc/nucleic/nash.conf
  test "$(stat -c %u:%a /etc/nucleic/nash.conf)" = "0:644"
  # The bypass the image used to publish to every shell it started.
  ! grep -rq NUCLEIC_REAL_BASH /etc/profile.d/
'

# 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
      # Swift comes from forky swiftlang here (vm-desktop.pkgs), so assert the compiler
      # actually loads — a soname drift in the pocket (the libxml2 .so.2→.so.16 kind) would
      # otherwise ship a Swift that only fails the first time an agent invokes it.
      swiftc --version > /dev/null'
    ;;

  *)
    echo "unknown flavor: $FLAVOR (expected base, vm, or vm-desktop)" >&2
    exit 2
    ;;
esac

echo "smoke OK ($FLAVOR/$ARCH)"
