#!/bin/sh # Probe host capabilities needed for a real login-manager deployment. # # This script never reports an unavailable capability as a pass. On an # ordinary container it prints SKIP and exits successfully; --strict turns # every SKIP into a failure for a prepared VM or privileged runner. set -u binary=${1:-} strict=0 if [ "${1:-}" = "--strict" ]; then strict=1 shift binary=${1:-} fi failures=0 skips=0 passes=0 pass() { passes=$((passes + 1)) printf 'PASS: %s\n' "$*" } skip() { skips=$((skips + 1)) printf 'SKIP: %s\n' "$*" } fail() { failures=$((failures + 1)) printf 'FAIL: %s\n' "$*" >&2 } need_command() { command -v "$1" >/dev/null 2>&1 } if [ -n "$binary" ]; then if [ ! -x "$binary" ]; then fail "latchd binary is not executable: $binary" else pass "latchd binary is available" fi else skip "latchd binary not supplied; capability-only probe" fi # This is deliberately a runtime capability check, not an authentication # claim. Authentication needs a disposable VM user and a test PAM policy. if need_command ldconfig && ldconfig -p 2>/dev/null | grep -q 'libpam\.so'; then pass "PAM runtime library is available" else skip "PAM runtime library is unavailable" fi if [ -n "$binary" ] && need_command nm && nm -D "$binary" 2>/dev/null | grep -q 'pam_chauthtok'; then pass "PAM password-change entry point is linked" else skip "PAM password-change entry point could not be inspected" fi if [ -r /etc/pam.d/latchd ]; then pass "latchd PAM policy is installed" else skip "latchd PAM policy is not installed (authentication E2E requires a provisioned VM)" fi if need_command faillock; then pass "faillock helper is available" else skip "faillock helper is unavailable" fi # A real VT is a character device and must be allocated by the host/VM. A # pseudo-terminal from CI is not equivalent and is intentionally not accepted. if [ -c /dev/tty0 ] && [ -d /sys/class/tty/tty0 ]; then pass "Linux virtual terminal device is available" else skip "Linux virtual terminal is unavailable (container or non-console host)" fi # Xvfb is a genuine X server and is safe to exercise without host display # access. If it is absent, this is a skip rather than a synthetic success. if need_command Xvfb; then display_number=$((100 + ($$ % 500))) display=":$display_number" xlog=${TMPDIR:-/tmp}/latchd-xvfb.$$.log Xvfb "$display" -screen 0 640x480x24 -nolisten tcp >"$xlog" 2>&1 & xvfb_pid=$! cleanup_xvfb() { kill "$xvfb_pid" >/dev/null 2>&1 || true wait "$xvfb_pid" >/dev/null 2>&1 || true rm -f "$xlog" } trap cleanup_xvfb EXIT HUP INT TERM ready=0 i=0 while [ "$i" -lt 20 ]; do if [ -S "/tmp/.X11-unix/X$display_number" ] && kill -0 "$xvfb_pid" 2>/dev/null; then ready=1 break fi i=$((i + 1)) sleep 0.1 done if [ "$ready" -eq 1 ]; then pass "X11 server starts in an isolated display ($display)" else fail "Xvfb did not start; see $xlog" fi cleanup_xvfb trap - EXIT HUP INT TERM else skip "Xvfb is unavailable" fi # A Wayland socket is meaningful only when a compositor owns it. Do not claim # Wayland support merely because a client library or executable is installed. wayland_socket= if [ -n "${WAYLAND_DISPLAY:-}" ] && [ -n "${XDG_RUNTIME_DIR:-}" ]; then case "$WAYLAND_DISPLAY" in /*) wayland_socket=$WAYLAND_DISPLAY ;; *) wayland_socket=$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY ;; esac fi if [ -n "$wayland_socket" ] && [ -S "$wayland_socket" ]; then pass "Wayland compositor socket is available ($wayland_socket)" else skip "Wayland compositor socket is unavailable (requires a compositor-backed VM/session)" fi # systemd-logind is not normally PID 1 in a Docker container. loginctl output # is checked only when the manager and seat are actually reachable. if need_command loginctl && [ -d /run/systemd/system ]; then if loginctl --no-pager show-seat seat0 >/dev/null 2>&1; then pass "systemd-logind seat0 is reachable" else fail "systemd-logind is present but seat0 is not reachable" fi else skip "systemd-logind seat0 is unavailable" fi printf 'E2E summary: pass=%s skip=%s fail=%s\n' "$passes" "$skips" "$failures" if [ "$failures" -ne 0 ]; then exit 1 fi if [ "$strict" -eq 1 ] && [ "$skips" -ne 0 ]; then echo "E2E strict mode: unavailable capabilities are errors" >&2 exit 2 fi exit 0