Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@ repos:
# que le zéro-bash interdit, et il y manquait deux commandes. Elle est
# désormais produite par la CLI, et ce hook refuse une version périmée.
- id: doc-a-jour
name: la documentation décrit la CLI réelle
name: la documentation décrit la CLI et les chemins réels
entry: python3 scripts/generer-doc.py --verifier
language: system
pass_filenames: false
files: '^(src/dsoxlab/(cli\.py|i18n/)|README(\.fr)?\.md|scripts/generer-doc\.py)'
files: '^(src/dsoxlab/.*\.py|docs/.*\.md|[A-Z]+(\.fr)?\.md|scripts/generer-doc\.py)$'

# Full test suite runs on push (kept off the per-commit path for speed).
- id: pytest
Expand Down
50 changes: 50 additions & 0 deletions CHANGELOG.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,56 @@ et le projet suit le [versionnage sémantique](https://semver.org/lang/fr/).

## [Non publié]

## [0.1.63] - 2026-08-24

- **La documentation décrivait un produit qui n'existe pas.** Trois
affirmations de la section « Persistence » des deux README étaient fausses, et
c'étaient celles que suit un lecteur cherchant ses notes : une base
`~/.local/share/dsoxlab/progress.db`, un fichier de configuration utilisateur
`~/.config/dsoxlab/config.yaml`, et `XDG_DATA_HOME` / `XDG_CONFIG_HOME` pour
les déplacer. La base est `<catalogue>/.dsoxlab.db`, une par catalogue, et
aucun fichier de configuration n'est lu nulle part. Quatre autres
affirmations ont suivi le même chemin : une progression « conforme à la
spécification XDG », `incus` et `kvm` présentés comme des runtimes (il y en a
deux, `shell` et `vm`, et le backend est le choix du catalogue), une carte
d'architecture nommant des classes `IncusRuntime` et `KvmRuntime` qui
n'existent pas, et un champ `runtime.host` dans l'exemple de `lab.yaml` le
plus en vue, qu'aucun code ne lit.

- L'aide de `--lab-home` annonçait « racine du dépôt linux-training », nommant
un catalogue comme s'il était le seul, dans les deux langues. Elle dit
désormais « le catalogue de labs ».

### Ajouté

- **Un contrôle qui interdit à la dérive de recommencer.** Les emplacements de
fichiers documentés sont désormais confrontés au code comme l'était déjà la
table des commandes : `scripts/generer-doc.py` relève les emplacements réels
**en appelant les fonctions que la CLI appelle**, sur un `HOME` jetable, puis
signale tout chemin qu'une page cite et qui ne correspond à aucun d'eux.
Prouvé par mutation, et par six tests dans
`tests/test_documentation_synchrone.py`. Un chemin peut être cité pour dire
qu'il **n'**existe **pas**, mais par la seule page dont c'est le sujet, et un
test vérifie qu'il est bien absent du code.

### Modifié

- **Documentation découpée par public**, chaque page nommant son lecteur dès ses
premières lignes : [l'apprenant](docs/learner.fr.md), [l'auteur de
catalogue](docs/catalog-author.fr.md), [le formateur](docs/trainer.fr.md),
plus deux références communes aux trois ([où dsoxlab écrit](docs/files.fr.md)
et [les commandes](docs/commands.fr.md), toujours produites par la CLI). Les
deux README gardent leur rôle de porte d'entrée et se lisent maintenant en
trente secondes. Aucun générateur de site n'est introduit : cette décision
appartient au propriétaire du dépôt.

- `Documentation` dans `pyproject.toml` pointe sur la documentation de l'outil
plutôt que sur l'index générique d'un blog. La carte de l'architecture a
déménagé dans `CONTRIBUTING.fr.md`, corrigée, là où les contributeurs à qui
elle s'adresse la trouveront.

Closes #86.

## [0.1.62] - 2026-08-24

### Corrigé
Expand Down
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,53 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.1.63] - 2026-08-24

