Les quatre jobs existaient ; aucun ne verifiait ce qu'il annoncait.
security-audit
`pip-audit --require-hashes --no-deps || pip-audit`. L'etape
d'installation ne posait que pip-audit, et aucune des deux formes ne
nommait le fichier d'exigences : le repli auditait l'environnement du
runner, qui ne contenait que pip-audit lui-meme. Le job passait au vert
sans avoir examine une seule dependance de l'application. Remplace par
`pip-audit -r requirements.txt`.
security-scan
Appelait `python security_scan.py`, alors que le fichier se trouve dans
app/supporting_scripts/. En echec a chaque execution depuis le
deplacement du fichier. Trois autres defauts sont apparus en le faisant
tourner :
- la CI passe --skip-http, un argument que l'argparse du script
n'acceptait pas : sortie en erreur 2 meme avec le bon chemin.
- check_dependencies lisait data['dependencies'] comme la liste des
vulnerabilites. Ce tableau liste en realite TOUTES les dependances,
chacune portant un champ vulns vide si le paquet est sain. Les ~45
paquets installes etaient donc signales vulnerables a chaque
execution. Le filtrage se fait desormais sur vulns non vide.
- check_flask_config interceptait son exception et renvoyait quand
meme all_ok : ne pas reussir a charger l'application comptait comme
un controle reussi. La section la plus importante du rapport n'avait
jamais tourne. Elle renvoie desormais False, et l'import fonctionne
grace a l'ajout de la racine du projet dans sys.path.
- la banniere en caracteres semi-graphiques faisait planter le script
sur une console Windows en cp1252, la plateforme meme du projet.
Passee en ASCII.
lint
Ruff n'avait aucun fichier de configuration : le job tournait sur le jeu
de regles par defaut. La configuration vit maintenant dans pyproject.toml.
`ruff format --check` est retire pour l'instant : la base n'ayant jamais
ete formatee, il echouerait sur 62 fichiers sur 64 pour des raisons
etrangeres a la correction. Reformatage puis application : QUA-002.
test
Un `echo` protege par continue-on-error : le job annoncait un succes
sans rien executer. Il lance desormais pytest avec couverture, et bloque.
permissions: contents: read au niveau du workflow, aucune etape n'ecrivant
dans le depot.
Deploiement Gitea
actions/checkout@v7 n'existe pas (derniere majeure : v5) : le workflow
echouait des sa premiere etape. Ramene a v4.
Le miroir lftp poussait l'integralite de l'arbre de travail, dont
clear_db.py -- un script qui vide toutes les tables et recree
admin/password -- vers le noeud de production. Liste d'exclusions ajoutee.
--delete reste volontairement absent : les contrats televerses, les
journaux et le .env du serveur vivent sous la racine de deploiement et
sont absents du depot ; les supprimer detruirait des donnees.
Le workflow de deploiement n'a pas pu etre execute depuis ici : la
syntaxe lftp reste a valider lors du prochain deploiement manuel.
Co-Authored-By: Claude Opus 5 <[email protected]>
66 lines
2.7 KiB
YAML
66 lines
2.7 KiB
YAML
name: Push to SFTP
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
# push:
|
|
# branches:
|
|
# - main # Optional: Run automatically on pushes to the main branch
|
|
|
|
jobs:
|
|
deploy-to-sftp:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
# Was @v7, which does not exist (latest major is v5): the workflow
|
|
# failed on its very first step.
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install lftp and ssh
|
|
run: sudo apt-get update && sudo apt-get install -y lftp openssh-client
|
|
|
|
- name: Set up SSH Private Key
|
|
env:
|
|
# Binds the secret to a secure environment variable
|
|
SSH_PRIVATE_KEY: ${{ secrets.SSH }}
|
|
run: |
|
|
mkdir -p ~/.ssh
|
|
# Uses the environment variable, so the raw key is never printed in the execution log
|
|
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
|
|
chmod 600 ~/.ssh/id_rsa
|
|
|
|
- name: Push files via SFTP with progress
|
|
run: |
|
|
# The mirror command below uses the -R (reverse) flag
|
|
# to push from local './' to remote './'
|
|
# Connection is made using 'open' inside the execution block to enforce SSH key usage
|
|
#
|
|
# --exclude-glob entries: the previous command mirrored the entire
|
|
# working tree, so CI definitions, the test suite and clear_db.py --
|
|
# a script that DELETEs every table and recreates admin/password --
|
|
# were all shipped to the production node.
|
|
#
|
|
# --delete is deliberately NOT used. Uploaded contracts, logs and the
|
|
# server's own .env live under the deployment root and are absent
|
|
# from the repository; deleting anything not present locally would
|
|
# destroy them. Stale files therefore accumulate: switching to an
|
|
# atomic timestamped-directory deploy is tracked as OPS-011.
|
|
lftp -e "set sftp:connect-program 'ssh -a -x -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no -o BatchMode=yes -o PasswordAuthentication=no'; \
|
|
set sftp:auto-confirm yes; \
|
|
set net:max-retries 5; \
|
|
set net:timeout 30; \
|
|
set cmd:fail-exit yes; \
|
|
open -u ${{ secrets.SSH_USER }}, sftp://sftp.node4.immortal.host:2022; \
|
|
mirror -R --verbose --parallel=4 \
|
|
--exclude-glob .git/ \
|
|
--exclude-glob .github/ \
|
|
--exclude-glob .gitea/ \
|
|
--exclude-glob .venv/ \
|
|
--exclude-glob venv/ \
|
|
--exclude-glob tests/ \
|
|
--exclude-glob audit/ \
|
|
--exclude-glob .ai/ \
|
|
--exclude-glob __pycache__/ \
|
|
--exclude-glob clear_db.py \
|
|
./ ./; \
|
|
quit" |