docs : un document d'entrée par épreuve, et Trivy dans la chaîne (#269) #270

Merged
gabriel merged 6 commits from lenaic/269-docs-epreuves-et-trivy into develop 2026-09-10 17:28:51 +00:00
Owner

Deux sujets qui partent ensemble parce qu'ils sont tous les deux attendus au gel de vendredi 9h00.

1. Le nom que le correcteur cherche

L'énoncé demande « rapport de sécurisation EC04, documentations EC03/EC05/EC06 ». Le rapport EC04 porte déjà ce nom. Les trois autres n'existaient pas : la matière était là, répartie entre docs/data/, docs/adr/, tests/ci/ et les manuels, et il fallait la deviner.

Trois documents d'entrée, sur le modèle du rapport EC04. Chacun dit ce qui tourne, où c'est dans le dépôt, comment le vérifier sans nous croire sur parole, et ce qui n'est pas livré :

  • docs/EC03-INTEGRATION-CONTINUE.md
  • docs/EC05-CHAINE-DE-DONNEES.md
  • docs/EC06-MODELE-ET-PREVISION.md

Aucun fichier n'est renommé, aucun lien existant ne casse. Le README porte en plus une table « Documentation par épreuve », cinq lignes, qui donne le document d'entrée et ses renvois.

2. Trivy dans la chaîne

pip-audit couvre les dépendances Python déclarées. Il ne voit ni un secret laissé dans un fichier, ni une image de base vulnérable, ni une ressource Terraform mal configurée. Trivy couvre ces trois-là.

Deux passes, et leur sévérité diffère à dessein :

Passe Statut Pourquoi
vuln,secret bloquante verte aujourd'hui, donc elle ne bloquera que sur du neuf
misconfig journalisée deux constats réels, portés par le #269 avec leur valeur et la date où la passe devient bloquante

Rendre misconfig bloquante ce soir arrêterait la chaîne sur un état connu, ce qui n'apprend rien à personne.

L'archive est épinglée par version ET par empreinte, vérifiée contre le fichier de sommes publié avec la version. Comparer un numéro de version ne prouve rien : c'est l'empreinte qui lie l'octet au projet. C'est la leçon du 88d8330, où l'épinglage avait été vérifié contre le mauvais miroir.

tests/ci/fixtures/ est exclu, et cette exclusion est obligatoire : ces fichiers sont volontairement fautifs et servent à prouver que le garde Terraform et les bancs rougissent. Les scanner ferait échouer la chaîne sur ses propres cas d'essai.

Preuve

Éprouvé avant d'être écrit, avec trivy 0.74.0 sur le dépôt :

vuln + secret ......... 0 constat
misconfig ............. 2 constats (stockage.tf CRITICAL, postgres/Dockerfile HIGH) → #269

Bancs rejoués en local :

test-hygiene-workflows.sh ... les 37 noms de contrôle correspondent tous à un contrôle rapporté
test-hygiene-bancs.sh ....... aucun « … | grep -q » dans un script sous pipefail
test-liens-markdown.sh ...... 355 liens relatifs dans 89 fichiers, aucun mort

Ce que la relecture doit regarder

  1. Les trois documents d'entrée disent-ils vrai sur ton épreuve ? Le §6 « ce qui n'est pas livré » est le plus important : il vaut mieux qu'il soit trop honnête que trop court.
  2. La passe misconfig non bloquante est un compromis assumé à J-1. Si tu préfères la rendre bloquante tout de suite, il faut d'abord fermer le #269.