- **The documentation described a product that does not exist.** Three claims
of the "Persistence" section of both READMEs were false, and they were the
ones a reader looking for their scores would follow: a database at
`~/.local/share/dsoxlab/progress.db`, a user configuration file at
`~/.config/dsoxlab/config.yaml`, and `XDG_DATA_HOME` / `XDG_CONFIG_HOME` as
the way to move them. The database is `<catalog>/.dsoxlab.db`, one per
catalog; no configuration file is read anywhere. Four more claims went the
same way: progress "following the XDG spec", `incus` and `kvm` presented as
runtimes (there are two, `shell` and `vm`, and the backend is the catalog's
choice), an architecture map naming `IncusRuntime` and `KvmRuntime` classes
that do not exist, and a `runtime.host` field in the flagship `lab.yaml`
example that no code reads.

- The `--lab-home` help said "root of the linux-training repo", naming one
catalog as if it were the only one, in both languages. It now says "the lab
catalog".

### Added

- **A control that forbids the drift from starting again.** The documented file
locations are now confronted with the code the same way the command table
already was: `scripts/generer-doc.py` derives the real locations **by calling
the functions the CLI calls**, on a throwaway `HOME`, then reports any path a
page cites that matches none of them. Proven by mutation, and by six tests in
`tests/test_documentation_synchrone.py`. A path may be cited as *not*
existing, but only by the page whose subject that is, and a test checks that
such a path really is absent from the code.

### Changed

- **Documentation split by audience**, each page naming its reader in its first
lines: [the learner](docs/learner.md), [the catalog
author](docs/catalog-author.md), [the trainer](docs/trainer.md), plus two
references shared by the three ([where dsoxlab writes](docs/files.md) and
[the commands](docs/commands.md), still generated from the CLI). Both READMEs
keep their role as the entry point and now fit in a thirty-second read. No
site generator is introduced: that decision belongs to the repository owner.

- `Documentation` in `pyproject.toml` points at the tool's documentation instead
of the generic index of a blog. The architecture map moved to
`CONTRIBUTING.md`, corrected, where the contributors it addresses will find
it.

Closes #86.

## [0.1.62] - 2026-08-24

### Fixed
Expand Down
41 changes: 38 additions & 3 deletions CONTRIBUTING.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ commit sont rédigés en anglais pour que tout le monde puisse participer.

