#!/bin/sh # banger-first-boot — runs once at the first boot of a pulled OCI image. # Installs openssh-server via the guest's native package manager, enables # and starts the ssh daemon, and removes its own trigger file so the # service is a no-op on subsequent boots. # # Distro dispatch is driven by /etc/os-release's ID / ID_LIKE values. # RUN_PLAN=1 in the environment makes this script echo the commands it # would run instead of executing them — used by tests. set -eu log() { printf '[banger-first-boot] %s\n' "$*" >&2; } MARKER="${BANGER_FIRST_BOOT_MARKER:-/var/lib/banger/first-boot-pending}" if [ ! -f "$MARKER" ]; then log "marker absent; nothing to do" exit 0 fi # If sshd is already present, just enable + start and finish. # The RUN_PLAN env skips this short-circuit so tests can exercise the # dispatch logic on hosts that happen to have sshd installed. if [ "${RUN_PLAN:-0}" != "1" ] && command -v sshd >/dev/null 2>&1; then log "sshd already installed; enabling and starting" systemctl enable --now ssh.service 2>/dev/null || \ systemctl enable --now sshd.service 2>/dev/null || true rm -f "$MARKER" exit 0 fi DIST="" FAMILY="" OS_RELEASE_FILE="${OS_RELEASE_FILE:-/etc/os-release}" if [ -r "$OS_RELEASE_FILE" ]; then # shellcheck source=/dev/null . "$OS_RELEASE_FILE" DIST="${ID:-}" FAMILY="${ID_LIKE:-}" fi log "detected distro: ID=$DIST ID_LIKE=$FAMILY" # Dispatch. Each branch sets CMD to the single install command. CMD="" case "$DIST" in debian|ubuntu|kali|raspbian|linuxmint|pop) CMD="env DEBIAN_FRONTEND=noninteractive apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-server" ;; alpine) CMD="apk add --no-cache openssh" ;; fedora|rhel|centos|rocky|almalinux) CMD="dnf install -y openssh-server" ;; arch|archlinux|manjaro) CMD="pacman -Sy --noconfirm openssh" ;; opensuse*|suse) CMD="zypper --non-interactive install -y openssh" ;; *) # Fall back to ID_LIKE. case " $FAMILY " in *" debian "*) CMD="env DEBIAN_FRONTEND=noninteractive apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-server" ;; *" rhel "* | *" fedora "*) CMD="dnf install -y openssh-server" ;; *" arch "*) CMD="pacman -Sy --noconfirm openssh" ;; *" suse "*) CMD="zypper --non-interactive install -y openssh" ;; esac ;; esac if [ -z "$CMD" ]; then log "no known install command for distro '$DIST' (ID_LIKE='$FAMILY')" log "edit /usr/local/libexec/banger-first-boot to add a branch, then restart banger-first-boot.service" exit 1 fi if [ "${RUN_PLAN:-0}" = "1" ]; then printf '%s\n' "$CMD" exit 0 fi log "installing openssh-server: $CMD" sh -c "$CMD" log "enabling sshd" systemctl enable --now ssh.service 2>/dev/null || \ systemctl enable --now sshd.service 2>/dev/null || \ { log "could not enable sshd service"; exit 1; } rm -f "$MARKER" log "first-boot provisioning complete"