Repository navigation
Merge pull request #26 from otspi/feat/attestation-pdf #47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Tests et déploiement o2switch (FTPS) | |
| # manifesto-sign.otspi.org est servi par o2switch. Chaque push sur main passe le test de bout en bout, | |
| # puis envoie le code. config.php et data/ (base SQLite) restent sur le serveur et ne sont jamais touchés. | |
| on: | |
| push: | |
| branches: ["main"] | |
| pull_request: | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.event_name == 'pull_request' && format('tests-{0}', github.ref) || 'deploy' }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| tests: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Test de bout en bout | |
| run: bash tests/flow.sh | |
| navigateur: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| # Chromium piloté par Playwright : preuve de travail, partage, clé de sécurité virtuelle, sélection par lot. | |
| - name: Tests dans un vrai navigateur | |
| run: bash tests/navigateur.sh | |
| deploy: | |
| needs: [tests, navigateur] | |
| if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| # Environnement GitHub : on peut y exiger une approbation manuelle avant chaque mise en production. | |
| environment: | |
| name: production | |
| url: https://manifesto-sign.otspi.org/ | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Installation de lftp | |
| run: sudo apt-get update -qq && sudo apt-get install -y -qq lftp | |
| # Compte FTP dédié, cantonné au répertoire de l'application (le parent de public/) ; TLS obligatoire | |
| # et certificat vérifié. Seuls les dossiers de code sont envoyés, config.php et data/ ne sont jamais | |
| # visés. src/ part avant public/ : pendant les quelques secondes de l'envoi, d'anciennes pages avec | |
| # la nouvelle bibliothèque restent fonctionnelles, alors que l'inverse appellerait des fonctions | |
| # absentes. --delete retire le code supprimé du dépôt ; .well-known/ (certificats), cgi-bin/ et error_log | |
| # (créés par le serveur) sont préservés. | |
| - name: Déploiement FTPS | |
| env: | |
| FTP_HOST: ${{ vars.O2_FTP_HOST }} | |
| FTP_DIR: ${{ vars.O2_SIGN_FTP_DIR || '.' }} | |
| FTP_USERNAME: ${{ secrets.O2_SIGN_FTP_USERNAME }} | |
| LFTP_PASSWORD: ${{ secrets.O2_SIGN_FTP_PASSWORD }} | |
| run: | | |
| lftp -u "$FTP_USERNAME" --env-password "ftp://$FTP_HOST" -e " | |
| set cmd:fail-exit yes; | |
| set ftp:ssl-force yes; | |
| set ftp:ssl-protect-data yes; | |
| set ssl:verify-certificate yes; | |
| set ftp:passive-mode yes; | |
| set net:max-retries 2; | |
| cd '$FTP_DIR'; | |
| mkdir -p -f bin cron src public; | |
| mirror --reverse --delete --verbose --no-perms bin/ bin/; | |
| mirror --reverse --delete --verbose --no-perms cron/ cron/; | |
| mirror --reverse --delete --verbose --no-perms src/ src/; | |
| mirror --reverse --delete --verbose --no-perms --exclude '^\\.well-known/' --exclude '^cgi-bin/' --exclude '^error_log$' public/ public/; | |
| bye" | |
| # Contrôle en lecture seule : formulaire et page d'erreur de l'application, fichiers hors de public/ | |
| # non servis. signataires.php n'est pas interrogé : o2switch ne répond pas à cette adresse depuis | |
| # les serveurs de GitHub Actions (délai dépassé), alors qu'elle répond normalement ailleurs. | |
| - name: Vérification du site | |
| run: | | |
| set -euo pipefail | |
| U=https://manifesto-sign.otspi.org | |
| # Erreurs réseau passagères (flux HTTP/2 interrompu, code 92) : nouvelles tentatives, et un échec | |
| # de curl ne coupe pas le script ; seul le résultat attendu décide. | |
| body() { curl -s --retry 3 --retry-all-errors -m 20 "$1" || true; } | |
| status() { curl -s -o /dev/null -w '%{http_code}' --retry 3 --retry-all-errors -m 20 "$1" || true; } | |
| [ "$(status "$U/")" = 200 ] || { echo "formulaire inaccessible"; exit 1; } | |
| page404=$(body "$U/page-inexistante") | |
| grep -q 'class="card"' <<< "$page404" || { echo "page 404 de l'application absente"; exit 1; } | |
| for p in /config.php /src/lib.php /bin/moderation.php /data/signatures.sqlite; do | |
| code=$(status "$U$p") | |
| # Le pare-feu d'o2switch coupe parfois ces requêtes « de scanner » venant des runners (code 000) : | |
| # seul un fichier réellement servi (2xx) fait échouer le contrôle, le reste est signalé. | |
| case "$code" in | |
| 2*) echo "$p exposé ($code)"; exit 1 ;; | |
| 403|404) ;; | |
| *) echo "::warning::$p : réponse $code (connexion refusée par le pare-feu ?), exposition non vérifiée depuis le runner" ;; | |
| esac | |
| done | |
| echo "Site vérifié." |