diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3c0288a09..f2e35ebfa 100755 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -20,7 +20,7 @@ # # This file can be built with `docker-compose -f docker-compose.yml up --build --force-recreate` -FROM alpine:3.22 AS builder +FROM alpine:3.24 AS builder ARG INSTALL_DIR=/app @@ -53,7 +53,7 @@ RUN python -m pip install --upgrade pip setuptools wheel && \ # second stage is the main runtime stage with just the minimum required to run the application # The runner is used for both devcontainer, and as a base for the hardened stage. -FROM alpine:3.22 AS runner +FROM alpine:3.24 AS runner ARG INSTALL_DIR=/app # Runtime service account (override at build; container user can still be overridden at run time) @@ -119,7 +119,7 @@ ENV READ_WRITE_FOLDERS="${NETALERTX_DATA} ${NETALERTX_CONFIG} ${NETALERTX_DB} ${ ENV PYTHONUNBUFFERED=1 ENV VIRTUAL_ENV=/opt/venv ENV VIRTUAL_ENV_BIN=/opt/venv/bin -ENV PYTHONPATH=${NETALERTX_APP}:${NETALERTX_SERVER}:${NETALERTX_PLUGINS}:${VIRTUAL_ENV}/lib/python3.12/site-packages +ENV PYTHONPATH=${NETALERTX_APP}:${NETALERTX_SERVER}:${NETALERTX_PLUGINS}:${VIRTUAL_ENV}/lib/python3.14/site-packages ENV PATH="${SYSTEM_SERVICES}:${VIRTUAL_ENV_BIN}:$PATH" # App Environment @@ -134,9 +134,11 @@ ENV NETALERTX_USER=netalertx NETALERTX_GROUP=netalertx ENV LANG=C.UTF-8 +# PHP 8.3.36 fixes CVE-2026-109618 and CVE-2026-109619. RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss iw nmap fping \ nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \ - sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 py3-psutil envsubst \ + sqlite 'php83>=8.3.36' 'php83-fpm>=8.3.36' 'php83-cgi>=8.3.36' \ + 'php83-curl>=8.3.36' 'php83-sqlite3>=8.3.36' 'php83-session>=8.3.36' python3 py3-psutil envsubst \ nginx supercronic shadow su-exec jq && \ rm -Rf /var/cache/apk/* && \ rm -Rf /etc/nginx && \ @@ -264,7 +266,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ FROM runner AS netalertx-devcontainer ENV INSTALL_DIR=/app -ENV PYTHONPATH=${PYTHONPATH}:/workspaces/NetAlertX/test:/workspaces/NetAlertX/server:/usr/lib/python3.12/site-packages +ENV PYTHONPATH=${PYTHONPATH}:/workspaces/NetAlertX/test:/workspaces/NetAlertX/server:/usr/lib/python3.14/site-packages ENV PATH=/services:${PATH} ENV PHP_INI_SCAN_DIR=/services/config/php/conf.d:/etc/php83/conf.d ENV LISTEN_ADDR=0.0.0.0 diff --git a/.devcontainer/resources/devcontainer-Dockerfile b/.devcontainer/resources/devcontainer-Dockerfile index e65f6f80f..59a0d9a4c 100755 --- a/.devcontainer/resources/devcontainer-Dockerfile +++ b/.devcontainer/resources/devcontainer-Dockerfile @@ -11,7 +11,7 @@ FROM runner AS netalertx-devcontainer ENV INSTALL_DIR=/app -ENV PYTHONPATH=${PYTHONPATH}:/workspaces/NetAlertX/test:/workspaces/NetAlertX/server:/usr/lib/python3.12/site-packages +ENV PYTHONPATH=${PYTHONPATH}:/workspaces/NetAlertX/test:/workspaces/NetAlertX/server:/usr/lib/python3.14/site-packages ENV PATH=/services:${PATH} ENV PHP_INI_SCAN_DIR=/services/config/php/conf.d:/etc/php83/conf.d ENV LISTEN_ADDR=0.0.0.0 diff --git a/Dockerfile b/Dockerfile index 6d606f766..1aa5bfc2a 100755 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ # # This file can be built with `docker-compose -f docker-compose.yml up --build --force-recreate` -FROM alpine:3.22 AS builder +FROM alpine:3.24 AS builder ARG INSTALL_DIR=/app @@ -50,7 +50,7 @@ RUN python -m pip install --upgrade pip setuptools wheel && \ # second stage is the main runtime stage with just the minimum required to run the application # The runner is used for both devcontainer, and as a base for the hardened stage. -FROM alpine:3.22 AS runner +FROM alpine:3.24 AS runner ARG INSTALL_DIR=/app # Runtime service account (override at build; container user can still be overridden at run time) @@ -116,7 +116,7 @@ ENV READ_WRITE_FOLDERS="${NETALERTX_DATA} ${NETALERTX_CONFIG} ${NETALERTX_DB} ${ ENV PYTHONUNBUFFERED=1 ENV VIRTUAL_ENV=/opt/venv ENV VIRTUAL_ENV_BIN=/opt/venv/bin -ENV PYTHONPATH=${NETALERTX_APP}:${NETALERTX_SERVER}:${NETALERTX_PLUGINS}:${VIRTUAL_ENV}/lib/python3.12/site-packages +ENV PYTHONPATH=${NETALERTX_APP}:${NETALERTX_SERVER}:${NETALERTX_PLUGINS}:${VIRTUAL_ENV}/lib/python3.14/site-packages ENV PATH="${SYSTEM_SERVICES}:${VIRTUAL_ENV_BIN}:$PATH" # App Environment @@ -131,9 +131,11 @@ ENV NETALERTX_USER=netalertx NETALERTX_GROUP=netalertx ENV LANG=C.UTF-8 +# PHP 8.3.36 fixes CVE-2026-109618 and CVE-2026-109619. RUN apk add --no-cache bash mtr libbsd zip lsblk tzdata curl arp-scan iproute2 iproute2-ss iw nmap fping \ nmap-scripts traceroute nbtscan net-tools net-snmp-tools bind-tools awake ca-certificates \ - sqlite php83 php83-fpm php83-cgi php83-curl php83-sqlite3 php83-session python3 py3-psutil envsubst \ + sqlite 'php83>=8.3.36' 'php83-fpm>=8.3.36' 'php83-cgi>=8.3.36' \ + 'php83-curl>=8.3.36' 'php83-sqlite3>=8.3.36' 'php83-session>=8.3.36' python3 py3-psutil envsubst \ nginx supercronic shadow su-exec jq && \ rm -Rf /var/cache/apk/* && \ rm -Rf /etc/nginx && \ diff --git a/test/runtime/test_php_runtime.py b/test/runtime/test_php_runtime.py new file mode 100644 index 000000000..013251075 --- /dev/null +++ b/test/runtime/test_php_runtime.py @@ -0,0 +1,32 @@ +"""Check the PHP runtime installed in the Docker test environment.""" + +import os +import re +import shutil +import subprocess + +import pytest + + +pytestmark = pytest.mark.skipif( + os.environ.get("ENVIRONMENT") != "alpine", + reason="PHP package checks require the Alpine Docker environment", +) + + +@pytest.mark.parametrize("binary", ["php83", "php-fpm83", "php-cgi83"]) +def test_php_security_version(binary): + """Require the PHP 8.3 security release in every installed SAPI.""" + executable = shutil.which(binary) + assert executable is not None, f"Missing required PHP binary: {binary}" + + result = subprocess.run( + [executable, "-v"], capture_output=True, text=True, check=True, timeout=60 + ) + match = re.search(r"PHP (\d+)\.(\d+)\.(\d+)", result.stdout) + assert match is not None, result.stdout + version = tuple(int(part) for part in match.groups()) + assert version[:2] == (8, 3), f"Unexpected PHP branch for {binary}: {result.stdout}" + assert version >= (8, 3, 36), ( + f"{binary} is affected by CVE-2026-109618/CVE-2026-109619: {result.stdout}" + ) diff --git a/test/ui/test_ui_devices.py b/test/ui/test_ui_devices.py index aef75df89..877c39aad 100644 --- a/test/ui/test_ui_devices.py +++ b/test/ui/test_ui_devices.py @@ -7,6 +7,8 @@ Tests device details page, field updates, and delete operations import sys import os from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait # Add test directory to path sys.path.insert(0, os.path.dirname(__file__)) @@ -117,7 +119,9 @@ def test_add_device_with_generated_mac_ip(driver, api_token): assert test_ip, "IP should be generated" # --- Fill Name --- - name_field = driver.find_element(By.ID, "NEWDEV_devName") + name_field = WebDriverWait(driver, 10).until( + EC.element_to_be_clickable((By.ID, "NEWDEV_devName")) + ) name_field.clear() name_field.send_keys("Test Device Selenium")