Deux sujets qui partent ensemble parce qu'ils sont tous les deux attendus au gel de vendredi 9h00. ## 1. Le nom que le correcteur cherche L'énoncé demande « rapport de sécurisation EC04, documentations EC03/EC05/EC06 ». Le rapport EC04 porte déjà ce nom. Les trois autres n'existaient pas : la matière était là, répartie entre `docs/data/`, `docs/adr/`, `tests/ci/` et les manuels, et il fallait la deviner. Trois documents d'entrée, sur le modèle du rapport EC04. Chacun dit **ce qui tourne, où c'est dans le dépôt, comment le vérifier sans nous croire sur parole, et ce qui n'est pas livré** : - `docs/EC03-INTEGRATION-CONTINUE.md` - `docs/EC05-CHAINE-DE-DONNEES.md` - `docs/EC06-MODELE-ET-PREVISION.md` Aucun fichier n'est renommé, aucun lien existant ne casse. Le README porte en plus une table « Documentation par épreuve », cinq lignes, qui donne le document d'entrée et ses renvois. ## 2. Trivy dans la chaîne `pip-audit` couvre les dépendances Python déclarées. Il ne voit **ni un secret laissé dans un fichier, ni une image de base vulnérable, ni une ressource Terraform mal configurée**. Trivy couvre ces trois-là. Deux passes, et leur sévérité diffère à dessein : | Passe | Statut | Pourquoi | |---|---|---| | `vuln,secret` | **bloquante** | verte aujourd'hui, donc elle ne bloquera que sur du neuf | | `misconfig` | journalisée | deux constats réels, portés par le #269 avec leur valeur et la date où la passe devient bloquante | Rendre `misconfig` bloquante ce soir arrêterait la chaîne sur un état connu, ce qui n'apprend rien à personne. **L'archive est épinglée par version ET par empreinte**, vérifiée contre le fichier de sommes publié avec la version. Comparer un numéro de version ne prouve rien : c'est l'empreinte qui lie l'octet au projet. C'est la leçon du 88d8330, où l'épinglage avait été vérifié contre le mauvais miroir. `tests/ci/fixtures/` est exclu, et **cette exclusion est obligatoire** : ces fichiers sont volontairement fautifs et servent à prouver que le garde Terraform et les bancs rougissent. Les scanner ferait échouer la chaîne sur ses propres cas d'essai. ## Preuve Éprouvé avant d'être écrit, avec trivy 0.74.0 sur le dépôt : ``` vuln + secret ......... 0 constat misconfig ............. 2 constats (stockage.tf CRITICAL, postgres/Dockerfile HIGH) → #269 ``` Bancs rejoués en local : ``` test-hygiene-workflows.sh ... les 37 noms de contrôle correspondent tous à un contrôle rapporté test-hygiene-bancs.sh ....... aucun « … | grep -q » dans un script sous pipefail test-liens-markdown.sh ...... 355 liens relatifs dans 89 fichiers, aucun mort ``` ## Ce que la relecture doit regarder 1. Les trois documents d'entrée disent-ils vrai sur ton épreuve ? Le §6 « ce qui n'est pas livré » est le plus important : il vaut mieux qu'il soit trop honnête que trop court. 2. La passe `misconfig` non bloquante est un compromis assumé à J-1. Si tu préfères la rendre bloquante tout de suite, il faut d'abord fermer le #269.
docs: un document d'entrée par épreuve, et Trivy dans la chaîne (#269)
Some checks failed
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 10s
Intégration / Terraform — format, validité et lint (pull_request) Successful in 30s
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Successful in 47s
Intégration / Workflows — lint et audit de sécurité (pull_request) Failing after 15s
Intégration / Checkov — audit de la configuration (pull_request) Successful in 44s
Intégration / Python — qualité, tests et dépendances (pull_request) Successful in 6m26s
d021460d16
DEUX SUJETS, UNE SEULE DEMANDE, PARCE QU'ILS PARTENT ENSEMBLE AU GEL.

## Le nom que le correcteur cherche

L'énoncé demande « rapport de sécurisation EC04, documentations
EC03/EC05/EC06 ». Le rapport EC04 porte déjà ce nom. Les trois autres
n'existaient pas : la matière était là, répartie entre docs/data,
docs/adr, tests/ci et les manuels, et il fallait la deviner.

Trois documents d'entrée, sur le même modèle que le rapport EC04. Chacun
dit ce qui tourne, où c'est dans le dépôt, comment le vérifier sans nous
croire sur parole, et ce qui n'est pas livré. Aucun fichier n'est
renommé, aucun lien existant ne casse.

Le README porte la table « Documentation par épreuve », cinq lignes, qui
donne le document d'entrée et ses renvois.

## Trivy

pip-audit couvre les dépendances Python déclarées. Il ne voit ni un
secret laissé dans un fichier, ni une image de base vulnérable, ni une
ressource Terraform mal configurée.

Deux passes, et leur sévérité diffère à dessein :

- « vuln,secret » est BLOQUANTE. Elle est verte aujourd'hui, donc elle ne
  bloquera que sur du neuf. Éprouvée avant d'être écrite : zéro constat.
- « misconfig » est JOURNALISÉE. Elle rend deux constats réels, portés
  par le #269 avec ce qu'ils valent et la date où la passe devient
  bloquante. Les rendre bloquants ce soir arrêterait la chaîne sur un
  état connu, ce qui n'apprend rien à personne.

L'archive est épinglée par version ET par empreinte, vérifiée contre le
fichier de sommes publié avec la version. Comparer un numéro de version
ne prouve rien, c'est l'empreinte qui lie l'octet au projet — la leçon
du #88d8330, où l'épinglage avait été vérifié contre le mauvais miroir.

