Siphonight a0245e72c2 Conteneurisation Docker + tests de release (container-test, mode --release)
Conteneurisation (site 100 % statique — l'image ne détient AUCUNE donnée,
vie privée identique) :
- Dockerfile : nginxinc/nginx-unprivileged:alpine (uid 101, port 8080,
  pas de root), healthcheck wget intégré, labels OCI
- nginx.conf : no-cache systématique (cohérence du jeu de fichiers à
  chaque mise à jour d'image, coût nul : ~600 Ko + gzip sur l'asset PK),
  gzip, en-têtes de sécurité, deny des dotfiles
- .dockerignore : runtime uniquement (docs/ inclus — dialog changelog) ;
  local-test-data exclu en filet de sécurité
- docker-compose.yml : read_only + tmpfs (/var/cache/nginx, /run, /tmp —
  les temporaires de nginx-unprivileged, constat au premier test réel)
  + no-new-privileges

Nouveaux tests avant release :
- scripts/container-test.sh : build + run DURCI (config compose) +
  healthcheck healthy + endpoints 200 + headers (no-cache/nosniff/DENY/
  no-referrer) + gzip réel + MIME strict des modules ES + fichiers cachés
  non servis + image propre (pas de node_modules/npm) + docs/ embarqué +
  E2E playwright complet CONTRE LE CONTENEUR (HRT_E2E_BASE)
- scripts/e2e.mjs : mode externe HRT_E2E_BASE (pilote un site déjà déployé
  — conteneur inclus, serveur local non démarré)
- scripts/check.sh --release : supplée les 9 vérifications (version ↔
  changelog ↔ tag ↔ arbre propre + test conteneur si daemon)

Runtime Docker local installé pour le CI-like (colima 2 CPU / 2 Go) :
premier build + run réel = 2 problèmes testés et corrigés (tmpfs /tmp,
key case header_json curl). CONTAINER TEST OK en configuration durcie.
2026-09-08 21:07:23 +02:00

145 lines
5.5 KiB
Bash

