Spaces:
Running
Running
feat: enhance nginx config validation script to track Dockerfile base and improve error messaging
Browse files- deploy/check-nginx.sh +48 -20
deploy/check-nginx.sh
CHANGED
|
@@ -12,44 +12,72 @@
|
|
| 12 |
# silently PASSES the exact config that breaks production β a false safety net.
|
| 13 |
# So we build a throwaway image from the same base + package as the Dockerfile.
|
| 14 |
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
# Usage: bash deploy/check-nginx.sh
|
|
|
|
| 16 |
# Requires Docker. Exits non-zero when the config is invalid.
|
| 17 |
set -euo pipefail
|
| 18 |
|
| 19 |
cd "$(dirname "$0")/.."
|
| 20 |
|
| 21 |
-
|
|
|
|
| 22 |
|
| 23 |
-
#
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
DOCKERFILE
|
| 31 |
fi
|
| 32 |
|
| 33 |
-
#
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
RENDERED="$(pwd)/${RENDERED_NAME}"
|
| 37 |
-
trap 'rm -f "$RENDERED"' EXIT
|
| 38 |
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
# Docker Desktop needs a Windows-style path; `pwd -W` provides it under Git Bash
|
| 43 |
# and is simply absent elsewhere, where the POSIX path already works.
|
| 44 |
HOST_DIR="$(pwd -W 2>/dev/null || pwd)"
|
| 45 |
|
| 46 |
-
echo "Validating
|
| 47 |
|
|
|
|
|
|
|
| 48 |
if MSYS_NO_PATHCONV=1 docker run --rm \
|
| 49 |
-
-
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
| 51 |
echo "OK β nginx accepts the rendered config."
|
| 52 |
else
|
| 53 |
-
echo "FAILED β fix
|
| 54 |
exit 1
|
| 55 |
fi
|
|
|
|
| 12 |
# silently PASSES the exact config that breaks production β a false safety net.
|
| 13 |
# So we build a throwaway image from the same base + package as the Dockerfile.
|
| 14 |
#
|
| 15 |
+
# That reasoning only holds if the validator TRACKS the Dockerfile. Two things
|
| 16 |
+
# enforce it: the base image is read out of the Dockerfile rather than
|
| 17 |
+
# duplicated here, and the image tag is a hash of the recipe β change the base
|
| 18 |
+
# or the package list and the tag changes, so a stale image cannot be reused.
|
| 19 |
+
#
|
| 20 |
+
# Rendering runs inside the container with envsubst, exactly as deploy/start.sh
|
| 21 |
+
# does it. Rendering differently here would validate a file production never
|
| 22 |
+
# builds β the same false safety net in another disguise.
|
| 23 |
+
#
|
| 24 |
# Usage: bash deploy/check-nginx.sh
|
| 25 |
+
# NGINX_PORT=8080 bash deploy/check-nginx.sh
|
| 26 |
# Requires Docker. Exits non-zero when the config is invalid.
|
| 27 |
set -euo pipefail
|
| 28 |
|
| 29 |
cd "$(dirname "$0")/.."
|
| 30 |
|
| 31 |
+
TEMPLATE="deploy/nginx.conf.template"
|
| 32 |
+
[ -f "$TEMPLATE" ] || { echo "Missing ${TEMPLATE}" >&2; exit 2; }
|
| 33 |
|
| 34 |
+
# The port reaches nginx through envsubst, so a hostile value cannot break out
|
| 35 |
+
# of the template β but a typo'd port fails deep inside `nginx -t` with an
|
| 36 |
+
# opaque message. Reject it here, where the error can name the cause.
|
| 37 |
+
NGINX_PORT="${NGINX_PORT:-8501}"
|
| 38 |
+
if ! [[ "$NGINX_PORT" =~ ^[0-9]+$ ]] || [ "$NGINX_PORT" -lt 1 ] || [ "$NGINX_PORT" -gt 65535 ]; then
|
| 39 |
+
echo "NGINX_PORT must be a number in 1-65535 (got: '${NGINX_PORT}')" >&2
|
| 40 |
+
exit 2
|
|
|
|
| 41 |
fi
|
| 42 |
|
| 43 |
+
# Track the Dockerfile's base rather than hardcoding it a second time.
|
| 44 |
+
BASE_IMAGE="$(awk '/^FROM /{print $2; exit}' Dockerfile)"
|
| 45 |
+
[ -n "$BASE_IMAGE" ] || { echo "Could not read a FROM line from Dockerfile" >&2; exit 2; }
|
|
|
|
|
|
|
| 46 |
|
| 47 |
+
# Mirrors the Dockerfile: same base, same nginx + gettext-base packages, and the
|
| 48 |
+
# same removal of Debian's default site (which otherwise occupies port 80 and is
|
| 49 |
+
# not what production serves).
|
| 50 |
+
RECIPE="FROM ${BASE_IMAGE}
|
| 51 |
+
RUN apt-get update && apt-get install -y --no-install-recommends nginx gettext-base \\
|
| 52 |
+
&& rm -rf /var/lib/apt/lists/* \\
|
| 53 |
+
&& rm -f /etc/nginx/sites-enabled/default"
|
| 54 |
+
|
| 55 |
+
# Tagging by recipe hash is what makes reuse safe: a different base or package
|
| 56 |
+
# set is a different tag, so `docker image inspect` misses and rebuilds.
|
| 57 |
+
RECIPE_HASH="$(printf '%s' "$RECIPE" | sha1sum | cut -c1-12)"
|
| 58 |
+
VALIDATOR_IMAGE="researchrag-nginx-validator:${RECIPE_HASH}"
|
| 59 |
+
|
| 60 |
+
if ! docker image inspect "$VALIDATOR_IMAGE" >/dev/null 2>&1; then
|
| 61 |
+
echo "Building validator image for ${BASE_IMAGE} (${RECIPE_HASH})β¦"
|
| 62 |
+
printf '%s\n' "$RECIPE" | docker build -t "$VALIDATOR_IMAGE" -f - . >/dev/null
|
| 63 |
+
fi
|
| 64 |
|
| 65 |
# Docker Desktop needs a Windows-style path; `pwd -W` provides it under Git Bash
|
| 66 |
# and is simply absent elsewhere, where the POSIX path already works.
|
| 67 |
HOST_DIR="$(pwd -W 2>/dev/null || pwd)"
|
| 68 |
|
| 69 |
+
echo "Validating ${TEMPLATE} (NGINX_PORT=${NGINX_PORT})β¦"
|
| 70 |
|
| 71 |
+
# envsubst with an explicit variable list, matching deploy/start.sh, so nginx
|
| 72 |
+
# sees precisely the file the container will serve.
|
| 73 |
if MSYS_NO_PATHCONV=1 docker run --rm \
|
| 74 |
+
-e "NGINX_PORT=${NGINX_PORT}" \
|
| 75 |
+
-v "${HOST_DIR}/${TEMPLATE}:/tmp/nginx.conf.template:ro" \
|
| 76 |
+
"$VALIDATOR_IMAGE" \
|
| 77 |
+
sh -c 'envsubst "\${NGINX_PORT}" < /tmp/nginx.conf.template \
|
| 78 |
+
> /etc/nginx/conf.d/default.conf && nginx -t' 2>&1 | sed 's/^/ /'; then
|
| 79 |
echo "OK β nginx accepts the rendered config."
|
| 80 |
else
|
| 81 |
+
echo "FAILED β fix ${TEMPLATE} before deploying." >&2
|
| 82 |
exit 1
|
| 83 |
fi
|