Fuzz est un package de Jon Purvis qui apporte le fuzzing guidé par la couverture à Pest 5. Il s'appuie sur PHP-Fuzzer de nikic, fait muter les chaînes fournies et les passe au code jusqu'à trouver un échec ou épuiser le budget d'exécution. Une exécution réussie signifie seulement qu'aucun échec n'a été trouvé dans ces tentatives.
use App\RateLimit;
use function Fuzz\fuzz;
$target = static function (string $input): void {
RateLimit::perSecond($input);
};
test('rate limit spec parser never fatals', function () use ($target): void {
fuzz($target)
->seed(['100/60s', '5/1s', '1000/3600s'])
->withDictionary(['/', 's', '0', '1'])
->runs(2000)
->maxLen(16)
->run('rate-limit-parser');
});Un fuzzer guidé par la couverture observe les chemins que les entrées empruntent dans le code. Quand une entrée atteint un chemin inexploré, le fuzzer la conserve dans un corpus et l'utilise pour créer d'autres variations. PHP-Fuzzer collecte ce retour en suivant les transitions entre blocs de code PHP et leur fréquence d'exécution approximative. Fuzz gère l'instrumentation lui-même, donc Xdebug et l'option --coverage de Pest ne sont pas nécessaires.
Fuzz exige PHP 8.4+ et Pest 5. Il s'installe avec `composer require jonpurvis/fuzz --dev`. Le tutoriel utilise un helper RateLimit qui convertit une expression comme 100/60s en requêtes par seconde sans valider l'entrée. Dans le test, une fonction cible appelant le helper est définie en dehors de test(). Puis fuzz() est configuré avec seed(), withDictionary(), runs(2000), maxLen(16) et un nom unique dans run(), que Fuzz utilise pour séparer les entrées sauvegardées et les fichiers de plantage.
La définition en dehors de test() est importante : lors de la vérification de Fuzz v1.0.1, ce wrapper enregistrait la couverture alors que Closure::fromCallable() n'en enregistrait aucune, car Fuzz exécute la fonction dans un processus PHP séparé où la classe de test générée par Pest n'est pas disponible.
Lors de l'essai de l'auteur, Fuzz a trouvé l'entrée 5/. La fenêtre manquante devient une chaîne vide. PHP la convertit en 0, et la division lève une DivisionByZeroError. Pest signale le test comme échoué. Les entrées fautives sont sauvegardées par défaut sous .pest/fuzz-crashes/. Après correction, la pratique recommandée est d'ajouter l'entrée à un dataset nommé et de vérifier le comportement attendu.
Les plantages ne sont pas les seuls échecs à détecter. Une valeur de retour incorrecte peut passer inaperçue, il est donc possible d'ajouter une expectation Pest dans la fonction cible, par exemple vérifier qu'encoder puis décoder une chaîne redonne l'original. Fuzz signale les TypeError ainsi que les avertissements et notices PHP non supprimés. Les exceptions ordinaires, y compris les exceptions de validation Laravel, sont ignorées par défaut. La méthode allow() restreint cette liste, et timeout() fixe une limite par entrée, ce qui requiert l'extension pcntl.
L'auteur conseille de garder les tests et datasets classiques pour les cas connus. Fuzz est utile quand le code accepte plus d'entrées qu'on ne peut raisonnablement en énumérer, comme les parseurs lisant du texte fourni par l'utilisateur, surtout avec des étapes de validation successives où la couverture guide le fuzzer vers du code plus profond. Il recommande un petit budget dans la suite normale et des recherches plus longues dans une tâche CI planifiée.




Commentaires
Pas encore de commentaire — écris le premier.
Lance la discussion
Pas de compte ni de mot de passe — saisis simplement ton adresse e-mail et nous t’envoyons un lien de connexion à usage unique. Première visite ? Tout se met en place automatiquement.
Ton évaluation sera appliquée automatiquement après ta connexion.
Vérifie ta boîte mail
Nous avons envoyé un lien de connexion à …. Ouvre-le sur cet appareil — cet onglet te connectera automatiquement.
Rien reçu ? Vérifiez le dossier spam — et marquez le message « Non spam » pour qu'il arrive directement la prochaine fois.