test(fuzz): couvrir les entrées que le moteur ne produit pas (0.1.64) - #156
Merged
Conversation
Le dépôt fuzzait les deux fichiers du contrat déclaratif, ce qui est la bonne
intuition mais pas la couverture complète : le contexte local et les outputs de
Terraform sont lus avec la même confiance, et n'étaient couverts par aucun
harnais.
Chaque entrée est non fiable pour une raison différente, et cette raison décide
du contrat que son harnais assère.
.dsoxlab-context.json vit sur le disque de l'apprenant : édité à la main,
tronqué par un portable refermé au mauvais moment, laissé par une version
ancienne. Son harnais n'a aucune exception de contrat, et c'est tout son propos :
read_context promet de rendre un contexte vide plutôt que de lever, parce que
perdre le contexte coûte un dsoxlab use là où une exception coûte la CLI entière.
Les outputs Terraform viennent d'un binaire externe dont la version, les
providers et le schéma de sortie bougent sans que dsoxlab le sache. Le harnais
vise ce que build_inventory fait du document, et non le json.loads qui le
précède : celui-là est déjà protégé, et le fuzzer n'y mesurerait que la
bibliothèque standard.
Il a trouvé un vrai défaut à sa troisième minute : {"hosts": {"value": "10.0.0.1"}}
faisait lever un AttributeError au moment de jouer un lab, sans jamais dire que
la cause était un state Terraform périmé. Corrigé, et figé par un test : le
fuzzing découvre, un test empêche le retour.
Le harnais m'a aussi appris son propre contrat : InfraNotProvisioned est une
exception attendue, celle du premier lancement ou de l'après-destroy, et un
harnais qui l'aurait comptée comme un crash aurait réclamé de la défaire.
Closes #71
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Le dépôt fuzzait les deux fichiers du contrat déclaratif, ce qui est la bonne
intuition mais pas la couverture complète : le contexte local et les outputs de
Terraform sont lus avec la même confiance, et n'étaient couverts par aucun
harnais.
Le harnais a trouvé un vrai défaut
Trente-quatre octets, et personne ne les avait écrits à la main :
Un
AttributeErrorau moment de jouer un lab, sans jamais dire que la causeest un state Terraform périmé, un provider qui a renommé sa sortie, ou un state
édité à la main. Corrigé, et figé par un test : le fuzzing découvre, un test
empêche le retour. Après correction, 200 000 exécutions ne rendent plus rien.
Chaque entrée est non fiable pour une raison différente
Et cette raison décide du contrat que son harnais assère. C'est le point de
conception de la PR, pas un détail :
lab.yaml,meta.ymlKeyError,ValueError,YAMLErrorsont la façon de refuser.dsoxlab-context.jsonLe harnais du contexte n'a aucune exception de contrat, et c'est tout son
propos.
read_contextpromet de rendre un contexte vide plutôt que de lever,parce que perdre le contexte coûte un
dsoxlab uselà où une exception coûte laCLI entière, sans même nommer le fichier à supprimer.
Le harnais Terraform vise la consommation, pas le décodage.
read_terraform_outputsfait de l'E/S et unjson.loadsdéjà protégé : lefuzzer n'y mesurerait que la bibliothèque standard. Ce qui atteint l'utilisateur
en traceback, c'est ce que
build_inventoryfait du document décodé.Le harnais m'a appris son propre contrat
Première exécution, sur la graine
{}:InfraNotProvisioned. Ce n'est pas undéfaut, c'est l'exception dédiée au cas normal du premier lancement ou de
l'après-
destroy, que la CLI rend en une phrase. Un harnais qui l'aurait comptéecomme un crash aurait réclamé de défaire exactement le patron que ce dépôt
applique. Elle rejoint donc les exceptions de contrat, avec la raison écrite.
Le corpus
Dix graines pour le contexte, neuf pour Terraform, chacune visant une forme
réelle et non une bizarrerie inventée : la forme encapsulée de
terraform output -jsonet la forme aplatie, un bastion Outscale, un outputd'une autre version, un contexte complet tel que
usel'écrit, une racine JSONqui n'est pas un objet, une écriture interrompue.
Couverture mesurée : 66 arêtes pour le harnais Terraform, contre 73 pour le
harnais
meta.ymlexistant. Il exerce donc bien du code, il ne se contente pasd'échouer au décodage.
Type of change
AttributeErrorsur un output mal formé)Checklist
Always
uv run ruff check src/dsoxlab tests tests_e2e fuzz scripts— All checks passed!uv run mypy src/dsoxlab— no issues in 60 source filesuv run pytest— 629 passed (620 avant, +9)When behavior changes
uv.lockrégénéréWhen a command or option is added, removed or changed — N/A
When the declarative contract changes — N/A
When
.github/workflows/is touchedactionlint: 0 problème ;zizmor --persona=regular: No findings(
-atheris_runs=20000 -max_len=4096), dans le job existant, donc sansallonger la porte de contribution
pourquoi elle est considérée non fiable
Une exclusion de hook, et pourquoi elle n'est pas une facilité
Deux hooks d'hygiène ont refusé le corpus :
check-jsonsur une graine tronquée,end-of-file-fixersur son absence de fin de ligne. Ils avaient raison, etc'est le corpus qui est hors de leur périmètre : ce sont des graines
délibérément malformées, faites pour être données à un fuzzer. Un JSON coupé au
milieu d'une chaîne reproduit un portable refermé pendant l'écriture ; le
« réparer » retire au corpus le cas qu'il porte.
fuzz/corpus/est donc exclu decheck-json,check-yamletend-of-file-fixer, avec cette raison écrite dans la configuration. Aucun hookde sécurité n'est touché :
detect-private-keyettrufflehogcontinuent devoir ces fichiers.
Related issues
Closes #71
🤖 Generated with Claude Code