#!/usr/bin/env bash # ============================================================================= # Tests de fumee post-deploiement # ============================================================================= # Verifie ce qu'un utilisateur constate reellement, depuis l'exterieur, a # travers Cloudflare et Traefik -- pas l'etat interne du cluster. # # bash scripts/smoke-test.sh # # Code de retour 0 = production saine. Utilise par deploy.sh et cd-main.yml # pour declencher un retour arriere automatique. set -uo pipefail API="${PROD_API_URL:-https://api.xpeditis.com}" APP="${PROD_APP_URL:-https://app.xpeditis.com}" SITE="${PROD_SITE_URL:-https://xpeditis.com}" PASS=0 FAIL=0 check() { local label="$1"; shift if "$@" >/dev/null 2>&1; then printf ' [OK] %s\n' "$label"; PASS=$((PASS + 1)) else printf ' [ECHEC] %s\n' "$label"; FAIL=$((FAIL + 1)) fi } http_code() { curl -sS -o /dev/null -w '%{http_code}' --max-time 15 "$1"; } expect_code() { local url="$1" expected="$2" [[ "$(http_code "$url")" == "$expected" ]] } expect_header() { local url="$1" header="$2" curl -sSI --max-time 15 "$url" | grep -qi "^${header}:" } echo "Tests de fumee - $(date -Is)" echo echo "Disponibilite" check "API en ligne (200 sur /api/v1/health)" expect_code "${API}/api/v1/health" 200 check "Frontend en ligne (app)" expect_code "${APP}/" 200 check "Vitrine en ligne (apex)" expect_code "${SITE}/" 200 echo echo "TLS et redirections" check "HTTP redirige vers HTTPS" bash -c "[[ \$(curl -sS -o /dev/null -w '%{http_code}' --max-time 15 'http://api.xpeditis.com/api/v1/health') =~ ^30 ]]" check "Certificat valide (pas d'option -k)" curl -sS --max-time 15 -o /dev/null "${API}/api/v1/health" check "En-tete HSTS present" expect_header "${API}/api/v1/health" "strict-transport-security" echo echo "Durcissement" check "X-Frame-Options present" expect_header "${APP}/" "x-frame-options" check "X-Content-Type-Options present" expect_header "${APP}/" "x-content-type-options" # main.ts desactive Swagger en production sauf si SWAGGER_USERNAME/PASSWORD # sont definis. 404 = desactive, 401 = protege : les deux sont acceptables, # 200 signifie que la documentation de l'API est publique. check "Swagger non accessible librement" bash -c "[[ \$(curl -sS -o /dev/null -w '%{http_code}' --max-time 15 '${API}/api/docs') != '200' ]]" check "Route protegee refuse l'anonyme (401/403)" bash -c "[[ \$(curl -sS -o /dev/null -w '%{http_code}' --max-time 15 '${API}/api/v1/bookings') =~ ^(401|403)$ ]]" check "CORS refuse une origine inconnue" bash -c "! curl -sSI --max-time 15 -H 'Origin: https://evil.example' '${API}/api/v1/health' | grep -qi 'access-control-allow-origin: https://evil.example'" echo echo "Etat du cluster" if command -v kubectl >/dev/null && kubectl get ns xpeditis-prod >/dev/null 2>&1; then check "Aucun pod en erreur" bash -c "! kubectl -n xpeditis-prod get pods --no-headers | grep -qE 'CrashLoopBackOff|ImagePullBackOff|Error'" check "Certificat cert-manager pret" bash -c "kubectl -n xpeditis-prod get certificate xpeditis-wildcard -o jsonpath='{.status.conditions[?(@.type==\"Ready\")].status}' | grep -q True" else echo " [saute] kubectl indisponible : verifications cluster ignorees" fi echo echo "-----------------------------------------" printf ' Reussis : %d Echecs : %d\n' "$PASS" "$FAIL" echo "-----------------------------------------" [[ "$FAIL" -eq 0 ]]