dsoxlab 0.2.2__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/workflows/appliance.yml +42 -6
  2. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/CHANGELOG.fr.md +74 -4
  3. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/CHANGELOG.md +70 -3
  4. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/PKG-INFO +44 -2
  5. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/README.fr.md +45 -2
  6. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/README.md +43 -1
  7. dsoxlab-0.2.3/docs/appliance.fr.md +288 -0
  8. dsoxlab-0.2.3/docs/appliance.md +277 -0
  9. dsoxlab-0.2.3/docs/assets/appliance-connexion.png +0 -0
  10. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/catalog-author.fr.md +63 -1
  11. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/catalog-author.md +62 -1
  12. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/commands.fr.md +11 -2
  13. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/commands.md +10 -2
  14. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/contract-v1.fr.md +2 -1
  15. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/contract-v1.md +2 -1
  16. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/files.fr.md +5 -3
  17. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/files.md +4 -3
  18. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/learner.fr.md +53 -8
  19. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/learner.md +48 -7
  20. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/trainer.fr.md +16 -3
  21. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/trainer.md +16 -3
  22. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/README.md +6 -2
  23. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/pyproject.toml +1 -1
  24. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/uv.lock +1 -1
  25. dsoxlab-0.2.2/docs/appliance.fr.md +0 -169
  26. dsoxlab-0.2.2/docs/appliance.md +0 -155
  27. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.bestpractices.json +0 -0
  28. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/CODEOWNERS +0 -0
  29. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/FUNDING.yml +0 -0
  30. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  31. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  32. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  33. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  34. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/dependabot.yml +0 -0
  35. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/workflows/ci.yml +0 -0
  36. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/workflows/plumber.yml +0 -0
  37. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/workflows/release.yml +0 -0
  38. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.github/workflows/scorecard.yml +0 -0
  39. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.gitignore +0 -0
  40. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.plumber.yaml +0 -0
  41. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.poutine.yml +0 -0
  42. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/.pre-commit-config.yaml +0 -0
  43. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/CODE_OF_CONDUCT.fr.md +0 -0
  44. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/CODE_OF_CONDUCT.md +0 -0
  45. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/CONTRIBUTING.fr.md +0 -0
  46. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/CONTRIBUTING.md +0 -0
  47. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/LICENSE +0 -0
  48. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/NOTICE +0 -0
  49. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/RELEASING.fr.md +0 -0
  50. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/RELEASING.md +0 -0
  51. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/SECURITY.fr.md +0 -0
  52. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/SECURITY.md +0 -0
  53. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/README.fr.md +0 -0
  54. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/README.md +0 -0
  55. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/appliance-bureau.png +0 -0
  56. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/appliance-lab-vm.png +0 -0
  57. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/dsoxlab-icon-dark.svg +0 -0
  58. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/dsoxlab-icon-mono.svg +0 -0
  59. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/dsoxlab-icon.svg +0 -0
  60. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/dsoxlab-lockup-dark.svg +0 -0
  61. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/dsoxlab-lockup-light.svg +0 -0
  62. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/dsoxlab-lockup-mono.svg +0 -0
  63. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-icon-1024.png +0 -0
  64. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-icon-256.png +0 -0
  65. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-icon-512.png +0 -0
  66. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-icon-dark-1024.png +0 -0
  67. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-icon-dark-512.png +0 -0
  68. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-lockup-dark-1024.png +0 -0
  69. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-lockup-dark-2048.png +0 -0
  70. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-lockup-light-1024.png +0 -0
  71. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-lockup-light-2048.png +0 -0
  72. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-social-preview-dark.png +0 -0
  73. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/assets/brand/png/dsoxlab-social-preview.png +0 -0
  74. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/brand.fr.md +0 -0
  75. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/brand.md +0 -0
  76. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/demo.gif +0 -0
  77. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/demo.tape +0 -0
  78. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/exit-codes.fr.md +0 -0
  79. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/exit-codes.md +0 -0
  80. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/infra-only.fr.md +0 -0
  81. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/infra-only.md +0 -0
  82. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/machine-output.fr.md +0 -0
  83. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/docs/machine-output.md +0 -0
  84. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/champ-inconnu.json +0 -0
  85. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/complet.json +0 -0
  86. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/position-negative.json +0 -0
  87. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/position-non-numerique.json +0 -0
  88. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/racine-chaine.json +0 -0
  89. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/racine-liste.json +0 -0
  90. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/racine-nulle.json +0 -0
  91. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/section-liste.json +0 -0
  92. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/tronque.json +0 -0
  93. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/context_json/vide.json +0 -0
  94. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/capstone-exam-score.yaml +0 -0
  95. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/schema-version-courante.yaml +0 -0
  96. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/schema-version-future.yaml +0 -0
  97. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/schema-version-mauvais-type.yaml +0 -0
  98. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/shell-fixtures-nested.yaml +0 -0
  99. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/shell-minimal.yaml +0 -0
  100. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/shell-services-init.yaml +0 -0
  101. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/shell-services.yaml +0 -0
  102. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/vm-multi-target.yaml +0 -0
  103. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/lab_yaml/vm-snapshot-requis.yaml +0 -0
  104. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/meta_yml/full-infra.yml +0 -0
  105. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/meta_yml/schema-version-courante.yml +0 -0
  106. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/meta_yml/schema-version-future.yml +0 -0
  107. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/avec-bastion.json +0 -0
  108. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/bastion-sans-ip.json +0 -0
  109. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/hosts-liste.json +0 -0
  110. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/ip-numerique.json +0 -0
  111. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/outputs-aplatis.json +0 -0
  112. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/outputs-encapsules.json +0 -0
  113. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/sans-hosts.json +0 -0
  114. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/value-non-objet.json +0 -0
  115. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/corpus/terraform_outputs/vide.json +0 -0
  116. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/dict/yaml_contract.dict +0 -0
  117. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/fuzz_context_json.py +0 -0
  118. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/fuzz_lab_yaml.py +0 -0
  119. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/fuzz_meta_yaml.py +0 -0
  120. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/fuzz/fuzz_terraform_outputs.py +0 -0
  121. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/dsoxlab-appliance.pkr.hcl +0 -0
  122. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/faire-ova.sh +0 -0
  123. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/http/preseed.cfg +0 -0
  124. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/scripts/10-base.sh +0 -0
  125. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/scripts/20-outils.sh +0 -0
  126. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/scripts/30-premier-demarrage.sh +0 -0
  127. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/scripts/40-reseau-portable.sh +0 -0
  128. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/packer/scripts/90-nettoyage.sh +0 -0
  129. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/schemas/lab.schema.json +0 -0
  130. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/schemas/meta.schema.json +0 -0
  131. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/scripts/check-release.py +0 -0
  132. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/scripts/generer-doc.py +0 -0
  133. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/scripts/generer-png-marque.py +0 -0
  134. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/scripts/parcours-distribution.py +0 -0
  135. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/__init__.py +0 -0
  136. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/__init__.py +0 -0
  137. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/_amorcage.py +0 -0
  138. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/_barres.py +0 -0
  139. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/_commun.py +0 -0
  140. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/_socle.py +0 -0
  141. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/_validation.py +0 -0
  142. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/auteur.py +0 -0
  143. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/catalogues.py +0 -0
  144. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/contexte.py +0 -0
  145. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/demarrage.py +0 -0
  146. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/destruction.py +0 -0
  147. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/diagnostic.py +0 -0
  148. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/etat.py +0 -0
  149. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/indices.py +0 -0
  150. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/infrastructure.py +0 -0
  151. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/instructeur.py +0 -0
  152. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/parcours.py +0 -0
  153. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/cli/progression.py +0 -0
  154. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/config.py +0 -0
  155. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/discovery/__init__.py +0 -0
  156. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/discovery/repo.py +0 -0
  157. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/discovery/scanner.py +0 -0
  158. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/exit_codes.py +0 -0
  159. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/i18n/__init__.py +0 -0
  160. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/i18n/strings/__init__.py +0 -0
  161. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/i18n/strings/en.py +0 -0
  162. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/i18n/strings/fr.py +0 -0
  163. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/__init__.py +0 -0
  164. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/ansible.py +0 -0
  165. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/credentials.py +0 -0
  166. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/inventory.py +0 -0
  167. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/libvirt.py +0 -0
  168. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/pont.py +0 -0
  169. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/snapshot/__init__.py +0 -0
  170. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/snapshot/kvm.py +0 -0
  171. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/infra/terraform.py +0 -0
  172. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/interrupt.py +0 -0
  173. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/locking.py +0 -0
  174. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/logging_setup.py +0 -0
  175. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/models/__init__.py +0 -0
  176. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/models/_contract.py +0 -0
  177. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/models/course.py +0 -0
  178. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/models/hint.py +0 -0
  179. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/models/lab.py +0 -0
  180. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/models/repo.py +0 -0
  181. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/models/runtime.py +0 -0
  182. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/models/schema_version.py +0 -0
  183. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/py.typed +0 -0
  184. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/reporting/__init__.py +0 -0
  185. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/reporting/console.py +0 -0
  186. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/reporting/machine.py +0 -0
  187. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/runtimes/__init__.py +0 -0
  188. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/runtimes/base.py +0 -0
  189. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/runtimes/manager.py +0 -0
  190. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/runtimes/services.py +0 -0
  191. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/runtimes/shell.py +0 -0
  192. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/runtimes/vm.py +0 -0
  193. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/__init__.py +0 -0
  194. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/catalog.py +0 -0
  195. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/demo.py +0 -0
  196. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/doctor.py +0 -0
  197. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/guide_service.py +0 -0
  198. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/host_diagnosis.py +0 -0
  199. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/issue_service.py +0 -0
  200. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/lab_service.py +0 -0
  201. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/lab_state.py +0 -0
  202. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/progress_service.py +0 -0
  203. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/scaffold.py +0 -0
  204. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/support.py +0 -0
  205. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/services/update_check.py +0 -0
  206. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/sessions/__init__.py +0 -0
  207. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/sessions/store.py +0 -0
  208. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/__init__.py +0 -0
  209. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/catalogues.yml +0 -0
  210. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/cloud-init/README.md +0 -0
  211. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/cloud-init/almalinux.yaml.tmpl +0 -0
  212. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/cloud-init/debian.yaml.tmpl +0 -0
  213. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/cloud-init/ubuntu.yaml.tmpl +0 -0
  214. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/README.fr.md +0 -0
  215. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/README.md +0 -0
  216. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/README.fr.md +0 -0
  217. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/README.md +0 -0
  218. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/hints.yaml +0 -0
  219. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/tests/conftest.py +0 -0
  220. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/tests/test_functional.py +0 -0
  221. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/lab.fr.yaml +0 -0
  222. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/lab.yaml +0 -0
  223. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/scenario.fr.md +0 -0
  224. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/scenario.md +0 -0
  225. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/meta.fr.yml +0 -0
  226. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/demo/meta.yml +0 -0
  227. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/README.md +0 -0
  228. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/incus/main.tf +0 -0
  229. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/incus/outputs.tf +0 -0
  230. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/incus/variables.tf +0 -0
  231. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/incus/versions.tf +0 -0
  232. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/kvm/main.tf +0 -0
  233. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/kvm/outputs.tf +0 -0
  234. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/kvm/variables.tf +0 -0
  235. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/kvm/versions.tf +0 -0
  236. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/outscale/main.tf +0 -0
  237. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/outscale/outputs.tf +0 -0
  238. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/outscale/variables.tf +0 -0
  239. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/templates/terraform/outscale/versions.tf +0 -0
  240. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/utils/__init__.py +0 -0
  241. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/utils/fichiers.py +0 -0
  242. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/utils/shell.py +0 -0
  243. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/validators/__init__.py +0 -0
  244. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/validators/content.py +0 -0
  245. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/validators/contract.py +0 -0
  246. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/validators/metadata.py +0 -0
  247. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/src/dsoxlab/validators/structure.py +0 -0
  248. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/__init__.py +0 -0
  249. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/conftest.py +0 -0
  250. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_ansible_availability.py +0 -0
  251. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_catalog.py +0 -0
  252. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_check_release.py +0 -0
  253. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_ci_valide_les_templates.py +0 -0
  254. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_cles_i18n_existantes.py +0 -0
  255. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_cli_smoke.py +0 -0
  256. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_cloud_init_degrade.py +0 -0
  257. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_cloud_init_incus_agent.py +0 -0
  258. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_cloud_init_templates.py +0 -0
  259. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_codes_de_sortie.py +0 -0
  260. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_commande_absente.py +0 -0
  261. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_completion.py +0 -0
  262. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_conteneurs_engendres.py +0 -0
  263. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_contrat_honore.py +0 -0
  264. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_convention_de_nommage.py +0 -0
  265. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_demo.py +0 -0
  266. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_description_alignee.py +0 -0
  267. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_doc_auteur_couvre_les_controles.py +0 -0
  268. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_doctor.py +0 -0
  269. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_doctor_explique.py +0 -0
  270. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_doctor_fix.py +0 -0
  271. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_doctor_installation.py +0 -0
  272. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_doctor_prerequis_vm.py +0 -0
  273. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_doctor_strict.py +0 -0
  274. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_documentation_synchrone.py +0 -0
  275. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_etat_libvirt.py +0 -0
  276. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_executable_absent.py +0 -0
  277. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_fixtures_declarees.py +0 -0
  278. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_guide_service.py +0 -0
  279. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_host_ready_timeout.py +0 -0
  280. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_i18n_coverage.py +0 -0
  281. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_i18n_validators.py +0 -0
  282. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_incus_pool.py +0 -0
  283. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_install_et_contexte.py +0 -0
  284. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_instructor_bootstrap.py +0 -0
  285. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_interruption.py +0 -0
  286. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_issue_service.py +0 -0
  287. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_journal_en_anglais.py +0 -0
  288. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_journalisation.py +0 -0
  289. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_json_output.py +0 -0
  290. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_json_schemas.py +0 -0
  291. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_kvm_disques_apparmor.py +0 -0
  292. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_lab_state.py +0 -0
  293. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_moteur_injoignable.py +0 -0
  294. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_nom_de_pont.py +0 -0
  295. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_note_sans_mesure.py +0 -0
  296. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_outputs_terraform.py +0 -0
  297. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_pager.py +0 -0
  298. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_parcours_distribution.py +0 -0
  299. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_progress_service.py +0 -0
  300. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_provision_ciblee.py +0 -0
  301. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_provision_et_json_services.py +0 -0
  302. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_repertoire_de_travail_annonce.py +0 -0
  303. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_scaffold.py +0 -0
  304. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_schema_version.py +0 -0
  305. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_schemas_sur_documents.py +0 -0
  306. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_services.py +0 -0
  307. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_session_spec.py +0 -0
  308. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_shell_fixtures.py +0 -0
  309. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_snapshot_kvm.py +0 -0
  310. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_sondes_des_tests_docker.py +0 -0
  311. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_sondes_virsh.py +0 -0
  312. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_stack_infra.py +0 -0
  313. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_start_sequence.py +0 -0
  314. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_support.py +0 -0
  315. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_support_en_anglais.py +0 -0
  316. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_update_check.py +0 -0
  317. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_validator_voit_tout.py +0 -0
  318. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_validators_content.py +0 -0
  319. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_verrou_depot.py +0 -0
  320. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_versions_supportees.py +0 -0
  321. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests/test_yaml_contract.py +0 -0
  322. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests_e2e/conftest.py +0 -0
  323. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests_e2e/pytest.ini +0 -0
  324. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests_e2e/test_boite_noire.py +0 -0
  325. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests_e2e/test_installation.py +0 -0
  326. {dsoxlab-0.2.2 → dsoxlab-0.2.3}/tests_e2e/test_parcours.py +0 -0