#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# check.sh — vérifications de l'app web (pré-commit / pré-push / pré-release).
#
# 1. node --check sur chaque module ES (syntaxe) — attrape les typos avant
# même de charger l'app dans un navigateur ;
# 2. présence des fichiers critiques (index.html, asset PK, CSS, changelog) ;
# 3. cohérence i18n : clés FR/EN synchronisées + clés référencées existantes
# (leçon Android §12 : une string manquante s'affiche brute) ;
# 4. tests unitaires Node (node --test) ;
# 5. E2E navigateur (si playwright est installé — npm i + npx playwright
# install firefox, cf docs/DEVELOPPEMENT.md §Tests) ;
# 6. smoke HTTP (--with-serve : serveur + curl des ressources clés).
#
# Mode RELEASE (--release) : ajoute les vérifications OBLIGATOIRES avant une
# release (cf docs/DEVELOPPEMENT.md §10) —
# 7. cohérence de la version : WEB_VERSION == section `## [X.Y.Z]` de
# docs/CHANGELOG.md == tag annoté `vX.Y.Z` existant (le bump de version
# jamais commité côté Android, bug #46, ne doit pas se reproduire ici) ;
# 8. arbre git propre (tout commité avant publication) ;
# 9. test conteneur RÉEL (scripts/container-test.sh — build/run durci/
# headers/gzip/MIME/E2E contre le conteneur) si un daemon Docker est
# joignable, ignoré sinon (à lancer sur l'hôte qui a Docker).
#
# Usage : bash scripts/check.sh [--with-serve] [--release]
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail
cd "$(dirname "$0")/.." # racine du dépôt
fail=0
RELEASE=false
for arg in "$@"; do
[[ "$arg" == "--release" ]] && RELEASE=1
done
echo "── 1. Syntaxe des modules (node --check) ──"
while IFS= read -r f; do
if ! node --check "$f" 2>/tmp/hrt-check.err; then
echo "✗ $f"
cat /tmp/hrt-check.err
fail=1
fi
done < <(find js -name '*.js' -type f | sort)
echo " tous les modules de js/ sont syntaxiquement valides"
echo "── 2. Fichiers critiques ──"
for f in index.html css/style.css assets/pk_profiles.json docs/CHANGELOG.md \
js/ui/app.js js/pk/pk-engine.js; do
if [[ ! -f "$f" ]]; then
echo "✗ manquant : $f"
fail=1
fi
done
echo " fichiers critiques présents"
echo "── 3. Cohérence i18n FR/EN ──"
# Vérifie : (a) chaque clé de EN existe dans FR et inversement ;
# (b) chaque clé utilisée par t('...') dans js/ existe dans EN et FR.
# (leçon Android §12 : une string manquante s'affiche brute — et FR/EN
# désynchronisés = UI mi-anglaise mi-française)
if ! node scripts/i18n-check.mjs; then
echo "✗ clés i18n manquantes (voir ci-dessus)"
fail=1
fi
echo "── 4. Tests unitaires ──"
if ! node --test tests/ 2>&1 | tail -6; then
fail=1
fi
echo "── 5. E2E navigateur (si playwright installé) ──"
if [[ -d node_modules/playwright-core && -d "$HOME/Library/Caches/ms-playwright" ]]; then
if ! node scripts/e2e.mjs 8989; then
fail=1
fi
else
echo " (ignoré : playwright non installé — npm i && npx playwright install firefox)"
fi
if [[ "${1:-}" == "--with-serve" ]]; then
echo "── 6. Smoke HTTP ──"
python3 scripts/serve.py --port 8971 >/tmp/hrt-serve.log 2>&1 &
SRV=$!
sleep 1.5
for path in / /css/style.css /assets/pk_profiles.json /js/ui/app.js /docs/CHANGELOG.md; do
code=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:8971${path}")
if [[ "$code" != "200" ]]; then
echo "✗ ${path} → HTTP ${code}"
fail=1
else
echo " 200 ${path}"
fi
done
kill $SRV 2>/dev/null || true
wait $SRV 2>/dev/null || true
fi
if [[ "$RELEASE" == "1" ]]; then
echo "── 7. Cohérence de la version (release) ──"
ver=$(node --input-type=module -e "
import { WEB_VERSION } from './js/ui/settings.js';
process.stdout.write(WEB_VERSION);")
verGrep=$(echo "$ver" | sed 's/\./\\./g') # 1.4.10 → 1\.4\.10 pour grep -E
if grep -qE "^## \\[$verGrep\\]" docs/CHANGELOG.md; then
echo " WEB_VERSION = $ver ; section [$ver] présente dans docs/CHANGELOG.md"
else
echo "✗ WEB_VERSION ($ver) n'a pas de section correspondante dans docs/CHANGELOG.md"
fail=1
fi
# Le bump de version jamais commité (bug Android #46) ne doit pas se
# reproduire : la release est faite SUR un tag qui existe.
if git rev-parse -q --verify "refs/tags/v$ver" >/dev/null 2>&1; then
echo " tag v$ver présent"
else
echo "✗ tag v$ver ABSENT — créer et pousser le tag avant la release (leçon Android #46)"
fail=1
fi
echo "── 8. Arbre git propre avant publication ──"
if [[ -n "$(git status --porcelain)" ]]; then
echo "✗ working tree sale — tout committer avant la release"
git status --short | head -5
fail=1
else
echo " working tree propre"
fi
echo "── 9. Test conteneur RÉEL (si daemon Docker joignable) ──"
if docker info --format x >/dev/null 2>&1; then
if ! bash scripts/container-test.sh 8975; then
fail=1
fi
else
echo " (ignoré : aucun daemon Docker ici — lancer sur l'hôte cible :"
echo " bash scripts/container-test.sh ; cf docs/DEVELOPPEMENT.md §10)"
fi
fi
if [[ $fail -eq 0 ]]; then
echo "✓ CHECK OK"
else
echo "✗ CHECK FAILED"
exit 1
fi