riezqidr commited on
Commit
8e2b5e2
Β·
1 Parent(s): 73db263

feat: enhance nginx config validation script to track Dockerfile base and improve error messaging

Browse files
Files changed (1) hide show
  1. 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
- VALIDATOR_IMAGE="researchrag-nginx-validator:latest"
 
22
 
23
- # Build once, reuse thereafter (a few seconds when cached).
24
- if ! docker image inspect "$VALIDATOR_IMAGE" >/dev/null 2>&1; then
25
- echo "Building validator image (mirrors Dockerfile's nginx install)…"
26
- docker build -t "$VALIDATOR_IMAGE" -f - . >/dev/null <<'DOCKERFILE'
27
- FROM python:3.11-slim
28
- RUN apt-get update && apt-get install -y --no-install-recommends nginx gettext-base \
29
- && rm -rf /var/lib/apt/lists/*
30
- DOCKERFILE
31
  fi
32
 
33
- # Render next to the repo rather than /tmp: on Git Bash / Docker Desktop a
34
- # /tmp path is an MSYS path the daemon cannot bind-mount.
35
- RENDERED_NAME=".nginx-check.conf"
36
- RENDERED="$(pwd)/${RENDERED_NAME}"
37
- trap 'rm -f "$RENDERED"' EXIT
38
 
39
- NGINX_PORT="${NGINX_PORT:-8501}"
40
- sed "s|\${NGINX_PORT}|${NGINX_PORT}|g" deploy/nginx.conf.template > "$RENDERED"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 deploy/nginx.conf.template (NGINX_PORT=${NGINX_PORT})…"
47
 
 
 
48
  if MSYS_NO_PATHCONV=1 docker run --rm \
49
- -v "${HOST_DIR}/${RENDERED_NAME}:/etc/nginx/conf.d/default.conf:ro" \
50
- "$VALIDATOR_IMAGE" nginx -t 2>&1 | sed 's/^/ /'; then
 
 
 
51
  echo "OK β€” nginx accepts the rendered config."
52
  else
53
- echo "FAILED β€” fix deploy/nginx.conf.template before deploying." >&2
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