@@ -9,16 +9,23 @@
9
9
  # 2. un build d'image de vingt minutes ne doit ni retarder une publication PyPI,
10
10
  # ni pouvoir la faire échouer.
11
11
  #
12
- # Sur les tags, il ne se déclenche que sur les **mineurs** (`v0.3.0`, `v0.4.0`) :
13
- # l'image n'épingle pas la version de dsoxlab, elle installe la dernière au
14
- # premier démarrage, donc republier un gigaoctet à chaque correctif coûterait
15
- # cher pour ne rien changer.
12
+ # Il se déclenche sur **toute** version publiée, correctifs compris. La règle
13
+ # précédente — les seuls tags mineurs — économisait de la bande passante et
14
+ # coûtait plus cher que ça : elle laissait la doc annoncer une appliance que la
15
+ # dernière release ne portait pas, et obligeait le lecteur à chercher laquelle
16
+ # des releases précédentes en avait une. « La dernière release porte l'image »
17
+ # est la seule phrase qu'on n'a pas à nuancer.
18
+ #
19
+ # Ce que ça ne coûte pas : de l'espace qui s'accumule. Seuls les deux derniers
20
+ # jeux d'images sont conservés (voir l'étape de rétention), et l'image
21
+ # n'épinglant aucune version de dsoxlab, une ancienne n'offre rien d'autre que
22
+ # son poids.
16
23
 
