4NK_env/scripts/deploy_front_ext.sh

144 lines
5.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Deploy lecoffre-front (ext) via CI image and validate environment & CORS/state
#
# Usage:
# scripts/deploy_front_ext.sh [--ci] [--no-pull] [--no-up] [--validate-only]
#
# Behavior:
# - By default pulls CI image and restarts only the frontend service, then validates:
# 1) NEXT_PUBLIC_* variables in running app match lecoffre_node/.env.master
# 2) CORS preflight on dev3 OK (204) with Access-Control-Allow-Origin for dev4
# 3) POST /api/v1/idnot/state on dev3 OK (200) and returns a state
# - --ci: print a reminder to push branch/tag ext to trigger CI (no git ops here for safety)
# - --no-pull: skip docker compose pull
# - --no-up: skip docker compose up (restart)
# - --validate-only: skip pull & up, run validations only
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
NODE_DIR="$ROOT_DIR/lecoffre_node"
DO_PULL=1
DO_UP=1
DO_CI_HINT=0
for arg in "$@"; do
case "$arg" in
--ci) DO_CI_HINT=1 ;;
--no-pull) DO_PULL=0 ;;
--no-up) DO_UP=0 ;;
--validate-only) DO_PULL=0; DO_UP=0 ;;
*) echo "Unknown arg: $arg" >&2; exit 2 ;;
esac
done
if [[ $DO_CI_HINT -eq 1 ]]; then
echo "[HINT] Trigger CI by pushing branch 'ext' and tag 'ext' with commit message prefix 'ci: docker_tag=ext' (no git ops run by this script)."
fi
if [[ ! -f "$NODE_DIR/.env.master" ]]; then
echo "[ERROR] Missing $NODE_DIR/.env.master" >&2
exit 1
fi
# Pull and up only the frontend service
if [[ $DO_PULL -eq 1 ]]; then
echo "[STEP] docker compose pull lecoffre-front"
(cd "$NODE_DIR" && docker compose pull lecoffre-front)
fi
if [[ $DO_UP -eq 1 ]]; then
echo "[STEP] docker compose up -d --no-deps lecoffre-front"
(cd "$NODE_DIR" && docker compose up -d --no-deps lecoffre-front)
fi
# Wait for front to respond
FRONT_URL="http://localhost:3004"
echo "[STEP] Waiting for $FRONT_URL to be ready..."
ATTEMPTS=40
until curl -fsS "$FRONT_URL/" >/dev/null 2>&1; do
ATTEMPTS=$((ATTEMPTS-1)) || true
if [[ $ATTEMPTS -le 0 ]]; then
echo "[ERROR] Frontend not responding on $FRONT_URL" >&2
exit 1
fi
sleep 2
done
echo "[OK] Frontend is responding"
# 0) Public URL sanity check (dev4) to catch 404/misrouting early
echo "[STEP] Public URL check https://dev4.4nkweb.com/lecoffre (expect 301->/lecoffre/)"
PUB_RESP=$(curl -siS "https://dev4.4nkweb.com/lecoffre?nocache=$(date +%s)" 2>/dev/null | sed -n '1,20p')
echo "${PUB_RESP}"
echo "${PUB_RESP}" | grep -qE "^HTTP/(1.1|2) 301" || { echo "[FAIL] Public URL /lecoffre not 301" >&2; exit 1; }
echo "${PUB_RESP}" | grep -qi "^location: .*?/lecoffre/" || { echo "[FAIL] /lecoffre does not redirect to /lecoffre/" >&2; exit 1; }
echo "[OK] /lecoffre redirects to /lecoffre/"
echo "[STEP] Public URL check https://dev4.4nkweb.com/lecoffre/ (expect 200)"
PUB_RESP_SLASH=$(curl -siS "https://dev4.4nkweb.com/lecoffre/?nocache=$(date +%s)" 2>/dev/null | sed -n '1,20p')
echo "${PUB_RESP_SLASH}"
echo "${PUB_RESP_SLASH}" | grep -qE "^HTTP/(1.1|2) 200" || { echo "[FAIL] Public URL /lecoffre/ not 200" >&2; exit 1; }
echo "[OK] /lecoffre/ returns 200"
# 1) Validate NEXT_PUBLIC_* variables against .env.master (container env is source of truth)
echo "[STEP] Validating NEXT_PUBLIC_* variables vs .env.master (container env)"
if ! command -v jq >/dev/null 2>&1; then
echo "[ERROR] jq is required for validation" >&2
exit 1
fi
# Extract NEXT_PUBLIC_* from .env.master (ignore comments/blank)
mapfile -t FILE_KVS < <(grep -E '^[[:space:]]*NEXT_PUBLIC_[A-Za-z0-9_]+=' "$NODE_DIR/.env.master" | sed 's/^[[:space:]]*//' | sort)
MISMATCH=0
for kv in "${FILE_KVS[@]}"; do
key="${kv%%=*}"
expect="${kv#*=}"
# Normalize line endings and trim surrounding quotes if any
expect="$(printf '%s' "$expect" | tr -d '\r' | sed 's/^\"//; s/\"$//')"
# Read from running env
# Read from container environment (single source of truth at runtime)
actual="$(cd "$NODE_DIR" && docker compose exec -T lecoffre-front /bin/sh -lc "env | grep -E '^${key}=' | head -n1 | sed 's/^${key}=//'" || true)"
if [[ "$actual" != "$expect" ]]; then
echo "[MISMATCH] $key: running='$actual' vs .env.master='$expect'"
MISMATCH=1
fi
done
if [[ $MISMATCH -ne 0 ]]; then
echo "[FAIL] NEXT_PUBLIC_* variables mismatch."
exit 1
fi
echo "[OK] NEXT_PUBLIC_* variables match .env.master"
# 2) CORS preflight check on dev3
echo "[STEP] CORS preflight (OPTIONS) to dev3 idnot/state"
PRE="$(curl -i -X OPTIONS 'https://dev3.4nkweb.com/api/v1/idnot/state' \
-H 'Origin: https://dev4.4nkweb.com' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type' 2>/dev/null | sed -n '1,20p')"
echo "$PRE"
echo "$PRE" | grep -q "^HTTP/1.1 204" || { echo "[FAIL] Preflight not 204" >&2; exit 1; }
echo "$PRE" | grep -qi "Access-Control-Allow-Origin: https://dev4.4nkweb.com" || { echo "[FAIL] A-C-A-Origin not dev4" >&2; exit 1; }
echo "[OK] Preflight CORS ok"
# 3) POST state on dev3
echo "[STEP] POST state to dev3"
STATE_RESP="$(curl -i -X POST 'https://dev3.4nkweb.com/api/v1/idnot/state' \
-H 'Origin: https://dev4.4nkweb.com' \
-H 'Content-Type: application/json' \
--data '{"next_url":"https://dev4.4nkweb.com/lecoffre/authorized-client"}' 2>/dev/null)"
echo "$STATE_RESP" | sed -n '1,30p'
echo "$STATE_RESP" | grep -q "^HTTP/1.1 200" || { echo "[FAIL] state endpoint not 200" >&2; exit 1; }
echo "$STATE_RESP" | grep -qi "Access-Control-Allow-Origin: https://dev4.4nkweb.com" || { echo "[FAIL] A-C-A-Origin not dev4 on POST" >&2; exit 1; }
STATE_JSON="$(echo "$STATE_RESP" | awk 'BEGIN{p=0} /^\r?$/{p=1;next} p{print}')"
STATE_VAL="$(echo "$STATE_JSON" | jq -r '.state // empty')"
if [[ -z "$STATE_VAL" ]]; then
echo "[FAIL] Missing state in response" >&2
exit 1
fi
echo "[OK] state received"
echo "[SUCCESS] Deployment validation completed."