Rapatrie l'environnement dev à la demande (#151) et l'en-tête CORP (#149).
- deploy.yml : garde le routage de #151 (main vers prod, dev vers rec, toute autre branche vers
dev) et l'appel par ci.yml après « CI ok ». Le groupe concurrency par environnement cède la
place au flock sur le dossier, qui sérialise aussi deux branches lancées dans dev. La garde
anti-recul ne joue que sur la même branche : dans dev, une autre branche que celle en place
est toujours déployée.
- provision-host.sh : le dossier dev reçoit aussi les clés de supervision, profil inactif,
ports 3003, 9092 et 9095.
- 10-infra.md, 50-cicd.md et ADR 0017 : trois environnements, supervision et verrou flock.
Les CI de deux push rapprochés peuvent finir dans le désordre. deploy.yml faisait alors
reset --hard sur un GITHUB_SHA plus ancien que celui déjà déployé, et le groupe concurrency
deploy-<branche> ne garde qu'un job en attente : un troisième arrivé annulait le précédent, qui
n'était jamais déployé.
- un commit qui précède celui déjà déployé est ignoré, avec une annotation dans le run ;
- le groupe concurrency cède la place à un flock posé dans le clone de la VM, tenu du fetch
jusqu'à la sonde de santé : les déploiements passent un par un, aucun n'est annulé ;
- les trois étapes n'en font plus qu'une, le verrou tombant avec le shell qui l'a posé ; les
journaux restent découpés par ::group::.
ADR 0014 et 50-cicd.md décrivent les deux gardes.
Troisième projet Compose sur la VM ENI, /srv/enervision/dev, alimenté par
workflow_dispatch de n'importe quelle branche autre que dev et main
(https://dev.enervision.local:9443). La recette suit toujours dev, la
production main.
- deploy.yml : routage main -> prod, dev -> rec, autre -> dev ; groupe de
concurrence par environnement et non plus par branche.
- provision-host.sh : prépare le dossier dev (ports 9443, 5435, 8027, 8084) ;
passe safe.directory à git, faute de quoi un second passage en root, celui
de terraform apply, échoue sur les clones déjà remis au runner.
- ADR 0017, 10-infra.md, 50-cicd.md, infra/README.md à jour.
- ADR 0014 : un pipeline CI unique, « CI ok » seul check à exiger, déploiement du commit testé.
- ADR 0015 : e2e et charge contre la stack Compose déployée, hypothèses et seuils de k6.
- ADR 0016 : supervision en profil Compose, active en prod, rôle en lecture seule.
- Nouvelle vue 60-observabilite.md ; 00-vue-ensemble, 10-infra, 20-backend et 50-cicd mis à
jour (monitoring passé à Fait, nouveau graphe de CI, gates, ports).
- README racine et guide de tests du frontend : où sont l'e2e, la charge et la supervision.
Un seul conflit, docs/architecture/50-cicd.md : les deux côtés ajoutaient une
section au même endroit, après « Secrets ». Les deux sont conservées. Celle de
la branche, « Pourquoi le job d'intégration ML installe aussi le backend »,
remonte sous « Le job d'intégration, et pourquoi il ne suffisait pas d'un
postgres », dont elle est le prolongement : posée après « Secrets », elle en
devenait une sous-section.
openapi.json régénéré : dev a renommé le schéma de sécurité « Jeton d'accès »
en « JetonAcces » pour l'analyseur de contrat de ZAP, et la route
/api/v1/monitoring/drift ajoutée ici portait encore l'ancien nom dans le
contrat figé. Aucune fusion textuelle ne pouvait le voir.
Trois phrases du depot annonçaient une surveillance de derive inexistante, et une quatrieme
disait qu'aucune base PostgreSQL n'etait joignable pour tester le chargement ML. Les quatre
sont maintenant fausses, donc reecrites plutot que laissees en dette.
- ADR 0011 : ou vit le calcul et pourquoi pas dans `ml/`, les deux dedoublonnages qu'impose la
jointure, et quatre alternatives ecartees avec la contrainte qui les interdit (la metrique
MLflow n'est pas la meme grandeur, `alert` borne ses valeurs et refuse un site nul, Prometheus
n'a pas de collecteur, ne rien persister ne repond pas a la question du jury).
- DAG `derive` quotidien, hors du DAG `alertes` : un echec de derive y ferait croire que la
detection a echoue, et la fenetre de 168 h ne se recalcule pas toutes les heures.
- ML-START : la limite de `--now` est dite au lieu d'etre decouverte en demonstration. Elle ne
decale que l'instant de reference, pas la fenetre de lecture, donc aucun rattrapage ne peut
fabriquer de paires prevu/realise sur un jeu fige.
- 50-cicd : pourquoi le job ML installe aussi le backend (le schema n'a qu'une source), et ce
que coute le filtre de chemins qui l'accompagne.
Le seul Terraform du dépôt installait un cluster k3s que rien ne consomme, et
sa racine ne passait même pas `terraform init` : depuis Terraform 1.x, un
provisioner `destroy` impose que tout le bloc `connection` ne lise que `self`,
et celui du module k3s lisait `var.*`. Il est corrigé en batissant la connexion
sur `triggers`, où ne figurent que l'adresse, le port, l'utilisateur et le
chemin de la clé : jamais la clé ni un mot de passe.
`environments/vm-eni` provisionne la machine qui porte la recette et la
production : Docker et le plugin Compose, `scripts/provision-host.sh`, puis
l'enregistrement du runner. Rien n'y construit d'image ni ne lance de
conteneur, et un `apply` n'interrompt pas la stack qui tourne. Le déploiement
continu ne bouge pas : `deploy.yml` reste le seul chemin de livraison.
`environments/dev` devient `k3s-cible`, parce qu'il provisionnait un cluster et
pas un environnement applicatif, et que `rec` et `prod` vivent sur la même
machine. `environments/prod`, dossier vide, disparaît.
`infra.yml` formate et valide chaque racine à chaque push : c'est l'absence
d'un tel job qui a laissé ce Terraform cassé sans que rien ne le dise. La
boucle parcourt `environments/*`, une racine ajoutée est couverte sans y
toucher.
ADR 0010 pour la frontière entre provisionnement et livraison, et la doc
d'architecture alignée dessus.
Rapatrie #135 : migration vers Airflow 3.3.2 (api-server, dag-processor,
secret JWT, FabAuthManager, DAGs et tests sur le SDK). Conflit Makefile :
la cible airflow-up garde le prérequis db-ensure-airflow de dev et les
services renommés de main.
Quatre services au lieu de trois (api-server, dag-processor), le secret JWT
partagé et le choix du FabAuthManager. Le Python 3.12 d'etl/airflow est celui
de l'image retenue, plus une limite d'Airflow.
`make stack-up` enchaîne `alembic upgrade head` dans le conteneur backend. Rien ne
migrait la base sur le chemin de déploiement, et `/api/v1/health/ready`, qui ne teste
que la connexion et l'extension TimescaleDB, aurait laissé passer un déploiement vert
sur une base sans schéma applicatif.
deploy.yml borne le job à 30 minutes et sort les journaux du backend et du proxy quand
la sonde échoue. provision-host.sh rappelle la création du premier administrateur, et
la propriété de /srv/enervision sans laquelle le runner ne peut ni manipuler les clones
ni lire un `.env` en 600.
Les statuts de livraison continue repassent à `En cours` : le code est écrit, la machine
n'est pas provisionnée, le runner n'est pas enregistré, rien n'a été déployé. À basculer
sur `Fait` au premier déploiement vert. Décompte des jobs corrigé, 18 et non 17.
Refs #21, #22
Un projet Compose par environnement sur la même machine : ports du proxy et origine
publique en variables dans docker-compose.prod.yml, réglage mémoire des deux bases
TimescaleDB et du webserver Airflow. Le workflow deploy.yml déploie dev en recette et
main en production depuis un runner installé sur la VM, jamais sur pull_request.
scripts/provision-host.sh prépare les deux dossiers, secrets et certificats compris,
sans rien démarrer.
L'image frontend quitte dhi.io/nginx, registre authentifié dont personne n'a l'accès,
pour nginx:1.28-alpine : elle n'avait jamais été construite.
ADR 0009, vues infra et CI/CD, README et .env.example mis à jour.
Refs #21, #22
ML-START.md affirmait que l'orchestration Airflow n'existait pas : `ml_score`
tourne en `@hourly` depuis l'issue #115, seuls le mode `--csv` et un lancement
local restent manuels.
50-cicd.md : Dependabot compte six entrées sur cinq écosystèmes et non cinq
entrées, le filtre d'`airflow.yml` couvre aussi `apps/backend/` depuis le DAG
`alertes`, et les issues #21 (job de déploiement) et #22 (secrets) sont
distinguées au lieu d'être citées l'une pour l'autre. Le `continue-on-error` du
second passage Bandit est nommé pour ce qu'il est : le job reste vert même avec
un constat LOW.
Bandit est épinglé à 1.9.4 dans les deux jobs `sast` : sans épingle, une
nouvelle version passe la CI au rouge sans qu'une ligne du dépôt ait changé, et
le rejeu à l'identique documenté n'existe pas. Le `cache-dependency-glob` part :
`uvx` n'installe pas le projet, le verrou n'alimentait aucune clé de cache.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
La documentation du pipeline est explicitement notée par EC03 (C20) et n'existait
pas. L'index des vues justifiait son absence par un manque de matière : quatre
workflows et quatorze jobs en sont assez.
Trois affirmations de 00-vue-ensemble.md étaient devenues fausses, ce qui coûte
plus cher qu'une absence puisqu'on les lit et qu'on construit dessus :
- la CI/CD y était déclarée `Cible` / `Rien` alors que quatre workflows tournent ;
- le flux bout en bout y était `Cible` avec "aucun maillon n'existe, à l'exception
de la base", alors que tout le chemin de lecture et deux ingestions existent ;
- l'analyse de dépendances y était listée comme absente alors que pip-audit,
npm audit et Dependabot sont en place. Seule celle des images manque.
Ferme C20 de la grille d'auto-évaluation.