Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
82 lines
3.5 KiB
Bash
Executable File
82 lines
3.5 KiB
Bash
Executable File
#!/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 ]]
|