#!/usr/bin/env bash # ============================================================================== # Script de rafraîchissement et anonymisation (RGPD) de la base de données UAT # Projet : AS Talange # Description : # 1. Récupère un dump PostgreSQL spécifié en paramètre ou le dernier dump produit # 2. Réinitialise le schéma public de la base de données UAT de test # 3. Restaure le dump de production vers la base UAT # 4. Anonymise l'ensemble des données personnelles (Adhérents, Pré-inscriptions, Éducateurs) # # Usage : # ./scripts/refresh_uat_db.sh [chemin_vers_dump.sql.gz] # ============================================================================== set -u # Localisation du répertoire du script et du projet SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" # Chargement du fichier .env si présent dans le projet if [ -f "${PROJECT_DIR}/.env" ]; then set -a source "${PROJECT_DIR}/.env" set +a fi # Configuration du répertoire de sauvegarde BACKUP_DIR="${BACKUP_DIR:-${PROJECT_DIR}/backups}" # Configuration de la base de données UAT UAT_DB_HOST="${UAT_DB_HOST:-10.8.0.2}" UAT_DB_PORT="${UAT_DB_PORT:-5433}" UAT_DB_NAME="${UAT_DB_NAME:-astalange}" UAT_DB_USER="${UAT_DB_USER:-myuser}" UAT_DB_PASSWORD="${UAT_DB_PASSWORD:-mypassword}" # Détermination du fichier dump à restaurer DUMP_PATH="${1:-}" # Si aucun dump n'est passé en argument, on cherche le plus récent dans BACKUP_DIR if [ -z "$DUMP_PATH" ]; then if [ -d "$BACKUP_DIR" ]; then DUMP_PATH=$(ls -t "${BACKUP_DIR}"/astalange_db_backup_*.sql.gz 2>/dev/null | head -n 1) fi fi # Journalisation TIMESTAMP=$(date +"%Y-%m-%d_%H%M%S") DATE_HUMAN=$(date +"%d/%m/%Y à %H:%M:%S") LOG_FILE=$(mktemp /tmp/astalange_refresh_uat_${TIMESTAMP}_XXXXXX.log) log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } log "======================================================================" log " Rafraîchissement & Anonymisation de la Base UAT / Test AS Talange" log "======================================================================" log "Date d'exécution : ${DATE_HUMAN}" log "Cible UAT : ${UAT_DB_USER}@${UAT_DB_HOST}:${UAT_DB_PORT}/${UAT_DB_NAME}" # Vérification de l'existence du fichier dump if [ -z "$DUMP_PATH" ] || [ ! -f "$DUMP_PATH" ]; then log "❌ ERREUR: Fichier dump introuvable ou non spécifié." log "Veuillez fournir le chemin d'un dump valide en argument ou vérifier le dossier ${BACKUP_DIR}." log "Exemple d'utilisation : $0 /chemin/vers/astalange_db_backup_XXXX.sql.gz" rm -f "$LOG_FILE" exit 1 fi if [ ! -s "$DUMP_PATH" ]; then log "❌ ERREUR: Le fichier dump spécifié est vide : ${DUMP_PATH}" rm -f "$LOG_FILE" exit 1 fi DUMP_SIZE=$(du -h "$DUMP_PATH" | cut -f1) log "Fichier dump source: ${DUMP_PATH} (${DUMP_SIZE})" # Requêtes SQL de nettoyage du schéma CLEAN_SCHEMA_SQL=" DO \$\$ DECLARE r RECORD; BEGIN FOR r IN (SELECT oid FROM pg_largeobject_metadata) LOOP PERFORM lo_unlink(r.oid); END LOOP; EXCEPTION WHEN OTHERS THEN NULL; END \$\$; DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public; GRANT ALL ON SCHEMA public TO ${UAT_DB_USER}; GRANT ALL ON SCHEMA public TO public; " # Requêtes SQL d'anonymisation RGPD (avec gestion dynamique des colonnes) ANONYMIZE_SQL=" DO \$\$ BEGIN -- 1. Anonymisation des adhérents UPDATE adherent SET nom = 'Nom_Adherent_' || id, prenom = 'Prenom_Adherent_' || id, email = 'adherent' || id || '@test.local', telephone = '06' || LPAD((id)::text, 8, '0'), lieu_naissance_ville = 'Ville_' || id, representant_legal = CASE WHEN representant_legal IS NOT NULL AND TRIM(representant_legal) <> '' THEN 'Representant_' || id ELSE representant_legal END; -- Anonymisation de l'adresse si les colonnes existent IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'adherent' AND column_name = 'adresse') THEN EXECUTE 'UPDATE adherent SET adresse = ''1 rue de Test'', code_postal = ''57525'', commune = ''Talange'''; END IF; -- 2. Anonymisation des pré-inscriptions UPDATE pre_inscription SET nom = 'Nom_PreInscr_' || id, prenom = 'Prenom_PreInscr_' || id, email = 'preinscr' || id || '@test.local', telephone = '06' || LPAD((id)::text, 8, '0'), lieu_naissance_ville = 'Ville_' || id, representant_legal = CASE WHEN representant_legal IS NOT NULL AND TRIM(representant_legal) <> '' THEN 'Representant_PreInscr_' || id ELSE representant_legal END; IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'pre_inscription' AND column_name = 'adresse') THEN EXECUTE 'UPDATE pre_inscription SET adresse = ''1 rue de Test'', code_postal = ''57525'', commune = ''Talange'''; END IF; -- 3. Anonymisation des éducateurs UPDATE educateur SET nom = 'Nom_Educ_' || id, prenom = 'Prenom_Educ_' || id, email = 'educ' || id || '@test.local', telephone = '06' || LPAD((id)::text, 8, '0'); END \$\$; " RESTORE_SUCCESS=false # Exécution soit via le client psql local, soit via conteneur Docker éphémère if command -v psql >/dev/null 2>&1; then log "Mode d'exécution : Client psql local détecté." log "1/3. Réinitialisation du schéma public sur la base UAT..." if PGPASSWORD="${UAT_DB_PASSWORD}" psql -h "${UAT_DB_HOST}" -p "${UAT_DB_PORT}" -U "${UAT_DB_USER}" -d "${UAT_DB_NAME}" -c "$CLEAN_SCHEMA_SQL" >> "$LOG_FILE" 2>&1; then log "✅ Schéma public réinitialisé." else log "❌ ERREUR lors de la réinitialisation du schéma sur UAT." fi log "2/3. Restauration du dump vers UAT..." if gunzip -c "$DUMP_PATH" | PGPASSWORD="${UAT_DB_PASSWORD}" psql -h "${UAT_DB_HOST}" -p "${UAT_DB_PORT}" -U "${UAT_DB_USER}" -d "${UAT_DB_NAME}" >> "$LOG_FILE" 2>&1; then log "✅ Dump restauré avec succès." log "3/3. Exécution de l'anonymisation RGPD sur UAT..." if PGPASSWORD="${UAT_DB_PASSWORD}" psql -h "${UAT_DB_HOST}" -p "${UAT_DB_PORT}" -U "${UAT_DB_USER}" -d "${UAT_DB_NAME}" -c "$ANONYMIZE_SQL" >> "$LOG_FILE" 2>&1; then log "✅ Données personnelles anonymisées avec succès." RESTORE_SUCCESS=true else log "❌ ERREUR lors de l'anonymisation RGPD." fi else log "❌ ERREUR lors de la restauration du dump sur UAT." fi elif command -v docker >/dev/null 2>&1; then log "Mode d'exécution : psql absent, utilisation de Docker (postgres:15-alpine)." log "1/3. Réinitialisation du schéma public sur la base UAT via Docker..." if docker run --rm --net=host -e PGPASSWORD="${UAT_DB_PASSWORD}" postgres:15-alpine psql -h "${UAT_DB_HOST}" -p "${UAT_DB_PORT}" -U "${UAT_DB_USER}" -d "${UAT_DB_NAME}" -c "$CLEAN_SCHEMA_SQL" >> "$LOG_FILE" 2>&1; then log "✅ Schéma public réinitialisé." else log "❌ ERREUR lors de la réinitialisation du schéma sur UAT." fi log "2/3. Restauration du dump vers UAT via Docker..." if gunzip -c "$DUMP_PATH" | docker run --rm -i --net=host -e PGPASSWORD="${UAT_DB_PASSWORD}" postgres:15-alpine psql -h "${UAT_DB_HOST}" -p "${UAT_DB_PORT}" -U "${UAT_DB_USER}" -d "${UAT_DB_NAME}" >> "$LOG_FILE" 2>&1; then log "✅ Dump restauré avec succès." log "3/3. Exécution de l'anonymisation RGPD sur UAT via Docker..." if docker run --rm --net=host -e PGPASSWORD="${UAT_DB_PASSWORD}" postgres:15-alpine psql -h "${UAT_DB_HOST}" -p "${UAT_DB_PORT}" -U "${UAT_DB_USER}" -d "${UAT_DB_NAME}" -c "$ANONYMIZE_SQL" >> "$LOG_FILE" 2>&1; then log "✅ Données personnelles anonymisées avec succès." RESTORE_SUCCESS=true else log "❌ ERREUR lors de l'anonymisation RGPD." fi else log "❌ ERREUR lors de la restauration du dump sur UAT." fi else log "❌ ERREUR: Ni psql ni docker ne sont installés sur cette machine." fi log "======================================================================" if [ "$RESTORE_SUCCESS" = "true" ]; then log "🎉 Opération terminée avec succès : la base UAT est rafraîchie et anonymisée !" rm -f "$LOG_FILE" exit 0 else log "❌ ÉCHEC : Le rafraîchissement ou l'anonymisation UAT a rencontré des erreurs." log "Consultez les logs ci-dessus pour plus de détails." rm -f "$LOG_FILE" exit 1 fi