- [Règles fondamentales](#règles-fondamentales)
- [Mise en place](#mise-en-place)
- [Carte de l'architecture](#carte-de-larchitecture)
- [Contrôles qualité](#contrôles-qualité)
- [Scanners de workflow](#scanners-de-workflow)
- [Fuzzer le contrat non fiable](#fuzzer-le-contrat-non-fiable)
Expand Down Expand Up @@ -60,6 +61,40 @@ cd ~/Projets/linux-dsoxlab-training && dsoxlab list-labs
cd ~/Projets/ansible-training && dsoxlab list-labs
```

## Carte de l'architecture

```text
src/dsoxlab/
├── cli.py ← point d'entrée Typer (+ le groupe de commandes i18n)
├── config.py ← LAB_HOME, contexte actif, .dsoxlab-context.json
├── locking.py ← verrou d'écriture par catalogue (flock), code de sortie 7
├── logging_setup.py ← le journal qu'écrit chaque commande, quelle que soit la verbosité
├── i18n/ ← get_lang(), _(), strings/en.py + strings/fr.py
├── models/ ← schémas typés du contrat déclaratif
├── discovery/ ← scan du meta.yml et de tous les lab.yaml du catalogue
├── services/ ← orchestration métier (lab, progression, guide, doctor…)
├── sessions/ ← persistance SQLite (results + hint_requests)
├── runtimes/ ← BaseRuntime, ShellRuntime, VmRuntime, RuntimeManager
├── infra/ ← Terraform, Ansible, inventaire, snapshots, identifiants
├── validators/ ← structure, métadonnées et contenu d'un catalogue
├── reporting/ ← sorties terminal Rich, et le JSON de --json
├── utils/ ← wrapper subprocess centralisé
└── templates/ ← Terraform, cloud-init et le catalogue de démonstration
```

Il existe deux runtimes, et deux seulement : `shell` et `vm`. Les valeurs `kvm`
et `incus` de `runtime.type` sont des alias historiques traités par
`VmRuntime` ; quel backend sert réellement une VM vient de
`meta.yml: infra.provider`.

`infra/inventory.py` est la surface publique qu'un catalogue consomme : son
`conftest.py` importe `build_inventory`, `read_terraform_outputs` et
`write_ssh_config` pour construire l'inventaire testinfra sans coder la moindre
adresse IP.

Le moteur reste indépendant de l'arborescence d'un dépôt : `discovery/`
fonctionne sur n'importe quel arbre déclaré par le `meta.yml`.

## Contrôles qualité

À lancer avant d'ouvrir une pull request. La CI exécute les mêmes contrôles.
Expand Down Expand Up @@ -198,9 +233,9 @@ Nous utilisons les Conventional Commits avec un scope de module :

Types : `feat`, `fix`, `docs`, `refactor`, `chore`, `test`, `ci`. Exemples :

- `feat(discovery): support multi-repo via ~/.config/dsoxlab/config.yaml`
- `fix(runtimes/kvm): make snapshot revert idempotent when snapshot is absent`
- `docs(readme): document the incus runtime`
- `feat(runtimes): declare containerized services in lab.yaml`
- `fix(runtimes/vm): make snapshot revert idempotent when the snapshot is absent`
- `docs(contract): document the meta.fr.yml overrides`

Gardez des commits ciblés et un historique lisible. Avant un commit groupé,
consultez `git log --oneline -5` pour coller au style.
Expand Down
39 changes: 36 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ in English so everyone can take part.

- [Ground rules](#ground-rules)
- [Development setup](#development-setup)
- [Architecture map](#architecture-map)
- [Quality gates](#quality-gates)
- [Workflow scanners](#workflow-scanners)
- [Fuzzing the untrusted contract](#fuzzing-the-untrusted-contract)
Expand Down Expand Up @@ -60,6 +61,38 @@ cd ~/Projets/linux-dsoxlab-training && dsoxlab list-labs
cd ~/Projets/ansible-training && dsoxlab list-labs
```

## Architecture map

```text
src/dsoxlab/
├── cli.py ← Typer entry point (+ the i18n command group)
├── config.py ← LAB_HOME, active context, .dsoxlab-context.json
├── locking.py ← per-catalog write lock (flock), exit code 7
├── logging_setup.py ← the log every command writes, whatever the verbosity
├── i18n/ ← get_lang(), _(), strings/en.py + strings/fr.py
├── models/ ← typed schemas of the declarative contract
├── discovery/ ← scan meta.yml + every lab.yaml of the current catalog
├── services/ ← business orchestration (lab, progress, guide, doctor…)
├── sessions/ ← SQLite persistence (results + hint_requests)
├── runtimes/ ← BaseRuntime, ShellRuntime, VmRuntime, RuntimeManager
├── infra/ ← Terraform, Ansible, inventory, snapshots, credentials
├── validators/ ← structure, metadata and content of a catalog
├── reporting/ ← Rich terminal output, and the JSON of --json
├── utils/ ← centralized subprocess wrapper
└── templates/ ← Terraform, cloud-init and the demonstration catalog
```

Two runtimes exist, and only two: `shell` and `vm`. The `kvm` and `incus`
values of `runtime.type` are legacy aliases handled by `VmRuntime`; which
backend actually serves a VM comes from `meta.yml: infra.provider`.

`infra/inventory.py` is the public surface a catalog consumes: its `conftest.py`
imports `build_inventory`, `read_terraform_outputs` and `write_ssh_config` to
build the testinfra inventory without hardcoding a single IP address.

The engine stays independent of any single repository layout: `discovery/`
works on whatever tree the `meta.yml` declares.

## Quality gates

Run these before opening a pull request. CI runs the same checks.
Expand Down Expand Up @@ -197,9 +230,9 @@ We use Conventional Commits with a module scope:

Types: `feat`, `fix`, `docs`, `refactor`, `chore`, `test`, `ci`. Examples:

- `feat(discovery): support multi-repo via ~/.config/dsoxlab/config.yaml`
- `fix(runtimes/kvm): make snapshot revert idempotent when snapshot is absent`
- `docs(readme): document the incus runtime`
- `feat(runtimes): declare containerized services in lab.yaml`
- `fix(runtimes/vm): make snapshot revert idempotent when the snapshot is absent`
- `docs(contract): document the meta.fr.yml overrides`

Keep commits focused and the history readable. Before a grouped commit, check
`git log --oneline -5` to match the style.
Expand Down
Loading
Loading