Files
parenthese/.github/workflows/deploy-hostinger.yml
T
IliesAllaliandClaude Opus 5.5 882a981e0b Workflows : actions épinglées par SHA, clé d'hôte SSH épinglée, audit npm
Chaque action est référencée par son commit, version en commentaire. Le
déploiement lit la clé d'hôte dans le secret SSH_KNOWN_HOSTS et exige sa
vérification ; sans secret, repli sur ssh-keyscan avec un avertissement.
La CI échoue sur une faille critique d'une dépendance de production.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 17:42:11 +02:00

98 lines
3.9 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 origin/main au moment du run (fetch + reset) : si deux pushs se suivent de près,
# c'est le plus récent qui part, sa propre CI déclenchera ensuite un run sans changement.
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@dc588b651fe13675774614f8e6a936a468676387 # v0.9.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, repli sur ssh-keyscan au moment du run, qui
# fait confiance à la clé présentée ce jour-là : un avertissement le signale dans le run.
- name: Hostinger host key
env:
HOSTINGER_HOST: ${{ secrets.HOSTINGER_HOST }}
HOSTINGER_PORT: ${{ secrets.HOSTINGER_PORT }}
SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
run: |
set -euo pipefail
PORT="${HOSTINGER_PORT:-22}"
mkdir -p ~/.ssh
chmod 700 ~/.ssh
if [ -n "$SSH_KNOWN_HOSTS" ]; then
printf '%s\n' "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
else
echo "::warning::Secret SSH_KNOWN_HOSTS absent : clé d'hôte récupérée par ssh-keyscan, sans vérification. Ajoutez le secret."
ssh-keyscan -T 5 -p "$PORT" -H "$HOSTINGER_HOST" >> ~/.ssh/known_hosts || true
fi
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' }}
run: |
set -euo pipefail
PORT="${HOSTINGER_PORT:-22}"
# 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 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" bash -c '
set -euo pipefail
git fetch -q origin main
git reset -q --hard origin/main
bash deploy/deploy.sh
'
EOF