mirror of
https://github.com/IliesAllali/parenthese.git
synced 2026-11-06 23:32:08 +00:00
- Vidéo piégée : l'expression régulière de position était quadratique, un faux MP4 de 2 Mo figeait l'API (bornée, linéaire) - Sessions émises avant le 01/10/2026 refusées (SESSIONS_NOT_BEFORE) : des sessions ont fuité dans les annotations et les journaux jusqu'à la 1.0 - Contributions : l'« avant » montré au propriétaire vient de la base ; une suppression approuvée part en cascade (unions, liens, souvenirs, portrait, fichiers) - Mot de passe de partage : essai compté avant bcrypt, comparaisons une par une, changement et rattachement dans une transaction - Quota mesuré sur le disque, 10 arbres par compte, corps à 1 Mo hors envois, bornes sur annotations, contributions et GEDCOM - GIF réencodés ; anciennes propositions d'annotation sans adresse stockée ; clé d'exemple refusée sans NODE_ENV - Déploiement du commit validé par la CI, clé d'hôte obligatoire ; nginx : X-Forwarded-For écrasé, version masquée, journal sans query string - PostHog verrouillé dans le code, sans script externe ; CSP sans *.posthog.com ; sauvegardes hors serveur chiffrées par défaut Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
4.6 KiB
YAML
110 lines
4.6 KiB
YAML
name: Deploy Hostinger
|
|
|
|
# Déploie Parenthèse sur le VPS quand le workflow « CI » a réussi sur un push sur main, ou à la main.
|
|
# Le travail est fait sur le serveur par deploy/deploy.sh, incrémental et verrouillé : seules les parties
|
|
# modifiées sont reconstruites, et un run sans changement ne reconstruit rien.
|
|
# Le serveur déploie le commit exact que la CI a validé (head_sha du run), jamais la tête de main au
|
|
# moment du run : un push arrivé entre-temps, CI rouge ou en cours, partait sinon en production sans contrôle.
|
|
# Un run plus ancien qu'un déploiement déjà fait ne revient pas en arrière.
|
|
on:
|
|
workflow_run:
|
|
workflows:
|
|
- CI
|
|
types:
|
|
- completed
|
|
branches:
|
|
- main
|
|
workflow_dispatch:
|
|
inputs:
|
|
full:
|
|
description: 'Tout réinstaller et tout reconstruire'
|
|
type: boolean
|
|
default: false
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
# Un déploiement à la fois. Un push arrivé pendant un déploiement attend son tour au lieu de le couper
|
|
# (couper un npm ci en cours laisse node_modules à moitié vide).
|
|
concurrency:
|
|
group: hostinger-production
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
deploy:
|
|
# Uniquement sur le dépôt d'origine (jamais sur un fork), et après une CI réussie sur un vrai push sur main.
|
|
if: >-
|
|
github.repository == 'IliesAllali/parenthese' &&
|
|
(
|
|
github.event_name == 'workflow_dispatch' ||
|
|
(
|
|
github.event.workflow_run.conclusion == 'success' &&
|
|
github.event.workflow_run.event == 'push' &&
|
|
github.event.workflow_run.head_branch == 'main' &&
|
|
github.event.workflow_run.head_repository.full_name == 'IliesAllali/parenthese'
|
|
)
|
|
)
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 25
|
|
|
|
steps:
|
|
- name: Start SSH agent
|
|
uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0
|
|
with:
|
|
ssh-private-key: ${{ secrets.HOSTINGER_SSH_PRIVATE_KEY }}
|
|
|
|
# Clé d'hôte épinglée par le secret SSH_KNOWN_HOSTS (sortie de ssh-keyscan relue à la main, voir
|
|
# deploy/HOSTINGER_GITHUB_SETUP.md). Sans ce secret, le déploiement s'arrête : faire confiance à la clé
|
|
# présentée le jour du run enverrait la clé de déploiement à n'importe quel serveur intercalé.
|
|
- name: Hostinger host key
|
|
env:
|
|
SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -z "$SSH_KNOWN_HOSTS" ]; then
|
|
echo "::error::Secret SSH_KNOWN_HOSTS absent : ajoutez la clé d'hôte du VPS (voir deploy/HOSTINGER_GITHUB_SETUP.md)."
|
|
exit 1
|
|
fi
|
|
mkdir -p ~/.ssh
|
|
chmod 700 ~/.ssh
|
|
printf '%s\n' "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
|
chmod 600 ~/.ssh/known_hosts
|
|
|
|
- name: Deploy on Hostinger
|
|
env:
|
|
HOSTINGER_HOST: ${{ secrets.HOSTINGER_HOST }}
|
|
HOSTINGER_PORT: ${{ secrets.HOSTINGER_PORT }}
|
|
HOSTINGER_USER: ${{ secrets.HOSTINGER_USER }}
|
|
FORCE_FULL: ${{ inputs.full && '1' || '0' }}
|
|
DEPLOY_SHA: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
PORT="${HOSTINGER_PORT:-22}"
|
|
if ! printf '%s' "$DEPLOY_SHA" | grep -Eq '^[0-9a-f]{40}$'; then
|
|
echo "::error::Commit à déployer invalide : $DEPLOY_SHA"
|
|
exit 1
|
|
fi
|
|
|
|
# backend/.env vit sur le serveur, jamais dans GitHub (dépôt public)
|
|
ssh -p "$PORT" -o StrictHostKeyChecking=yes -o ServerAliveInterval=30 "$HOSTINGER_USER@$HOSTINGER_HOST" "FORCE_FULL=$FORCE_FULL DEPLOY_SHA=$DEPLOY_SHA bash -s" <<'EOF'
|
|
set -euo pipefail
|
|
cd /var/www/parenthese
|
|
# Sous le même verrou que deploy.sh : récupération du code, puis déploiement
|
|
flock -w 900 /tmp/parenthese-deploy.lock env PARENTHESE_DEPLOY_LOCKED=1 FORCE_FULL="$FORCE_FULL" DEPLOY_SHA="$DEPLOY_SHA" bash -c '
|
|
set -euo pipefail
|
|
git fetch -q origin main
|
|
# Le commit validé doit appartenir à main
|
|
if ! git merge-base --is-ancestor "$DEPLOY_SHA" origin/main; then
|
|
echo "Commit $DEPLOY_SHA absent de main : rien n est déployé" >&2
|
|
exit 1
|
|
fi
|
|
# Un déploiement plus récent est déjà en ligne : pas de retour en arrière
|
|
if [ "$(git rev-parse HEAD)" != "$DEPLOY_SHA" ] && git merge-base --is-ancestor "$DEPLOY_SHA" HEAD; then
|
|
echo "Version plus récente déjà déployée, $DEPLOY_SHA ignoré"
|
|
exit 0
|
|
fi
|
|
git reset -q --hard "$DEPLOY_SHA"
|
|
bash deploy/deploy.sh
|
|
'
|
|
EOF
|