Skip to content

fix(labs): rendre les 84 labs rejouables en séquence, et le prouver - #27

Open
stephrobert wants to merge 2 commits into
mainfrom
fix/campagne-validation-et-sequence-l1
Open

fix(labs): rendre les 84 labs rejouables en séquence, et le prouver#27
stephrobert wants to merge 2 commits into
mainfrom
fix/campagne-validation-et-sequence-l1

Conversation

@stephrobert

Copy link
Copy Markdown
Owner

Première campagne de validation complète du catalogue : les 84 labs rejoués sur KVM avec contrôle négatif (rouge sans la solution, vert avec). Dix défauts sont remontés, tous invisibles jusque-là. Les tests d'un lab ne tournent que si quelqu'un le joue, et personne ne les enchaînait.

Trois labs étaient purement infaisables. l4-reverse-proxy-lb et l4-ldap-integration démarraient leur service sur le second nœud sans ouvrir le port dans son pare-feu : HAProxy rendait un 503, SSSD ne résolvait rien. l2-filesystem-create-xfs n'était rejouable qu'une fois, son cleanup laissant le marqueur qui garde son setup.

Six cleanup.yaml ne pouvaient pas s'exécuter : « . fichier || exit 0 » ne protège rien, un sh POSIX non interactif meurt sur le source avant d'atteindre le ||. Leur dsoxlab reset échouait, donc l'apprenant restait bloqué.

Le reste tient à l'état partagé entre labs, qui se joue toujours de la même façon : le lab fautif reste vert, et c'est le suivant qui échoue. Trois labs laissaient une partition sur le disque commun, trois autres laissaient leurs comptes (alice, appuser, smbuser…) et drill-firewall laissait firewalld désactivé, ce qui cassait le capstone RHCSA.

Un cas inverse mérite d'être noté : sur l2-luks-encryption, c'était le TEST qui était faux, pas la solution. Il cherchait le « 2 » de Version: dans une tranche de 8 caractères, alors que l'alignement de cryptsetup le place en 9e position. Le volume était en LUKS2 depuis le début.

Trois garde-fous accompagnent ces corrections, chacun vérifié en le faisant échouer :

  • test_playbooks_syntaxe.py joue ansible-playbook --syntax-check sur les 129 playbooks. Un YAML valide ne prouve pas qu'Ansible charge les tâches : une apostrophe française dans un bloc shell casse le découpage des arguments, et cela ne se voyait qu'à l'exécution, en rc=4 sans une seule tâche jouée.
  • test_marqueurs_setup_cleanup.py exige qu'un cleanup rende ce que son setup garde : marqueurs « creates: » et comptes créés. Il a trouvé deux défauts que la lecture manuelle avait manqués, dont smbuser.
  • verify-solutions.py compare l'état du disque partagé avant et après chaque lab vm, et nomme le lab qui salit au lieu de laisser échouer le suivant.

Enfin, la séquence l1 exigeait d'éditer un fichier sans jamais l'avoir enseigné : l1-first-terminal passe en tête et gagne une section sur nano et la survie sous vi. Le challenge interdit la redirection, l'éditeur était donc obligatoire et introuvable dans le cours.

stephrobert and others added 2 commits July 27, 2026 13:59
Première campagne de validation complète du catalogue : les 84 labs rejoués
sur KVM avec contrôle négatif (rouge sans la solution, vert avec). Dix défauts
sont remontés, tous invisibles jusque-là. Les tests d'un lab ne tournent que si
quelqu'un le joue, et personne ne les enchaînait.

Trois labs étaient purement infaisables. l4-reverse-proxy-lb et
l4-ldap-integration démarraient leur service sur le second nœud sans ouvrir le
port dans son pare-feu : HAProxy rendait un 503, SSSD ne résolvait rien.
l2-filesystem-create-xfs n'était rejouable qu'une fois, son cleanup laissant le
marqueur qui garde son setup.

Six cleanup.yaml ne pouvaient pas s'exécuter : « . fichier || exit 0 » ne
protège rien, un sh POSIX non interactif meurt sur le source avant d'atteindre
le ||. Leur dsoxlab reset échouait, donc l'apprenant restait bloqué.

Le reste tient à l'état partagé entre labs, qui se joue toujours de la même
façon : le lab fautif reste vert, et c'est le suivant qui échoue. Trois labs
laissaient une partition sur le disque commun, trois autres laissaient leurs
comptes (alice, appuser, smbuser…) et drill-firewall laissait firewalld
désactivé, ce qui cassait le capstone RHCSA.

Un cas inverse mérite d'être noté : sur l2-luks-encryption, c'était le TEST qui
était faux, pas la solution. Il cherchait le « 2 » de Version: dans une tranche
de 8 caractères, alors que l'alignement de cryptsetup le place en 9e position.
Le volume était en LUKS2 depuis le début.

Trois garde-fous accompagnent ces corrections, chacun vérifié en le faisant
échouer :

- test_playbooks_syntaxe.py joue ansible-playbook --syntax-check sur les 129
  playbooks. Un YAML valide ne prouve pas qu'Ansible charge les tâches : une
  apostrophe française dans un bloc shell casse le découpage des arguments, et
  cela ne se voyait qu'à l'exécution, en rc=4 sans une seule tâche jouée.
- test_marqueurs_setup_cleanup.py exige qu'un cleanup rende ce que son setup
  garde : marqueurs « creates: » et comptes créés. Il a trouvé deux défauts que
  la lecture manuelle avait manqués, dont smbuser.
- verify-solutions.py compare l'état du disque partagé avant et après chaque
  lab vm, et nomme le lab qui salit au lieu de laisser échouer le suivant.

Enfin, la séquence l1 exigeait d'éditer un fichier sans jamais l'avoir
enseigné : l1-first-terminal passe en tête et gagne une section sur nano et la
survie sous vi. Le challenge interdit la redirection, l'éditeur était donc
obligatoire et introuvable dans le cours.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…jamais traduite

Le job « Pre-commit parity » joue les hooks sur TOUS les fichiers, là où un
commit ne les joue que sur les fichiers touchés. Il révélait donc 27 problèmes
ruff préexistants, dans du code que personne n'avait relinté depuis que le hook
utilise `uvx ruff` (donc la dernière version publiée, pas un pin).

Dix-sept se corrigent d'eux-mêmes (imports, `re.M` en `re.MULTILINE`). Les dix
autres demandaient une décision :

- cinq subprocess.run sans `check` explicite, dans des tests de labs et le
  conftest racine. Tous JUGENT le code de retour, ils ne doivent surtout pas
  lever dessus : `check=False` est rendu explicite.
- `datetime.date.today()` sans fuseau, dans le test l1 qui compare l'année
  courante. Remplacé par une heure locale assumée.
- un `if` imbriqué inutile dans le conftest racine.
- un shebang sans bit exécutable sur gen_catalog.py.

Les deux dernières étaient le même défaut, et il avait une conséquence
visible : deux conditions « if lang == en else » dont les deux branches
disaient exactement la même chose. La variante anglaise n'avait jamais été
écrite, si bien que le README ANGLAIS affichait sa légende de catalogue en
français. Elle est traduite, et les deux catalogues sont régénérés.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant