Amélioration des tests de sécurité des projets Gradle basés sur Git grâce au fichier de verrouillage
Antonio Gomes
7 décembre 2020
0 minutes de lectureDepuis un an, nous travaillons sans relâche à améliorer les tests des projets Gradle importés depuis des dépôts Git, afin de les rendre plus fiables, plus précis et plus évolutifs.
Nous avons compris que l’analyse d’un manifeste Gradle plutôt que d’un fichier de verrouillage Gradle serait une bataille sans fin, que nous finirions toujours par perdre. Tenter d’interpréter le modèle de complexité de Gradle en analysant un fichier build.gradle est une approche non déterministe qui repose sur de nombreuses hypothèses. Les configurations qui imposent strictement une version ou une version maximale pour une ou plusieurs dépendances, ou dont les versions sont définies dans d’autres fichiers, ne seraient pas toujours prises en compte. De plus, cette approche ne permettrait jamais de déclarer explicitement ce que Gradle va résoudre et utiliser dans différents contextes de configuration, comme les phases de compilation, de test ou d’exécution. Tout cela peut entraîner des résultats inexacts ou incomplets.
C’est pourquoi différents outils de gestion des dépendances s’appuient sur le verrouillage des dépendances pour aider les développeurs à obtenir des builds reproductibles. C’est notamment le cas de npm (package-lock.json), yarn (yarn.lock), RubyGems (Gemfile.lock) et, désormais, de Gradle avec gradle.lockfile.
Comment générer un fichier de verrouillage Gradle
Voici à quoi ressemble un fichier gradle.lockfile classique :

Il ne contient ni arborescence ni graphe. Il remplit plutôt son rôle en répertoriant toutes les dépendances directes et transitives utilisées, ainsi que leurs versions et les configurations auxquelles elles appartiennent.
Pour générer un fichier de verrouillage dans votre projet unique ou votre mono-dépôt (qui contient plusieurs sous-projets), modifiez votre fichier build.gradle en y ajoutant les instructions suivantes :

Comme vous pouvez le voir, nous demandons à Gradle de déclencher dependencyLocking pour toutes les configurations disponibles, par exemple annotationProcessor, compile, runtime, etc.
Une fois le code ajouté, Gradle pourra comprendre ce que nous voulons faire.
Dans cet exemple, nous avons une seule configuration. En général, cependant, nous pouvons en avoir plusieurs et obtenir un fichier de verrouillage par configuration. Pour disposer d’une source unique de vérité, voyons comment générer un seul fichier de verrouillage par projet.
Générer un fichier de verrouillage unique
Grâce à une fonctionnalité en avant-première de Gradle 7.0, déjà disponible pour les utilisateurs de Gradle 6.0 et versions ultérieures, nous pouvons générer un fichier gradle.lockfile unique par projet, qui contient tous les états de verrouillage des différentes configurations. Cette méthode utilisant un fichier de verrouillage unique deviendra la méthode par défaut à partir de Gradle 7.0.

Une fois cette règle définie, il faut exécuter dans le terminal la commande gradle resolveAndLockAll --write-locks, qui générera le fichier de verrouillage ci-dessous :

Voici ce que nous pouvons constater :
chaque ligne représente toujours une dépendance unique au format GAV
group:artifact:version.chaque dépendance est associée à une liste de configurations dans lesquelles elle figure.
la dernière ligne,
empty, contient la liste des configurations disponibles sans dépendance.
Comment le fichier de verrouillage Gradle vous simplifie la vie
Le verrouillage des dépendances peut éviter les erreurs inattendues causées par une dépendance transitive que vous ne maîtrisez pas lorsque vous utilisez des versions dynamiques (par exemple, 1.+ ou [1.0,2.0). C’est une situation fréquente qui peut survenir à tout moment en arrière-plan.
Voici un petit fichier build.gradle dans lequel nous déclarons une dépendance avec une version dynamique :

En exécutant la commande gradle -q dependencies, le résultat n’est ni 2.11 ni 2.14. Comme le montre l’image ci-dessous, Gradle a résolu les dépendances vers la version 2.13.

En vérifiant les dépendances répertoriées dans le fichier de verrouillage, nous pouvons maintenant confirmer que le résultat de la commande correspond à l’état du fichier de verrouillage de l’application de notre exemple.

Passons maintenant aux résultats !
Voici un cas où nous n’avons pas pu analyser le fichier build.gradle contenant des dépendances avec des versions dynamiques. Comparons les résultats en utilisant un fichier gradle.lockfile.

Comme vous pouvez le constater, les résultats obtenus avec le fichier gradle.lockfile sont nettement meilleurs : nous avons pu identifier 24 dépendances contre 0 dans le cas précédent, y compris les dépendances directes et transitives, et signaler 33 problèmes au total !

Pour approfondir le verrouillage des dépendances dans Gradle, consultez la documentation officielle.
Nous espérons que cette fonctionnalité de Snyk vous plaira ! Vous n’avez pas encore de compte Snyk ? Inscrivez-vous gratuitement.
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.
