#!/bin/sh
## semurg-cluster-preflight (RR-13, desktop-de 2026-09-29): THE ONE CHECK of a cluster-mode node's boot prerequisites.
## Two callers, one implementation (Law 0):
##   * rel/env.sh.eex SOURCES this file and calls semurg_cluster_preflight at every boot of a cluster-mode node: a
##     failure is that boot's refusal (exit 78 = EX_CONFIG; the unit's RestartPreventExitStatus=78 makes it final);
##   * semurg-install.sh RUNS it before it writes the unit or starts anything, so a cluster install that cannot come up
##     is refused BEFORE the start, naming EVERY missing prerequisite at once (the audit's RR-13: the documented
##     SEMURG_CLUSTER=1 install crash-looped because the installer provisioned none of these and checked none).
## PURE: it reads the environment, the wg0 address and the release's vm.args / flag sources; it writes nothing, starts
## nothing, and never prints a secret. One line per failure, "semurg: <message> [refused:<tag>]", on stderr (the tags
## are env.sh's, unchanged); returns 78 when any failed, 0 otherwise, and leaves WG0_IP set for the sourcing env.sh.
## Provisioning wg0 (keys, peers, the firewall) is the JOIN DOOR's work, never this file's: a fresh install is a cluster of
## one, and a node is added through a join token.
semurg_cluster_preflight() {
  semurg_pf_bad=0
  WG0_IP="$(ip -4 -o addr show wg0 2>/dev/null | awk '{print $4}' | cut -d/ -f1 | head -n1)"
  if [ -z "${WG0_IP}" ]; then
    echo "semurg: cluster mode requires the WireGuard interface wg0, which is not present; refusing to start distribution. Bring up wg0, or unset SEMURG_CLUSTER and SEMURG_PEERS to run a standalone node. [refused:dist_not_on_wg0]" >&2
    semurg_pf_bad=1
  fi
  if [ -z "${SEMURG_DIST_PORT_MIN:-}" ] || [ -z "${SEMURG_DIST_PORT_MAX:-}" ]; then
    echo "semurg: cluster mode requires a pinned distribution port range (SEMURG_DIST_PORT_MIN and SEMURG_DIST_PORT_MAX), the range the firewall allows on wg0 [refused:join_refused]" >&2
    semurg_pf_bad=1
  fi
  if [ "${SEMURG_JOIN_ROLE:-}" = "authority" ] && [ -z "${SEMURG_JOIN_AUTHORITY_KEY_DIR:-}" ]; then
    echo "semurg: the join authority needs SEMURG_JOIN_AUTHORITY_KEY_DIR [refused:join_refused]" >&2
    semurg_pf_bad=1
  fi
  ## Review 82 MUST-2 / S-3: no cookie source but env.sh's own may exist (the release's vm.args, RELEASE_VM_ARGS, the flag
  ## variables, and any -args_file they name).
  for semurg_vmargs in "${RELEASE_VM_ARGS:-}" "${RELEASE_ROOT:-}/releases/${RELEASE_VSN:-}/vm.args"; do
    if [ -n "${semurg_vmargs}" ] && [ -r "${semurg_vmargs}" ] && grep -qE -- "^[[:space:]]*-setcookie" "${semurg_vmargs}"; then
      echo "semurg: ${semurg_vmargs} carries -setcookie; remove it in cluster mode (cookie_source_conflict) [refused:join_refused]" >&2
      semurg_pf_bad=1
    fi
  done
  for semurg_flags in "${ERL_FLAGS:-}" "${ERL_AFLAGS:-}" "${ERL_ZFLAGS:-}" "${ELIXIR_ERL_OPTIONS:-}"; do
    case " ${semurg_flags} " in *" -setcookie "*)
      echo "semurg: a -setcookie in ERL_FLAGS/ERL_AFLAGS/ERL_ZFLAGS/ELIXIR_ERL_OPTIONS; in cluster mode the cookie is set only by env.sh (cookie_source_conflict) [refused:join_refused]" >&2
      semurg_pf_bad=1 ;;
    esac
    semurg_next=0
    for semurg_tok in ${semurg_flags}; do
      if [ "${semurg_next}" = 1 ] && [ -r "${semurg_tok}" ] && grep -q -- "-setcookie" "${semurg_tok}"; then
        echo "semurg: an -args_file (${semurg_tok}) carries -setcookie; remove it in cluster mode (cookie_source_conflict) [refused:join_refused]" >&2
        semurg_pf_bad=1
      fi
      if [ "${semurg_tok}" = "-args_file" ]; then semurg_next=1; else semurg_next=0; fi
    done
  done
  [ "${semurg_pf_bad}" = 0 ] || return 78
  return 0
}

## Run directly (the installer): check and exit with the verdict. Sourced (env.sh): only define the function.
case "${0##*/}" in semurg-cluster-preflight) semurg_cluster_preflight; exit $? ;; esac