17
24
  name: Appliance
18
25
 
19
26
  on:
20
27
  push:
21
- tags: ["v[0-9]+.[0-9]+.0"]
28
+ tags: ["v[0-9]+.[0-9]+.[0-9]+"]
22
29
  workflow_dispatch:
23
30
  inputs:
24
31
  tag:
@@ -97,6 +104,18 @@ jobs:
97
104
  echo "sum=$sum" >> "$GITHUB_OUTPUT"
98
105
  echo "ISO : $name"
99
106
 
107
+ - name: Prepare the build directory on /mnt
108
+ # `/mnt` has the space (~70 GB against ~14 on `/`), but it belongs to
109
+ # root: the runner cannot create anything there. The first real run of
110
+ # this workflow died on exactly that, four hundredths of a second in —
111
+ # a defect no local build could show, since the directory exists and is
112
+ # writable on a developer's machine.
113
+ run: |
114
+ set -euo pipefail
115
+ sudo mkdir -p "${BUILD_DIR}/out" "${BUILD_DIR}/tmp"
116
+ sudo chown -R "$(id -u):$(id -g)" "${BUILD_DIR}"
117
+ df -h "${BUILD_DIR}"
118
+
100
119
  - name: packer init && validate
101
120
  working-directory: packer
102
121
  env:
@@ -104,7 +123,6 @@ jobs:
104
123
  ISO_SUM: ${{ steps.iso.outputs.sum }}
105
124
  run: |
106
125
  set -euo pipefail
107
- mkdir -p "${BUILD_DIR}/out" "${BUILD_DIR}/tmp"
108
126
  packer init .
109
127
  packer validate \
110
128
  -var "image_version=${GITHUB_REF_NAME#v}" \
@@ -206,6 +224,24 @@ jobs:
206
224
  REPO: ${{ github.repository }}
207
225
  run: |
208
226
  set -euo pipefail
227
+
228
+ # Les deux workflows partent du même tag : celui-ci construit pendant
229
+ # vingt minutes, `release.yml` publie en deux. La Release existe donc
230
+ # en pratique bien avant qu'on arrive ici — mais « en pratique » n'est
231
+ # pas une garantie, et un upload sur une Release absente échouerait
232
+ # sur un message qui ne dirait pas pourquoi. On attend, et on le dit.
233
+ restants=30 # 30 × 20 s = dix minutes
234
+ until gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; do
235
+ restants=$((restants - 1))
236
+ if [ "$restants" -le 0 ]; then
237
+ echo "::error::La Release $TAG n'existe toujours pas après dix minutes."
238
+ echo "::error::Regardez release.yml : s'il a échoué, les images n'ont rien où s'attacher."
239
+ exit 1
240
+ fi
241
+ echo "En attente de la Release $TAG…"
242
+ sleep 20
243
+ done
244
+
209
245
  gh release upload "$TAG" --repo "$REPO" --clobber \
210
246
  "${BUILD_DIR}"/out/*.ova \
211
247
  "${BUILD_DIR}"/out/*.qcow2 \
@@ -9,6 +9,75 @@ et le projet suit le [versionnage sémantique](https://semver.org/lang/fr/).
9
9
 
10
10
  ## [Non publié]
11
11
 
12
+ ## [0.2.3] - 2026-09-26
13
+
14
+ ### Corrigé
15
+
16
+ - **Le workflow de l'appliance n'avait jamais tourné, et il est mort au bout de
17
+ quatre centièmes de seconde.** `mkdir: cannot create directory
18
+ '/mnt/appliance': Permission denied` — sur un runner GitHub, `/mnt`
19
+ appartient à root, et c'est là qu'est la place (environ 70 Go contre 14 sur
20
+ `/`). Aucun build local ne pouvait le montrer : sur une machine de
21
+ développement, ce répertoire existe et s'écrit. Une étape dédiée le crée
22
+ désormais en `sudo` et le remet au runner.
23
+
24
+ - **L'image est publiée à chaque release, et plus seulement aux mineures.**
25
+ L'ancienne règle économisait de la bande passante et coûtait plus qu'elle
26
+ n'économisait : la documentation annonçait une appliance que la dernière
27
+ release ne portait pas, et le lecteur devait deviner laquelle des
28
+ précédentes l'avait. « La dernière release porte l'image » est la seule
29
+ phrase qui n'appelle aucune nuance, et rien ne s'accumule puisque l'étape de
30
+ rétention garde les deux derniers jeux. Les deux workflows partant désormais
31
+ du même tag, l'upload attend que la Release existe au lieu de le supposer —
32
+ et dit quel workflow regarder si elle n'arrive jamais.
33
+
34
+ ### Modifié
35
+
36
+ - **La documentation est un parcours, plus une pile de pages.** Relue de bout
37
+ en bout contre le code, elle portait des ruptures qu'aucune page seule ne
38
+ pouvait révéler :
39
+
40
+ `learner.fr.md` promettait `run` juste après le clonage d'un catalogue, alors
41
+ que **66 des 86 labs du catalogue Linux** sont des labs `vm` : ce `run` sort
42
+ en 2, le `provision` qu'il suggère sort en 1 faute de clé SSH, et ni
43
+ `instructor bootstrap`, ni `start`, ni le mot Terraform n'apparaissaient sur
44
+ la page. Elle nomme maintenant ce qu'un lab `vm` demande à une machine, et
45
+ met `start` en premier — la commande qui joue tout l'ordre en annonçant
46
+ chaque étape avec la commande qui la rejoue seule.
47
+
48
+ `catalog-author.fr.md` listait les fichiers d'un lab sans dire ce qu'on y
49
+ met. Le barème que `validate-structure` impose (`### … (20 pts)` face à un
50
+ en-tête `N tâches, M points`, et un point par test), le format de
51
+ `hints.yaml`, et l'emplacement de `conftest.py` — pytest s'exécute depuis la
52
+ racine du catalogue — n'étaient documentés nulle part.
53
+
54
+ Le README n'atteignait ni l'index, ni `exit-codes.fr.md`,
55
+ `machine-output.fr.md` et `infra-only.fr.md` : trois pages de référence
56
+ inaccessibles depuis la porte d'entrée.
57
+
58
+ La clé SSH était décrite comme quelque chose que le catalogue livre. Il ne la
59
+ livre pas : les catalogues publiés ignorent tout le répertoire `ssh/`, et
60
+ `provision` refuse de démarrer sans la moitié privée. Elle se génère **par
61
+ clone**, avec `instructor bootstrap`, apprenants compris.
62
+
63
+ `contract-v1.fr.md` se contredisait à neuf lignes d'intervalle sur le
64
+ caractère obligatoire de `repo.category`.
65
+
66
+ - **`docs/appliance.fr.md` est un pas-à-pas**, de l'installation de VirtualBox
67
+ au premier lab, avec la vérification d'empreinte, la mémoire à donner à la
68
+ machine selon celle de l'hôte, ce que montre le premier démarrage en trois
69
+ temps, et un tableau de dépannage. Les deux README ouvrent sur les deux
70
+ façons d'entrer, chacune avec son parcours en quatre étapes.
71
+
72
+ ### Ajouté
73
+
74
+ - **Rendre à César** : l'appliance est l'idée de [@cedric-ribier], et elle
75
+ existe parce qu'il en avait déjà construit une de bout en bout, documentée
76
+ dans [#91](https://github.com/stephrobert/dsoxlab/issues/91). Celle qui est
77
+ livrée ici s'en inspire directement.
78
+
79
+ [@cedric-ribier]: https://github.com/cedric-ribier
80
+
12
81
  ## [0.2.2] - 2026-09-26
13
82
 
14
83
  ### Ajouté
@@ -28,9 +97,10 @@ et le projet suit le [versionnage sémantique](https://semver.org/lang/fr/).
28
97
 
29
98
  L'image **n'épingle rien**. Le premier démarrage installe le dernier dsoxlab, et
30
99
  les hyperviseurs seulement si l'hôte expose la virtualisation imbriquée, vérifiée
31
- en direct et jamais supposée. D'où sa reconstruction sur les **tags mineurs
32
- seulement** : republier un demi-gigaoctet à chaque correctif coûterait cher pour
33
- ne rien changer.
100
+ en direct et jamais supposée. Elle est reconstruite à **chaque version
101
+ publiée**, correctifs compris : la dernière release porte l'image, et c'est la
102
+ seule phrase qui n'appelle aucune nuance. Rien ne s'accumule pour autant —
103
+ seuls les deux derniers jeux sont conservés.
34
104
 
35
105
  Mesuré, non estimé : **461 Mio** pour le qcow2 et **446 Mio** pour l'OVA,
36
106
  construits en 4 min 50 s, contre un budget que le workflow impose à 800 Mio. Une
@@ -41,7 +111,7 @@ et le projet suit le [versionnage sémantique](https://semver.org/lang/fr/).
41
111
  bonne sous Linux, plutôt que de les vendre à égalité.
42
112
 
43
113
  - **Seuls les deux derniers jeux d'images sont conservés sur les Releases.**
44
- Environ 900 Mo par version mineure, pour toujours, pour des images qui
114
+ Environ 900 Mo par version, pour toujours, pour des images qui
45
115
  n'épinglent aucune version de dsoxlab et installent la dernière au premier
46
116
  démarrage : une ancienne n'offre aucune reproductibilité, seulement son
47
117
  poids. Deux plutôt qu'une, pour qu'une image cassée ait un recours. Les
@@ -9,6 +9,72 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.2.3] - 2026-09-26
13
+
14
+ ### Fixed
15
+
16
+ - **The appliance workflow had never run, and died four hundredths of a second
17
+ in.** `mkdir: cannot create directory '/mnt/appliance': Permission denied` —
18
+ on a GitHub runner `/mnt` belongs to root, and that is where the disk space
19
+ is (~70 GB against ~14 on `/`). No local build could show it, since the
20
+ directory exists and is writable on a developer's machine. A dedicated step
21
+ now creates it with `sudo` and hands it to the runner.
22
+
23
+ - **The image is published on every release, not only on minor ones.** The old
24
+ rule saved bandwidth and cost more than it saved: the documentation announced
25
+ an appliance the latest release did not carry, and the reader had to work out
26
+ which earlier release did. "The latest release carries the image" is the only
27
+ sentence that needs no caveat, and nothing accumulates since the retention
28
+ step keeps the last two sets. The two workflows now start from the same tag,
29
+ so the upload waits for the Release to exist instead of assuming it — and
30
+ says which workflow to look at if it never does.
31
+
32
+ ### Changed
33
+
34
+ - **The documentation is a path now, not a pile of pages.** Read end to end
35
+ against the code, it had breaks that no single page could reveal:
36
+
37
+ `learner.md` promised `run` right after cloning a catalog, while **66 of the
38
+ Linux catalog's 86 labs** are `vm` labs: that `run` exits 2, the `provision`
39
+ it suggests exits 1 for want of an SSH key, and neither `instructor
40
+ bootstrap`, nor `start`, nor the word Terraform appeared anywhere on the
41
+ page. It now names what a `vm` lab asks of a machine, and puts `start` first
42
+ — the command that plays the whole order and announces each step with the
43
+ command that replays it alone.
44
+
45
+ `catalog-author.md` listed a lab's files without saying what goes in them.
46
+ The scale that `validate-structure` enforces (`### … (20 pts)` against a
47
+ `N tasks, M points` header, and one point per test), the format of
48
+ `hints.yaml`, and where `conftest.py` lives — pytest runs from the catalog
49
+ root — were documented nowhere.
50
+
51
+ The README reached neither the index nor `exit-codes.md`,
52
+ `machine-output.md` and `infra-only.md`: three reference pages unreachable
53
+ from the front door.
54
+
55
+ The SSH key was described as something a catalog ships. It is not: published
56
+ catalogs ignore the whole `ssh/` directory, and `provision` refuses to start
57
+ without the private half. It is generated **per clone**, by `instructor
58
+ bootstrap`, learners included.
59
+
60
+ `contract-v1.md` contradicted itself nine lines apart on whether
61
+ `repo.category` is required.
62
+
63
+ - **`docs/appliance.md` is a step-by-step**, from installing VirtualBox to the
64
+ first lab, with the digest check, the memory to give the machine depending on
65
+ the host's, what the first boot looks like in three acts, and a
66
+ troubleshooting table. Both READMEs open on the two ways in, each with its
67
+ own four-step path.
68
+
69
+ ### Added
70
+
71
+ - **Credit where it is due**: the appliance is [@cedric-ribier]'s idea, and it
72
+ exists because he had already built one end to end and documented it in
73
+ [#91](https://github.com/stephrobert/dsoxlab/issues/91). The one shipped here
74
+ is directly inspired by his.
75
+
76
+ [@cedric-ribier]: https://github.com/cedric-ribier
77
+
12
78
  ## [0.2.2] - 2026-09-26
13
79
 
14
80
  ### Added
@@ -27,8 +93,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
27
93
 
28
94
  The image **pins nothing**. The first boot installs the latest dsoxlab, and the
29
95
  hypervisors only if the host exposes nested virtualization — checked live, never
30
- assumed. Which is why it is rebuilt on **minor tags only**: republishing half a
31
- gigabyte for every patch would cost a lot and change nothing.
96
+ assumed. It is rebuilt on **every published version**, patches included: the
97
+ latest release carries the image, which is the only sentence that needs no
98
+ caveat. Nothing accumulates — only the last two sets are kept.
32
99
 
33
100
  Measured, not estimated: **461 MiB** for the qcow2 and **446 MiB** for the OVA,
34
101
  built in 4 min 50 s, against a budget the workflow enforces at 800 MiB. A
@@ -39,7 +106,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
39
106
  selling them as equals.
40
107
 
41
108
  - **Only the last two sets of images are kept on the Releases.** Roughly 900 MB
42
- per minor version, forever, for images that pin no dsoxlab version and
109
+ per version, forever, for images that pin no dsoxlab version and
43
110
  install the latest at first boot: an old one offers no reproducibility, only
44
111
  weight. Two rather than one, so a broken image has a fallback. The Releases,
45
112
  their changelog and the Python distributions are untouched.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: dsoxlab
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Turn declarative exercises into reproducible, runnable and verifiable lab environments
5
5
  Project-URL: Homepage, https://blog.stephane-robert.info/
6
6
  Project-URL: Documentation, https://github.com/stephrobert/dsoxlab/blob/main/docs/README.md
@@ -118,9 +118,42 @@ and no Docker: it runs anywhere dsoxlab runs.
118
118
 
119
119
  ---
120
120
 
121
+ ## Or: the appliance, in four steps
122
+
123
+ For Windows and macOS, where `uv tool install` is not an option. No knowledge
124
+ of virtualization required.
125
+
126
+ 1. **Install VirtualBox** from <https://www.virtualbox.org/wiki/Downloads>. The
127
+ *Extension Pack* it offers is not needed.
128
+ 2. **Download the `.ova`** from the latest
129
+ [release](https://github.com/stephrobert/dsoxlab/releases) that carries one,
130
+ and check its digest against the `SHA256SUMS` published next to it.
131
+ 3. **Import and start**: in VirtualBox, *File → Import Appliance*, pick the
132
+ `.ova`, *Finish*, then *Start*. The first boot installs dsoxlab, the
133
+ hypervisors and the desktop, then **reboots on its own**: count five to
134
+ fifteen minutes, with nothing to type.
135
+ 4. **Log in** with `student` / `dsoxlab` — the machine requires you to change
136
+ that password, which is public — then, in the desktop's terminal:
137
+
138
+ ```bash
139
+ dsoxlab demo && cd ~/.local/share/dsoxlab/demo
140
+ dsoxlab course premiers-pas
141
+ ```
142
+
143
+ `vm` labs need one more step, **nested virtualization**, which is enabled on
144
+ your computer and not inside the machine: *Settings → System → Processor →
145
+ Enable Nested VT-x/AMD-V*, appliance powered off. `dsoxlab doctor` says so when
146
+ it is missing.
147
+
148
+ Every step in detail, the actual requirements and a troubleshooting table are
149
+ on **[the appliance page](docs/appliance.md)**.
150
+
151
+ ---
152
+
121
153
  ## Documentation
122
154
 
123
- Three readers, three doors. Every page names its audience in its first lines.
155
+ Every page names its audience in its first lines, and
156
+ [the index](docs/README.md) lists them all.
124
157
 
125
158
  | I want to… | Read |
126
159
  | --- | --- |
@@ -128,6 +161,8 @@ Three readers, three doors. Every page names its audience in its first lines.
128
161
  | Play labs on Windows or macOS, without installing anything | **[The appliance](docs/appliance.md)**, a ready-to-play VM |
129
162
  | Write my own catalog of labs | **[For the catalog author](docs/catalog-author.md)**, then [the v1 contract](docs/contract-v1.md) field by field |
130
163
  | Run the machines the labs need | **[For the trainer](docs/trainer.md)** |
164
+ | Get throwaway VMs, with no exercise to write | [Infrastructure without labs](docs/infra-only.md) |
165
+ | Call dsoxlab from a script or a CI, and branch on the result | [Exit codes](docs/exit-codes.md), then [the machine output](docs/machine-output.md) for `--json` |
131
166
  | Know where dsoxlab writes on my disk | [Where dsoxlab writes](docs/files.md) |
132
167
  | See every command | [Command reference](docs/commands.md), generated from the CLI |
133
168
 
@@ -217,6 +252,13 @@ persistent, and four releases come from his reports:
217
252
  ready-to-use appliance, discussed in
218
253
  [#91](https://github.com/stephrobert/dsoxlab/issues/91).
219
254
 
255
+ **And the appliance itself is his idea.** He did not ask for it: he had already
256
+ **built one end to end**, then documented it in
257
+ [#91](https://github.com/stephrobert/dsoxlab/issues/91). The one dsoxlab ships
258
+ today is directly inspired by his — the idea and the approach both. It is the
259
+ contribution a changelog shows least and the product owes most: without it,
260
+ there would be nothing to offer anyone working on Windows or macOS.
261
+
220
262
  **[@Gedd18](https://github.com/Gedd18)** found that the lab catalog's
221
263
  `conftest.py` failed to load whenever no infrastructure provider was resolved,
222
264
  which silently blocked **every `shell` lab** — the very first ones a learner
@@ -80,10 +80,43 @@ conteneur, ni Docker : il tourne partout où dsoxlab tourne.
80
80
 
81
81
  ---
82
82
 
83
+ ## Ou : l'appliance, en quatre étapes
84
+
85
+ Pour Windows et macOS, où `uv tool install` n'est pas une option. Aucune
86
+ connaissance de la virtualisation n'est nécessaire.
87
+
88
+ 1. **Installez VirtualBox** depuis
89
+ <https://www.virtualbox.org/wiki/Downloads>. L'*Extension Pack* proposé
90
+ n'est pas nécessaire.
91
+ 2. **Téléchargez le fichier `.ova`** de la dernière
92
+ [release](https://github.com/stephrobert/dsoxlab/releases) qui en porte un,
93
+ et vérifiez son empreinte avec le `SHA256SUMS` publié à côté.
94
+ 3. **Importez et démarrez** : dans VirtualBox, *Fichier → Importer un appareil
95
+ virtuel*, choisissez le `.ova`, *Terminer*, puis *Démarrer*. Le premier
96
+ démarrage installe dsoxlab, les hyperviseurs et le bureau, puis **redémarre
97
+ tout seul** : comptez cinq à quinze minutes, sans rien taper.
98
+ 4. **Connectez-vous** avec `student` / `dsoxlab` — la machine exige de changer
99
+ ce mot de passe, qui est public — puis, dans le terminal du bureau :
100
+
101
+ ```bash
102
+ dsoxlab demo && cd ~/.local/share/dsoxlab/demo
103
+ dsoxlab course premiers-pas
104
+ ```
105
+
106
+ Les labs `vm` demandent une étape de plus, la **virtualisation imbriquée**, qui
107
+ s'active sur votre ordinateur et non dans la machine : *Configuration → Système
108
+ → Processeur → Activer VT-x/AMD-V imbriqué*, appliance éteinte. `dsoxlab
109
+ doctor` le dit s'il manque.
110
+
111
+ Le détail de chaque étape, les prérequis chiffrés et un tableau de dépannage
112
+ sont dans **[la page de l'appliance](docs/appliance.fr.md)**.
113
+
114
+ ---
115
+
83
116
  ## Documentation
84
117
 
85
- Trois lecteurs, trois portes. Chaque page nomme son public dès ses premières
86
- lignes.
118
+ Chaque page nomme son public dès ses premières lignes, et
119
+ [l'index](docs/README.fr.md) les répertorie toutes.
87
120
 
88
121
  | Je veux… | Lire |
89
122
  | --- | --- |
@@ -91,6 +124,8 @@ lignes.
91
124
  | Jouer des labs sous Windows ou macOS, sans rien installer | **[L'appliance](docs/appliance.fr.md)**, une VM prête à jouer |
92
125
  | Écrire mon propre catalogue de labs | **[Pour l'auteur de catalogue](docs/catalog-author.fr.md)**, puis [le contrat v1](docs/contract-v1.fr.md) champ par champ |
93
126
  | Monter les machines dont les labs ont besoin | **[Pour le formateur](docs/trainer.fr.md)** |
127
+ | Obtenir des VM jetables, sans aucun exercice à écrire | [L'infrastructure sans labs](docs/infra-only.fr.md) |
128
+ | Appeler dsoxlab depuis un script ou une CI, et décider sur le résultat | [Les codes de sortie](docs/exit-codes.fr.md), puis [la sortie machine](docs/machine-output.fr.md) pour `--json` |
94
129
  | Savoir où dsoxlab écrit sur mon disque | [Où dsoxlab écrit](docs/files.fr.md) |
95
130
  | Voir toutes les commandes | [Référence des commandes](docs/commands.fr.md), produite par la CLI |
96
131
 
@@ -186,6 +221,14 @@ et quatre versions viennent de ses remontées :
186
221
  une image prête à l'emploi, discuté dans
187
222
  [#91](https://github.com/stephrobert/dsoxlab/issues/91).
188
223
 
224
+ **Et l'appliance elle-même est son idée.** Il ne l'a pas demandée : il l'avait
225
+ déjà **construite de bout en bout**, puis documentée dans
226
+ [#91](https://github.com/stephrobert/dsoxlab/issues/91). Celle que dsoxlab
227
+ publie aujourd'hui s'inspire directement de la sienne — l'idée comme la
228
+ démarche. C'est la contribution la moins visible dans un journal des
229
+ modifications et la plus structurante pour le produit : sans elle, il n'y
230
+ aurait rien à proposer à qui travaille sous Windows ou macOS.
231
+
189
232
  **[@Gedd18](https://github.com/Gedd18)** a trouvé que le `conftest.py` du
190
233
  catalogue de labs ne se chargeait plus dès qu'aucun provider d'infrastructure
191
234
  n'était résolu, ce qui bloquait en silence **tous les labs `shell`**, c'est-à-dire
@@ -81,9 +81,42 @@ and no Docker: it runs anywhere dsoxlab runs.
81
81
 
82
82
  ---
83
83
 
84
+ ## Or: the appliance, in four steps
85
+
86
+ For Windows and macOS, where `uv tool install` is not an option. No knowledge
87
+ of virtualization required.
88
+
89
+ 1. **Install VirtualBox** from <https://www.virtualbox.org/wiki/Downloads>. The
90
+ *Extension Pack* it offers is not needed.
91
+ 2. **Download the `.ova`** from the latest
92
+ [release](https://github.com/stephrobert/dsoxlab/releases) that carries one,
93
+ and check its digest against the `SHA256SUMS` published next to it.
94
+ 3. **Import and start**: in VirtualBox, *File → Import Appliance*, pick the
95
+ `.ova`, *Finish*, then *Start*. The first boot installs dsoxlab, the
96
+ hypervisors and the desktop, then **reboots on its own**: count five to
97
+ fifteen minutes, with nothing to type.
98
+ 4. **Log in** with `student` / `dsoxlab` — the machine requires you to change
99
+ that password, which is public — then, in the desktop's terminal:
100
+
101
+ ```bash
102
+ dsoxlab demo && cd ~/.local/share/dsoxlab/demo
103
+ dsoxlab course premiers-pas
104
+ ```
105
+
106
+ `vm` labs need one more step, **nested virtualization**, which is enabled on
107
+ your computer and not inside the machine: *Settings → System → Processor →
108
+ Enable Nested VT-x/AMD-V*, appliance powered off. `dsoxlab doctor` says so when
109
+ it is missing.
110
+
111
+ Every step in detail, the actual requirements and a troubleshooting table are
112
+ on **[the appliance page](docs/appliance.md)**.
113
+
114
+ ---
115
+
84
116
  ## Documentation
85
117
 
86
- Three readers, three doors. Every page names its audience in its first lines.
118
+ Every page names its audience in its first lines, and
119
+ [the index](docs/README.md) lists them all.
87
120
 
88
121
  | I want to… | Read |
89
122
  | --- | --- |
@@ -91,6 +124,8 @@ Three readers, three doors. Every page names its audience in its first lines.
91
124
  | Play labs on Windows or macOS, without installing anything | **[The appliance](docs/appliance.md)**, a ready-to-play VM |
92
125
  | Write my own catalog of labs | **[For the catalog author](docs/catalog-author.md)**, then [the v1 contract](docs/contract-v1.md) field by field |
93
126
  | Run the machines the labs need | **[For the trainer](docs/trainer.md)** |
127
+ | Get throwaway VMs, with no exercise to write | [Infrastructure without labs](docs/infra-only.md) |
128
+ | Call dsoxlab from a script or a CI, and branch on the result | [Exit codes](docs/exit-codes.md), then [the machine output](docs/machine-output.md) for `--json` |
94
129
  | Know where dsoxlab writes on my disk | [Where dsoxlab writes](docs/files.md) |
95
130
  | See every command | [Command reference](docs/commands.md), generated from the CLI |
96
131
 
@@ -180,6 +215,13 @@ persistent, and four releases come from his reports:
180
215
  ready-to-use appliance, discussed in
181
216
  [#91](https://github.com/stephrobert/dsoxlab/issues/91).
182
217
 
218
+ **And the appliance itself is his idea.** He did not ask for it: he had already
219
+ **built one end to end**, then documented it in
220
+ [#91](https://github.com/stephrobert/dsoxlab/issues/91). The one dsoxlab ships
221
+ today is directly inspired by his — the idea and the approach both. It is the
222
+ contribution a changelog shows least and the product owes most: without it,
223
+ there would be nothing to offer anyone working on Windows or macOS.
224
+
183
225
  **[@Gedd18](https://github.com/Gedd18)** found that the lab catalog's
184
226
  `conftest.py` failed to load whenever no infrastructure provider was resolved,
185
227
  which silently blocked **every `shell` lab** — the very first ones a learner