tests/ci/fixtures/ est exclu, et cette exclusion est obligatoire : ces
fichiers sont volontairement fautifs et servent à prouver que le garde
Terraform rougit. Les scanner ferait échouer la chaîne sur ses propres
cas d'essai.

## Vérifié avant de pousser

- trivy 0.74.0 joué sur le dépôt : 0 constat vuln+secret, 2 en misconfig
- test-hygiene-workflows.sh : les 37 noms de contrôle correspondent
- test-hygiene-bancs.sh : aucun « … | grep -q » sous pipefail
- test-liens-markdown.sh : 355 liens relatifs, aucun mort
lenaic left a comment

Correctif poussé après une remarque de Lénaïc : « on va valider une PR de CI qui bloquera ? »

Réponse sur le fond : non. La passe bloquante est vuln,secret, jouée sur le dépôt avant d'être écrite, zéro constat. La passe qui trouve quelque chose (misconfig, deux constats) est journalisée. Merger cette demande ne fait pas rougir la chaîne.

Mais la question a révélé un vrai défaut, corrigé en c786d8b. La première version traitait tout code de retour non nul de Trivy comme « un défaut a été trouvé ». Trivy sort aussi en erreur quand il ne peut pas télécharger sa base de vulnérabilités : réseau, quota, miroir indisponible. La chaîne aurait rougi sans qu'aucun défaut existe — le reproche que test-hygiene-bancs.sh fait aux autres.

La forme retenue : --exit-code 0 toujours, sortie JSON, et c'est le décompte lu dans le rapport qui décide. Pas de rapport exploitable, pas de verdict : l'étape se déclare sautée et laisse passer. ERREUR n'est pas zéro, et c'est tout le correctif.

Le décompte est un script (.forgejo/scripts/trivy-compter.py) et non un heredoc dans le workflow : un heredoc indenté dans un bloc YAML rend à Python des lignes à espaces de tête et meurt sur une IndentationError.

Éprouvé, pas supposé. L'étape a été extraite du YAML et rejouée sous dash, le shell du runner :

Cas Résultat
dépôt réel, empreinte juste code 0 · vuln+secret 0 constat · misconfig 2 constats en warned
empreinte fausse code 1 · « on n'exécute pas un binaire non vérifié »
rapport illisible ou absent ERREUR · étape sautée, la chaîne passe

Un point pour la relecture : sur infra/terraform/stockage.tf, Trivy recouvre partiellement Checkov, dont le commentaire dans le fichier explique déjà pourquoi huit règles échouent. C'est noté dans le #269.

Correctif poussé après une remarque de Lénaïc : « on va valider une PR de CI qui bloquera ? » **Réponse sur le fond : non.** La passe bloquante est `vuln,secret`, jouée sur le dépôt avant d'être écrite, **zéro constat**. La passe qui trouve quelque chose (`misconfig`, deux constats) est journalisée. Merger cette demande ne fait pas rougir la chaîne. **Mais la question a révélé un vrai défaut, corrigé en `c786d8b`.** La première version traitait *tout* code de retour non nul de Trivy comme « un défaut a été trouvé ». Trivy sort aussi en erreur quand il ne peut pas télécharger sa base de vulnérabilités : réseau, quota, miroir indisponible. La chaîne aurait rougi **sans qu'aucun défaut existe** — le reproche que `test-hygiene-bancs.sh` fait aux autres. La forme retenue : `--exit-code 0` toujours, sortie JSON, et c'est le **décompte** lu dans le rapport qui décide. Pas de rapport exploitable, pas de verdict : l'étape se déclare sautée et laisse passer. `ERREUR` n'est pas zéro, et c'est tout le correctif. Le décompte est un script (`.forgejo/scripts/trivy-compter.py`) et non un heredoc dans le workflow : un heredoc indenté dans un bloc YAML rend à Python des lignes à espaces de tête et meurt sur une IndentationError. **Éprouvé, pas supposé.** L'étape a été extraite du YAML et rejouée sous `dash`, le shell du runner : | Cas | Résultat | |---|---| | dépôt réel, empreinte juste | code **0** · vuln+secret 0 constat · misconfig 2 constats en `warned` | | empreinte fausse | code **1** · « on n'exécute pas un binaire non vérifié » | | rapport illisible ou absent | `ERREUR` · étape sautée, la chaîne passe | Un point pour la relecture : sur `infra/terraform/stockage.tf`, Trivy recouvre partiellement Checkov, dont le commentaire dans le fichier explique déjà pourquoi huit règles échouent. C'est noté dans le #269.
ci: Trivy ne bloque que sur un constat, jamais sur une panne d'outil
Some checks failed
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Successful in 49s
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 7s
Intégration / Python — qualité, tests et dépendances (pull_request) Failing after 1m20s
Intégration / Terraform — format, validité et lint (pull_request) Successful in 24s
Intégration / Workflows — lint et audit de sécurité (pull_request) Failing after 16s
Intégration / Checkov — audit de la configuration (pull_request) Successful in 43s
c786d8b790
LE DÉFAUT. La première version traitait tout code de retour non nul de
Trivy comme « un défaut a été trouvé ». Or Trivy sort aussi en erreur
quand il ne peut pas télécharger sa base de vulnérabilités : réseau
coupé, quota, miroir indisponible. La chaîne aurait rougi sans qu'aucun
défaut existe, et un rouge qui n'est pas une information finit par être
ignoré — c'est exactement le reproche que test-hygiene-bancs.sh fait aux
autres.

