From 0851680ef6da479018c48bc54f71dfdc8f7c9725 Mon Sep 17 00:00:00 2001 From: Adam Outler Date: Wed, 22 Oct 2025 23:51:36 +0000 Subject: [PATCH] Add additional startup checks --- .../services/scripts/check-network-mode.sh | 55 +++++++++++++++++++ .../services/scripts/check-nginx-config.sh | 50 +++++++++++++++++ .../services/scripts/check-storage-extra.sh | 40 ++++++++++++++ .../services/scripts/check-user-netalertx.sh | 42 ++++++++++++++ 4 files changed, 187 insertions(+) create mode 100755 install/production-filesystem/services/scripts/check-network-mode.sh create mode 100755 install/production-filesystem/services/scripts/check-nginx-config.sh create mode 100755 install/production-filesystem/services/scripts/check-storage-extra.sh create mode 100755 install/production-filesystem/services/scripts/check-user-netalertx.sh diff --git a/install/production-filesystem/services/scripts/check-network-mode.sh b/install/production-filesystem/services/scripts/check-network-mode.sh new file mode 100755 index 00000000..886a40ac --- /dev/null +++ b/install/production-filesystem/services/scripts/check-network-mode.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# check-network-mode.sh - detect when the container is not using host networking. + +DEFAULT_IF="$(ip route show default 0.0.0.0/0 2>/dev/null | awk 'NR==1 {print $5}')" +if [ -z "${DEFAULT_IF}" ]; then + # No default route; nothing to validate. + exit 0 +fi + +IF_LINK_INFO="$(ip link show "${DEFAULT_IF}" 2>/dev/null)" +IF_IP="$(ip -4 addr show "${DEFAULT_IF}" 2>/dev/null | awk '/inet / {print $2}' | head -n1)" +IF_MAC="" +if [ -r "/sys/class/net/${DEFAULT_IF}/address" ]; then + IF_MAC="$(cat "/sys/class/net/${DEFAULT_IF}/address")" +fi + +looks_like_bridge="0" + +case "${IF_MAC}" in + 02:42:*) looks_like_bridge="1" ;; + 00:00:00:00:00:00) looks_like_bridge="1" ;; + "") ;; # leave as is +esac + +case "${IF_IP}" in + 172.1[6-9].*|172.2[0-9].*|172.3[0-1].*) looks_like_bridge="1" ;; + 192.168.65.*) looks_like_bridge="1" ;; +esac + +if echo "${IF_LINK_INFO}" | grep -q "@if"; then + looks_like_bridge="1" +fi + +if [ "${looks_like_bridge}" -ne 1 ]; then + exit 0 +fi + +YELLOW=$(printf '\033[1;33m') +RESET=$(printf '\033[0m') +>&2 printf "%s" "${YELLOW}" +>&2 cat <&2 printf "%s" "${RESET}" +exit 1 diff --git a/install/production-filesystem/services/scripts/check-nginx-config.sh b/install/production-filesystem/services/scripts/check-nginx-config.sh new file mode 100755 index 00000000..6b2e6e9e --- /dev/null +++ b/install/production-filesystem/services/scripts/check-nginx-config.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# check-nginx-config.sh - verify nginx conf.active mount is writable when startup needs to render config. + +CONF_ACTIVE_DIR="${SYSTEM_NGINX_CONFIG}/conf.active" +TARGET_FILE="${CONF_ACTIVE_DIR}/netalertx.conf" + +# If the directory is missing entirely we warn and exit failure so the caller can see the message. +if [ ! -d "${CONF_ACTIVE_DIR}" ]; then + YELLOW=$(printf '\033[1;33m') + RESET=$(printf '\033[0m') + >&2 printf "%s" "${YELLOW}" + >&2 cat <&2 printf "%s" "${RESET}" + exit 1 +fi + +TMP_FILE="${CONF_ACTIVE_DIR}/.netalertx-write-test" +if ! ( : >"${TMP_FILE}" ) 2>/dev/null; then + YELLOW=$(printf '\033[1;33m') + RESET=$(printf '\033[0m') + >&2 printf "%s" "${YELLOW}" + >&2 cat <&2 printf "%s" "${RESET}" + exit 1 +fi +rm -f "${TMP_FILE}" + +exit 0 diff --git a/install/production-filesystem/services/scripts/check-storage-extra.sh b/install/production-filesystem/services/scripts/check-storage-extra.sh new file mode 100755 index 00000000..6f808298 --- /dev/null +++ b/install/production-filesystem/services/scripts/check-storage-extra.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# check-storage-extra.sh - ensure additional NetAlertX directories are persistent mounts. + +warn_if_not_persistent_mount() { + path="$1" + label="$2" + if awk -v target="${path}" '$5 == target {found=1} END {exit found ? 0 : 1}' /proc/self/mountinfo; then + return 0 + fi + + failures=1 + YELLOW=$(printf '\033[1;33m') + RESET=$(printf '\033[0m') + >&2 printf "%s" "${YELLOW}" + >&2 cat <&2 printf "%s" "${RESET}" +} + +failures=0 +warn_if_not_persistent_mount "${NETALERTX_LOG}" "Logs" +warn_if_not_persistent_mount "${NETALERTX_API}" "API JSON cache" +warn_if_not_persistent_mount "${SYSTEM_SERVICES_RUN}" "Runtime work directory" + +if [ "${failures}" -ne 0 ]; then + sleep 5 + exit 1 +fi + +exit 0 diff --git a/install/production-filesystem/services/scripts/check-user-netalertx.sh b/install/production-filesystem/services/scripts/check-user-netalertx.sh new file mode 100755 index 00000000..937538c6 --- /dev/null +++ b/install/production-filesystem/services/scripts/check-user-netalertx.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# check-user-netalertx.sh - ensure the container is running as the hardened service user. + +EXPECTED_USER="${NETALERTX_USER:-netalertx}" +EXPECTED_UID="$(getent passwd "${EXPECTED_USER}" 2>/dev/null | cut -d: -f3)" +EXPECTED_GID="$(getent passwd "${EXPECTED_USER}" 2>/dev/null | cut -d: -f4)" +CURRENT_UID="$(id -u)" +CURRENT_GID="$(id -g)" + +# Fallback to known defaults when lookups fail +if [ -z "${EXPECTED_UID}" ]; then + EXPECTED_UID="20211" +fi +if [ -z "${EXPECTED_GID}" ]; then + EXPECTED_GID="20211" +fi + +if [ "${CURRENT_UID}" -eq "${EXPECTED_UID}" ] && [ "${CURRENT_GID}" -eq "${EXPECTED_GID}" ]; then + exit 0 +fi + +YELLOW=$(printf '\033[1;33m') +RESET=$(printf '\033[0m') +>&2 printf "%s" "${YELLOW}" +>&2 cat < ${EXPECTED_UID}:${EXPECTED_GID}). + When you override the container user (for example, docker run --user 1000:1000 + or a Compose "user:" directive), NetAlertX loses crucial safeguards and + future upgrades may silently fail. + + Restore the container to the default user: + * Remove any custom --user flag + * Delete "user:" overrides in compose files + * Recreate the container so volume ownership is reset +══════════════════════════════════════════════════════════════════════════════ +EOF +>&2 printf "%s" "${RESET}" +exit 1