508a6b4178
Con los tiempos REALES medidos en el ensayo del 31-jul, no estimados: dump 25s + subida 74s + saneo 2s + import 107s = camino critico ~3min30s. - docs/cutover/RUNBOOK-cutover-wordpress.md: los pasos en orden, copiables, con el rollback y los tres verdes obligatorios previos (freeze, CDMON vivo, modo SSL de la zona). - scripts/cutover/post-import-seguridad.sh: rota la contrasena de los 6 administradores (las lee del .env del perfil, nunca van en el repo), retira el rol a pabloarias/josek/andrey y limpia los cron huerfanos de Yoast y WP Profile Builder. Es un script y no una tarea manual porque el dump revive esas cuentas en CADA import. - tools/e2e/sites/nuevo.json: la suite toma el host de un JSON, asi que apuntarla al staging es anadir un fichero. Hallazgo del ensayo: el origen es MariaDB 11.8.6 y el destino MySQL 8.4.10; el dump trae 20 tablas con collations uca1400_* que MySQL rechaza. El saneo las mapea antes de importar. Sin ese paso, el import aborta. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84 lines
3.8 KiB
Bash
Executable File
84 lines
3.8 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Higiene de seguridad posterior a importar la base de datos en el servidor nuevo.
|
|
# Parte del cutover CDMON -> Hetzner (gitea rafa/feadulta #180, criterio del comment-516).
|
|
#
|
|
# SE EJECUTA DESPUES DE CADA IMPORT. El dump trae las cuentas de administrador de
|
|
# produccion con sus hashes, incluidas las tres deshabilitadas durante el incidente #183,
|
|
# asi que reimportar las revive. Por eso esto es un script y no una tarea manual.
|
|
#
|
|
# Lee las contrasenas de ~/.hermes/profiles/feadulta/.env (claves FEA_WP_PASS_*).
|
|
# Nunca las imprime ni las pasa por argv: viajan por variable de entorno del proceso.
|
|
#
|
|
# Uso: bash post-import-seguridad.sh [--dry-run]
|
|
#
|
|
set -euo pipefail
|
|
|
|
DRY=0
|
|
[ "${1:-}" = "--dry-run" ] && DRY=1
|
|
|
|
ENVF=~/.hermes/profiles/feadulta/.env
|
|
[ -f "$ENVF" ] || { echo "Falta $ENVF"; exit 1; }
|
|
set -a; . "$ENVF"; set +a
|
|
|
|
SRV=root@188.40.120.157
|
|
U=r2ssjifwj0r0ghyoqd528uaa # servicio feadulta-wp en Coolify
|
|
WPC=wordpress-$U
|
|
|
|
# usuario:ID:variable_de_password
|
|
ADMINS_OK="eqpyk:1:FEA_WP_PASS_EQPYK icalvotorre:1048:FEA_WP_PASS_ICALVOTORRE calvo:396:FEA_WP_PASS_CALVO"
|
|
ADMINS_KO="pabloarias:1047:FEA_WP_PASS_PABLOARIAS josek:1049:FEA_WP_PASS_JOSEK andrey:1087:FEA_WP_PASS_ANDREY"
|
|
|
|
wp() { ssh -o BatchMode=yes "$SRV" "docker exec -u www-data $WPC php wp-content/wp-cli.phar --path=/var/www/html --skip-plugins --skip-themes $*" 2>/dev/null; }
|
|
|
|
echo "=== 1. Rotar la contrasena de los 6 administradores ==="
|
|
for entry in $ADMINS_OK $ADMINS_KO; do
|
|
login=${entry%%:*}; rest=${entry#*:}; id=${rest%%:*}; var=${rest##*:}
|
|
pass="${!var:-}"
|
|
[ -n "$pass" ] || { echo " $login: falta $var en el .env"; exit 1; }
|
|
if [ $DRY -eq 1 ]; then
|
|
echo " [dry-run] rotaria la contrasena de $login (ID $id)"
|
|
else
|
|
ssh -o BatchMode=yes "$SRV" \
|
|
"docker exec -e NEWPASS=\"$pass\" -u www-data $WPC php wp-content/wp-cli.phar --path=/var/www/html --skip-plugins --skip-themes eval 'wp_set_password(getenv(\"NEWPASS\"), $id);'" 2>/dev/null
|
|
echo " $login (ID $id): contrasena rotada"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
echo "=== 2. Deshabilitar las tres cuentas del incidente #183 ==="
|
|
echo " (doble cinturon: se les quita el rol Y el mu-plugin fea-security-blocked-users.php"
|
|
echo " bloquea wp_authenticate_user y allow_password_reset para estos mismos IDs)"
|
|
for entry in $ADMINS_KO; do
|
|
login=${entry%%:*}; rest=${entry#*:}; id=${rest%%:*}
|
|
if [ $DRY -eq 1 ]; then
|
|
echo " [dry-run] quitaria el rol administrator a $login (ID $id)"
|
|
else
|
|
wp user remove-role "$id" administrator >/dev/null || true
|
|
echo " $login (ID $id): rol administrator retirado"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
echo "=== 3. Limpiar los cron huerfanos de plugins ya desinstalados ==="
|
|
for hook in wpseo-reindex wpseo_permalink_structure_check wppb_review_check cozmos_wppb_plugin_optin_sync; do
|
|
if [ $DRY -eq 1 ]; then
|
|
echo " [dry-run] borraria el evento $hook"
|
|
else
|
|
out=$(wp cron event delete "$hook" 2>&1 || true)
|
|
echo " $hook: ${out:-sin eventos}"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
echo "=== 4. Verificacion ==="
|
|
echo " administradores que quedan:"
|
|
wp user list --role=administrator --fields=ID,user_login,user_email --format=csv | sed 's/^/ /'
|
|
echo " el mu-plugin de bloqueo esta presente?:"
|
|
ssh -o BatchMode=yes "$SRV" "docker exec $WPC test -f /var/www/html/wp-content/mu-plugins/fea-security-blocked-users.php && echo ' SI' || echo ' NO -- FALTA, las cuentas del incidente quedarian solo con el rol retirado'"
|
|
echo ""
|
|
echo " application passwords existentes (NO se tocan: las usan los bots de la carta;"
|
|
echo " su rotacion se coordina con Inma):"
|
|
wp db query "SELECT u.user_login, LENGTH(m.meta_value) AS bytes FROM wp_usermeta m JOIN wp_users u ON u.ID=m.user_id WHERE m.meta_key='_application_passwords';" 2>/dev/null | sed 's/^/ /' || \
|
|
echo " (wp db query no disponible; consultar por SQL directo)"
|