LA FORME RETENUE. « --exit-code 0 » toujours, sortie JSON, et c'est le
DÉCOMPTE lu dans le rapport qui décide. Pas de rapport exploitable, pas
de verdict : l'étape se déclare sautée et laisse passer.

.forgejo/scripts/trivy-compter.py rend le nombre de constats hauts et
critiques, ou « ERREUR » si le fichier n'existe pas ou n'est pas du JSON.
La distinction est le cœur du correctif : ERREUR n'est pas zéro.

Le décompte est un script et non un heredoc dans le workflow, parce
qu'un heredoc indenté dans un bloc YAML rend à Python des lignes à
espaces de tête et meurt sur une IndentationError.

ÉPROUVÉ, PAS SUPPOSÉ. L'étape a été extraite du YAML et rejouée sous
dash, le shell du runner :

  - dépôt réel, empreinte juste .... code 0, vuln+secret 0 constat,
                                     misconfig 2 constats en warned
  - empreinte fausse .............. code 1, « on n'exécute pas un
                                     binaire non vérifié »
  - rapport illisible ou absent .... « ERREUR », étape sautée

Bancs rejoués : test-hygiene-workflows.sh, test-hygiene-bancs.sh.
L'étape a été écrite en croyant curl présent dans le conteneur du job Python.
Il ne l'est pas : python:3.12-slim le purge avec ses dépendances de
construction, ce que les jobs « terraform » et « meta » savaient déjà
puisqu'ils l'installent tous les deux avec le commentaire « absents de l'image
slim ». Vérifié sur l'empreinte exacte que le job épingle : curl est absent,
tar et sha256sum sont là.

L'effet n'était pas un rouge, c'était pire. « if ! curl » attrapait le code 127
comme un échec de téléchargement, l'étape rapportait « Trivy (secrets,
vulnérabilités) | skipped | archive non téléchargeable » et sortait à zéro. La
chaîne restait verte, la synthèse portait une ligne rassurante, et le dépôt
n'était jamais analysé — le vert non informatif que l'en-tête de cette même
étape dit vouloir éviter.

Trois changements, et le troisième est celui qui compte :

- curl rejoint l'étape d'installation du job, comme dans les deux autres.
- Un garde « command -v curl » précède le téléchargement et ÉCHOUE. Un outil
  absent n'est pas une panne de réseau : c'est un défaut de la chaîne, et le
  repli « sauté » ne couvre plus que ce pour quoi il est écrit. Sans ce garde,
  la même faute repasserait en silence à la prochaine image.
- Les exclusions voyagent en paramètres positionnels. « $exclus » nu est le
  SC2086 que la tâche « meta » refuse — c'est ce qui la faisait rougir sur
  cette branche — et le quoter en aurait fait un seul argument.

Le commentaire annonçait aussi que Trivy voit « une image de base
vulnérable ». Non : « trivy fs » lit l'arbre du dépôt, les CVE d'une image
construite demandent « trivy image ». Laisser la phrase ferait porter au
rapport EC04 une couverture qu'il n'a pas.

Enfin, trivy-compter.py passe ruff format, qui le refusait et faisait rougir le
job Python.
docs : les §5 « comment le vérifier » se rejouent réellement (#269)
All checks were successful
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 9s
Intégration / Terraform — format, validité et lint (pull_request) Successful in 30s
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Successful in 46s
Intégration / Workflows — lint et audit de sécurité (pull_request) Successful in 17s
Intégration / Checkov — audit de la configuration (pull_request) Successful in 42s
Intégration / Python — qualité, tests et dépendances (pull_request) Successful in 6m11s
c4eba2b02a
Ces trois sections existent pour qu'on ne nous croie pas sur parole, et c'est
la première chose qu'un correcteur tape. Rejouées ici, elles rendaient une
erreur ou du vide.

EC06. « valeur_kw » n'existe pas dans public.prevision : la colonne est
« valeur_prevue_kw » (migration 0011). La requête montre en plus
« modele_version », qui dit qui a produit la ligne. Les deux commandes mlflow
étaient des inventions — « runs list » prend « --experiment-id », et l'accès
par alias est une API Python, pas une sous-commande. Un bloc MlflowClient les
remplace, et il fait d'une pierre deux coups : il imprime les quatre métriques
que la surveillance de dérive relit, donc il répond aussi à « la dérive
mesure-t-elle quelque chose aujourd'hui ».

Car elle ne mesure que si la version promue les porte. La référence figée est
écrite par l'entraînement, pas par la promotion : « reference_promue.lire »
rend None pour toute version antérieure au #117, et la passe publie alors une
tentative sans mesure. Le §4 le dit et le §6 le porte comme ce qui n'est pas
livré — le code est en place et la passe l'appelle, ce qui manque est une
promotion postérieure au ticket.

EC05. « mesure_horaire » n'a pas de colonne « horodatage » : l'agrégat continu
nomme son seau « heure » (migration 0016). Et « silver.mesure_minute » n'existe
nulle part : la zone argent est en Parquet dans MinIO, pas en base. La requête
porte donc sur public.qualite_jour, qui est exactement la preuve annoncée au §3
— relèves attendues, manquantes, et la répartition par méthode d'imputation —
et le script echantillon-imputation.py montre les quatre méthodes sans même
toucher au serveur. Le §1 dit maintenant que sa colonne « Code » nomme ce qui
écrit la zone, et que seule la zone or est interrogeable en SQL.

EC03. L'API des tâches ne rend pas de champ « conclusion » ; le verdict est
dans « status ». Le jq imprimait null sur chaque ligne. Le chiffre du §4 est
relevé de nouveau et daté, parce qu'il bouge à chaque exécution : 2 846 tâches,
94,3 % vertes au 10/09 à 15 h 00.
docs : les commandes des §5, rejouées sur le serveur cette fois (#269)
All checks were successful
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 9s
Intégration / Terraform — format, validité et lint (pull_request) Successful in 31s
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Successful in 46s
Intégration / Workflows — lint et audit de sécurité (pull_request) Successful in 18s
Intégration / Checkov — audit de la configuration (pull_request) Successful in 44s
Intégration / Python — qualité, tests et dépendances (pull_request) Successful in 6m15s
763bf7e293
Le commit précédent corrigeait les §5 d'après le schéma des migrations. Les
avoir joués sur la machine change trois choses de plus, et la troisième change
un verdict.

LA BASE NE S'APPELLE PAS « enervision ». Elle n'existe pas sous ce nom : le
serveur porte « enervision_prod » et « enervision_preprod ». Toutes les lignes
psql d'EC05 et d'EC06 échouaient donc avant même de lire une table, sur un
« FATAL : la base de données n'existe pas ». Elles prennent la forme des
manuels — conteneur, port 5433, docs/runbooks/etl.md.

MESURER LA FRAÎCHEUR SUR L'AGRÉGAT HORAIRE FAIT DOUTER DE LA CADENCE POUR
RIEN. La requête rendait une à deux heures d'âge, ce qui est normal : la
politique laisse l'heure en cours dehors (`end_offset => 1 hour`), sans quoi la
moyenne bougerait à chaque passage. La fraîcheur annoncée au §2 est celle de la
série à la minute, que lit le pavé « état des sites » : 13 min 20 s au relevé
du 10/09 à 17 h 02, dans la fenêtre de 6 à 15 min. Les deux requêtes sont là
maintenant, avec ce que chacune mesure.

ET LE §6 D'EC06 PASSE D'UNE CONDITION À UN CONSTAT. La version qui porte
l'alias production est la 6, entraînée le 08/09 et remise en place le 09/09 par
le retour arrière de la recette #47. Son exécution porte « modele_mae » mais ni
« entrees_moyenne_kw », ni « entrees_ecart_type_kw », ni « entrees_n » : la
référence figée que la dérive relit n'y est pas. « reference_promue.lire » rend
None, et la passe horaire publie une tentative sans mesure. Ce qui manque n'est
pas du code — il est en place et la passe l'appelle — mais un réentraînement
postérieur au #117, puis sa promotion.

Les deux commandes mlflow deviennent des appels à l'API REST du serveur de
suivi : rien à installer, et ce sont exactement celles qui ont produit le
constat ci-dessus.

Enfin, un commentaire du §5 d'EC03 annonçait « le taux de vert » au-dessus
d'une commande qui ne rend que le total. Il dit maintenant ce qu'elle fait, et
comment le taux se calcule.
Member

Relu, et corrigé sur la branche plutôt qu'en aller-retour : le gel est demain 9 h 00. Trois commits ajoutés — 89f03ff pour la chaîne, c4eba2b et 763bf7e pour les documents. Ce que la relecture a trouvé, dans l'ordre de gravité.

1. Trivy n'analysait rien, et la chaîne était verte

L'étape a été écrite en supposant curl présent dans l'image du job Python. Il ne l'est pas : python:3.12-slim le purge avec ses dépendances de construction. Vérifié en jouant l'image sur l'empreinte exacte que le job épingle — curl ABSENT, tar et sha256sum présents. Les jobs terraform et meta l'installent tous les deux, avec le commentaire « absents de l'image slim » ; celui-ci ne le faisait pas parce que rien n'en avait eu besoin avant.

L'effet n'était pas un rouge, c'était pire : if ! curl attrapait le code 127 comme un échec de téléchargement, l'étape rapportait Trivy (secrets, vulnérabilités) | skipped | archive non téléchargeable et sortait à zéro. Exactement le vert non informatif que l'en-tête de l'étape dit vouloir éviter.

Trois correctifs : curl rejoint l'étape d'installation ; un garde command -v curl précède le téléchargement et échoue (un outil absent n'est pas une panne de réseau, et sans ce garde la même faute repasserait en silence à la prochaine image) ; les exclusions voyagent en paramètres positionnels.

2. La PR était rouge sur ses deux jobs

Deux causes, reproduites en local avant correction :

  • Workflows : SC2086 × 4 sur $exclus, confirmé en jouant actionlint + shellcheck sur le fichier d'avant. Le dépôt applique déjà cette règle — voir le # shellcheck disable=SC2086 de ci.yml:1192.
  • Python : ruff format --check refusait trivy-compter.py, rejoué avec ruff 0.16.5, la version épinglée.

3. Les §5 « comment le vérifier » ne se rejouaient pas

C'est la section qu'un correcteur tape en premier. Jouées sur le serveur :

  • La base ne s'appelle pas enervision. Elle n'existe pas sous ce nom — le serveur porte enervision_prod et enervision_preprod. Toutes les lignes psql d'EC05 et EC06 mouraient sur un FATAL : la base de données n'existe pas. Elles prennent la forme des manuels : conteneur, port 5433.
  • EC06 : valeur_kw n'existe pas, la colonne est valeur_prevue_kw (migration 0011). Les deux commandes mlflow étaient des inventions — runs list prend --experiment-id, et l'accès par alias est une API Python, pas une sous-commande. Remplacées par l'API REST du serveur de suivi, qui ne demande rien à installer.
  • EC05 : mesure_horaire n'a pas de colonne horodatage, l'agrégat nomme son seau heure (migration 0016) ; et silver.mesure_minute n'existe nulle part — la zone argent est en Parquet dans MinIO, pas en base. La requête porte maintenant sur public.qualite_jour, qui est précisément la preuve annoncée au §3 : relevé du 09/09, sept sites, de 0 à 68 minutes non comblées sur 1 440.
  • EC03 : l'API des tâches ne rend pas de champ conclusion, le verdict est dans status ; le jq imprimait null sur chaque ligne.
  • Une précision ajoutée qui aurait fait douter de la cadence pour rien : mesurer la fraîcheur sur l'agrégat horaire rend 1 à 2 h d'âge, ce qui est normal (end_offset => 1 hour). La fraîcheur du §2 se lit sur la série à la minute : 13 min 20 s au relevé du 10/09 à 17 h 02, dans la fenêtre annoncée de 6 à 15 min.

4. Ta question 1 : le §6 d'EC06 était trop court

Relevé sur le registre, ce soir : la version qui porte l'alias production est la 6, entraînée le 08/09 et remise en place le 09/09 par le retour arrière de la recette #47. Son exécution porte modele_mae mais ni entrees_moyenne_kw, ni entrees_ecart_type_kw, ni entrees_n. reference_promue.lire rend donc None et la passe horaire publie une tentative sans mesure : la surveillance de dérive ne mesure rien aujourd'hui. Le §4 dit le mécanisme, le §6 dit le fait, daté. Ce qui manque n'est pas du code — il est en place et la passe l'appelle — mais un réentraînement postérieur au #117, puis sa promotion.

5. Ta question 2 : misconfig non bloquante

D'accord à J-1, à la condition que le #269 porte les deux constats avec leur date de bascule. Mesurés ici avec trivy 0.74.0 sur une extraction propre de la branche, puis confirmés par la chaîne : infra/terraform/stockage.tf AZU-0012 CRITICAL et infra/compose/postgres/Dockerfile DS-0002 HIGH.

Une correction de portée

Le corps de la PR et le commentaire de l'étape annonçaient que Trivy voit « une image de base vulnérable ». Non : trivy fs lit l'arbre du dépôt, les CVE d'une image construite demandent trivy image. Laissé tel quel, cela aurait fait porter au rapport EC04 une couverture qu'il n'a pas. Le commentaire est corrigé ; le corps de la PR, lui, garde la phrase — à ajuster si tu republies le texte ailleurs.

Ce que la chaîne rend maintenant

Les six tâches sont vertes sur 763bf7e, et le journal du run 753 montre que le vert a été gagné :

Setting up curl (7.88.1-10+deb12u15) ...
/tmp/trivy_0.74.0_Linux-64bit.tar.gz: OK
[vulndb] Artifact successfully downloaded
| Trivy (secrets, vulnérabilités) | réussi        | aucun constat haut ou critique |
| Trivy (configuration)           | avertissement | 2 constat(s), suivis par le #269 |

Reste à faire, hors de cette PR

  • Porter les deux constats misconfig dans le #269 avec leur date de bascule en bloquant.
  • --skip-dirs node_modules ne couvre pas les node_modules imbriqués (Trivy compare le motif depuis la racine du scan). Sans effet ici — ce job n'en a pas — mais à savoir le jour où l'exclusion comptera.
  • Un contrôle dans test-hygiene-workflows.sh : tout outil externe appelé dans un run: doit être installé par le job. C'est ce qui aurait attrapé le curl tout seul.

Réserve de forme : j'ai poussé trois commits sur cette branche, mon approbation porte donc en partie sur mon propre travail. L'auteur reste Lénaïc et le verrou tient formellement, mais une seconde paire d'yeux sur 89f03ff avant le gel ne serait pas du luxe.

Relu, et corrigé sur la branche plutôt qu'en aller-retour : le gel est demain 9 h 00. Trois commits ajoutés — `89f03ff` pour la chaîne, `c4eba2b` et `763bf7e` pour les documents. Ce que la relecture a trouvé, dans l'ordre de gravité. ## 1. Trivy n'analysait rien, et la chaîne était verte L'étape a été écrite en supposant `curl` présent dans l'image du job Python. Il ne l'est pas : `python:3.12-slim` le purge avec ses dépendances de construction. Vérifié en jouant l'image sur l'empreinte exacte que le job épingle — `curl ABSENT`, `tar` et `sha256sum` présents. Les jobs `terraform` et `meta` l'installent tous les deux, avec le commentaire « absents de l'image slim » ; celui-ci ne le faisait pas parce que rien n'en avait eu besoin avant. L'effet n'était pas un rouge, c'était pire : `if ! curl` attrapait le code 127 comme un échec de téléchargement, l'étape rapportait `Trivy (secrets, vulnérabilités) | skipped | archive non téléchargeable` et sortait à zéro. Exactement le vert non informatif que l'en-tête de l'étape dit vouloir éviter. Trois correctifs : `curl` rejoint l'étape d'installation ; un garde `command -v curl` précède le téléchargement et **échoue** (un outil absent n'est pas une panne de réseau, et sans ce garde la même faute repasserait en silence à la prochaine image) ; les exclusions voyagent en paramètres positionnels. ## 2. La PR était rouge sur ses deux jobs Deux causes, reproduites en local avant correction : - **Workflows** : `SC2086` × 4 sur `$exclus`, confirmé en jouant actionlint + shellcheck sur le fichier d'avant. Le dépôt applique déjà cette règle — voir le `# shellcheck disable=SC2086` de ci.yml:1192. - **Python** : `ruff format --check` refusait `trivy-compter.py`, rejoué avec ruff 0.16.5, la version épinglée. ## 3. Les §5 « comment le vérifier » ne se rejouaient pas C'est la section qu'un correcteur tape en premier. Jouées sur le serveur : - **La base ne s'appelle pas `enervision`.** Elle n'existe pas sous ce nom — le serveur porte `enervision_prod` et `enervision_preprod`. Toutes les lignes `psql` d'EC05 et EC06 mouraient sur un `FATAL : la base de données n'existe pas`. Elles prennent la forme des manuels : conteneur, port 5433. - **EC06** : `valeur_kw` n'existe pas, la colonne est `valeur_prevue_kw` (migration 0011). Les deux commandes `mlflow` étaient des inventions — `runs list` prend `--experiment-id`, et l'accès par alias est une API Python, pas une sous-commande. Remplacées par l'API REST du serveur de suivi, qui ne demande rien à installer. - **EC05** : `mesure_horaire` n'a pas de colonne `horodatage`, l'agrégat nomme son seau `heure` (migration 0016) ; et `silver.mesure_minute` n'existe nulle part — la zone argent est en Parquet dans MinIO, pas en base. La requête porte maintenant sur `public.qualite_jour`, qui est précisément la preuve annoncée au §3 : relevé du 09/09, sept sites, de 0 à 68 minutes non comblées sur 1 440. - **EC03** : l'API des tâches ne rend pas de champ `conclusion`, le verdict est dans `status` ; le `jq` imprimait `null` sur chaque ligne. - Une précision ajoutée qui aurait fait douter de la cadence pour rien : mesurer la fraîcheur sur l'agrégat horaire rend 1 à 2 h d'âge, ce qui est normal (`end_offset => 1 hour`). La fraîcheur du §2 se lit sur la série à la minute : **13 min 20 s** au relevé du 10/09 à 17 h 02, dans la fenêtre annoncée de 6 à 15 min. ## 4. Ta question 1 : le §6 d'EC06 était trop court Relevé sur le registre, ce soir : la version qui porte l'alias `production` est la **6**, entraînée le 08/09 et remise en place le 09/09 par le retour arrière de la recette #47. Son exécution porte `modele_mae` mais ni `entrees_moyenne_kw`, ni `entrees_ecart_type_kw`, ni `entrees_n`. `reference_promue.lire` rend donc `None` et la passe horaire publie une tentative sans mesure : **la surveillance de dérive ne mesure rien aujourd'hui**. Le §4 dit le mécanisme, le §6 dit le fait, daté. Ce qui manque n'est pas du code — il est en place et la passe l'appelle — mais un réentraînement postérieur au #117, puis sa promotion. ## 5. Ta question 2 : `misconfig` non bloquante D'accord à J-1, à la condition que le #269 porte les deux constats avec leur date de bascule. Mesurés ici avec trivy 0.74.0 sur une extraction propre de la branche, puis confirmés par la chaîne : `infra/terraform/stockage.tf` AZU-0012 CRITICAL et `infra/compose/postgres/Dockerfile` DS-0002 HIGH. ## Une correction de portée Le corps de la PR et le commentaire de l'étape annonçaient que Trivy voit « une image de base vulnérable ». Non : `trivy fs` lit l'arbre du dépôt, les CVE d'une image construite demandent `trivy image`. Laissé tel quel, cela aurait fait porter au rapport EC04 une couverture qu'il n'a pas. Le commentaire est corrigé ; le corps de la PR, lui, garde la phrase — à ajuster si tu republies le texte ailleurs. ## Ce que la chaîne rend maintenant Les six tâches sont vertes sur `763bf7e`, et le journal du run 753 montre que le vert a été gagné : ``` Setting up curl (7.88.1-10+deb12u15) ... /tmp/trivy_0.74.0_Linux-64bit.tar.gz: OK [vulndb] Artifact successfully downloaded | Trivy (secrets, vulnérabilités) | réussi | aucun constat haut ou critique | | Trivy (configuration) | avertissement | 2 constat(s), suivis par le #269 | ``` ## Reste à faire, hors de cette PR - Porter les deux constats `misconfig` dans le #269 avec leur date de bascule en bloquant. - `--skip-dirs node_modules` ne couvre pas les `node_modules` imbriqués (Trivy compare le motif depuis la racine du scan). Sans effet ici — ce job n'en a pas — mais à savoir le jour où l'exclusion comptera. - Un contrôle dans `test-hygiene-workflows.sh` : tout outil externe appelé dans un `run:` doit être installé par le job. C'est ce qui aurait attrapé le `curl` tout seul. **Réserve de forme** : j'ai poussé trois commits sur cette branche, mon approbation porte donc en partie sur mon propre travail. L'auteur reste Lénaïc et le verrou tient formellement, mais une seconde paire d'yeux sur `89f03ff` avant le gel ne serait pas du luxe.
Merge branch 'develop' into lenaic/269-docs-epreuves-et-trivy
All checks were successful
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 9s
Intégration / Terraform — format, validité et lint (pull_request) Successful in 29s
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Successful in 48s
Intégration / Workflows — lint et audit de sécurité (pull_request) Successful in 18s
Intégration / Checkov — audit de la configuration (pull_request) Successful in 46s
Intégration / Python — qualité, tests et dépendances (pull_request) Successful in 6m20s
082e90ff58
gabriel approved these changes 2026-09-10 17:18:35 +00:00
gabriel merged commit 9707de8d3a into develop 2026-09-10 17:28:51 +00:00
gabriel deleted branch lenaic/269-docs-epreuves-et-trivy 2026-09-10 17:28:51 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
g2/enervision!270
No description provided.