Guide complet de la gestion des dépendances des gems Ruby
5 août 2022
0 minutes de lectureComme d’autres langages de programmation, Ruby dispose de tout un écosystème de bibliothèques open source tierces, appelées gems ou parfois gems Ruby. Ces gems sont créées par la communauté et disponibles sur RubyGems.org, le registre officiel des bibliothèques Ruby. Comme dans les autres écosystèmes open source, des acteurs malveillants peuvent publier intentionnellement du code malveillant, par exemple avec des portes dérobées ou des mécanismes de collecte d’identifiants. Il est donc essentiel de gérer et d’auditer avec soin vos gems Ruby open source.
Dans cet article, je passe en revue les concepts et les outils qui composent l’écosystème des dépendances Ruby et réponds aux questions courantes des développeurs Ruby.
Le langage de programmation Ruby
Vous connaissez peut-être Ruby on Rails (RoR), le framework de développement web populaire qui a largement contribué au succès et à la popularité de Ruby. RoR repose sur Ruby, un langage dynamique, multiplateforme et interprété. Ses fichiers de code source sont facilement reconnaissables à leur extension .rb.
Que sont les gems Ruby ?
Les gems sont des bibliothèques de code source empaquetées, modulaires, indépendantes et facilement réutilisables dans différents projets.
Qu’est-ce que RubyGems et en quoi diffère-t-il de Bundler ?
RubyGems est le registre central de packages où sont partagées les gems Ruby open source tierces. C’est également le gestionnaire de packages officiel de Ruby, appelé gem lorsqu’on l’utilise via l’interface en ligne de commande.

RubyGems permet aux développeurs d’accéder à un écosystème de centaines de milliers de bibliothèques open source et de les utiliser dans leurs projets.
L’interface CLI gems de RubyGems est préinstallée dans un environnement Ruby fonctionnel. Les développeurs peuvent donc installer immédiatement leurs dépendances open source préférées, par exemple :
L’interface CLI gems gère toutefois chaque dépendance individuellement : elle les récupère depuis un registre et les installe sur le système de fichiers, afin qu’elles soient disponibles et faciles à importer dans les projets de code Ruby.
Le projet Bundler, qui est techniquement une gem Ruby et s’installe comme telle, simplifie l’installation des gems une par une. Il permet également d’obtenir un arbre de dépendances déterministe et cohérent grâce à un fichier manifeste appelé Gemfile et à son fichier de verrouillage associé, Gemfile.lock. Ce dernier verrouille les dépendances dans tout l’arbre et garantit la cohérence des installations au fil du temps.
Bundler étant une gem, il est très facile de commencer à l’utiliser :
Cette commande met l’outil en ligne de commande bundler à la disposition des développeurs.
Le Gemfile Ruby
Le fichier nommé Gemfile est un fichier manifeste texte qui décrit toutes les dépendances à utiliser dans le projet, ainsi que d’autres instructions de métadonnées prises en charge par l’outil bundler.
Voici un exemple de Gemfile simple :
Le Gemfile ci-dessus définit l’entrée source, qui indique le dépôt distant depuis lequel Bundler téléchargera les gems. Chaque ligne gem définit une bibliothèque open source, la version à récupérer et la source où la trouver.
Voici un exemple plus complexe qui montre comment les gems Ruby peuvent provenir de différents emplacements :
Les détails de ces sources sont décrits dans la documentation Git officielle de Bundler.
De quoi se compose une gem Ruby ?
Une gem Ruby est du code source Ruby empaqueté et modulaire, réutilisable par d’autres gems Ruby, par des applications Ruby ou, plus généralement, par les utilisateurs qui interagissent avec elle en ligne de commande, comme nous l’avons vu plus haut avec Bundler.
Les gems Ruby suivent généralement une convention qui comprend le code source Ruby, les tests, d’éventuels fichiers exécutables mis à la disposition de l’utilisateur dans son chemin d’accès et, surtout, le fichier de spécification de la gem Ruby, appelé Gemspec.
Certains répertoires, comme test/ et bin/, sont assez explicites : ils contiennent respectivement le code de test de cette dépendance et le fichier exécutable à distribuer et à installer avec celle-ci. On peut également citer les fichiers Gemfile et Gemfile.lock, que nous avons découverts en présentant Bundler pour gérer les gems Ruby et son fichier de verrouillage, qui garantit des installations déterministes et reproductibles en toute sécurité.
Le fichier Rakefile est associé au projet open source Rake, un outil de compilation pour les projets Ruby similaire à make. Son nom rappelle donc celui de Makefile. En voici un exemple de contenu :
Le fichier Rakefile importe les classes nécessaires depuis la gem Rake et définit une tâche test. Lorsque la commande rake test est exécutée dans ce répertoire, elle demande au programme Rake de rechercher, à l’aide d’un motif glob, tous les fichiers de test du dossier test/, puis de les exécuter. Pour en savoir plus sur le format du Rakefile, consultez la documentation du dépôt du projet Rake.
Un autre fichier, que vous avez peut-être remarqué dans l’arborescence ci-dessus, est le fichier gemspec, qui porte souvent le même nom que le package, par exemple base64ness.gemspec. Le fichier gemspec décrit la gem Ruby et fournit des métadonnées sur cette dépendance. Il aide le registre RubyGems à suivre, analyser et mettre ces informations à la disposition des utilisateurs qui recherchent des gems Ruby.
Voici un exemple du fichier base64ness.gemspec de la gem Ruby base64 mentionnée plus haut :
Le site RubyGems propose une documentation complète sur la classe Specification mentionnée plus haut. Elle présente notamment les métadonnées supplémentaires associées à une gem Ruby, les fonctionnalités avancées permettant aux responsables de la maintenance Ruby de définir des exécutables, l’ajout d’extensions C aux gems Ruby qui, grâce à la compilation croisée, prennent en charge les modules natifs, et bien plus encore.
Conseil : si vous souhaitez découvrir le contenu d’une gem Ruby en particulier, vous pouvez la décompresser dans un répertoire et examiner son code source comme suit :
Gérer l’installation des dépendances des gems Ruby
Les dépendances peuvent être regroupées logiquement en catégories spécifiques selon leur usage. Par exemple, vous pouvez avoir des dépendances de gems Ruby pour la production, ainsi que des gems Ruby de développement, à installer uniquement lorsque vous développez en local.
Pour les distinguer, vous pouvez définir le manifeste Gemfile suivant :
Vous pouvez ensuite installer les dépendances par catégorie avec Bundler. Par exemple, la commande ci-dessous n’installera que les dépendances de production :
Pourquoi avons-nous besoin d’un Gemfile.lock ?
Si vous étiez limité à la définition de vos dépendances à l’aide du manifeste de packages Gemfile de Bundler, vous seriez confronté aux contraintes suivantes :
Seules les dépendances directes des gems Ruby sont documentées.
Les versions des packages de ces dépendances directes des gems Ruby sont définies de manière imprécise et peu restrictive. Il peut s’agir de la dernière version disponible ou simplement de la dernière version dans une plage sémantique donnée.
Même si vous verrouillez ces dépendances directes des gems Ruby sur des versions précises, chaque nouvelle installation peut malgré tout résoudre vers une version inattendue d’une gem dépendante.
En conséquence, sans fichier de verrouillage pour figer l’ensemble des dépendances imbriquées des gems Ruby installées dans votre projet, vous risquez d’obtenir des versions indéterminées des gems installées. C’est probablement la dernière chose que vous souhaitez dans un environnement d’intégration continue (CI) ou de compilation automatisé, ou pour les autres développeurs Ruby qui collaborent avec vous sur le projet.
Voici donc le Gemfile.lock :
Examinons la spécification et le format de ce fichier de verrouillage des dépendances des gems :
La directive
GEMouvre le bloc qui répertorie toutes les dépendances des gems Ruby sous la forme d’un arbre imbriqué, avec les dépendances directes et transitives ainsi que leurs versions. Elles sont indiquées sous la directivespecs. La directiveremoteindique à l’outil bundler la source où récupérer ces gems Ruby pour les installer.La directive
PLATFORMScontient la liste des plateformes cibles pour lesquelles il faut compiler des gems Ruby natives, en raison notamment de la chaîne de compilation croisée requise pour les extensions Ruby écrites en C.La directive
RUBY VERSIONest facultative et indique la version de l’environnement d’exécution Ruby utilisée lors de la création du fichier de verrouillageGemfile.lock.La directive
BUNDLED WITHindique la version de Bundler utilisée pour créer le fichier de verrouillage. Les développeurs utilisant des versions plus anciennes devraient envisager une mise à niveau afin de rester à jour et de garantir des résultats d’installation de gems Ruby cohérents et fiables.
bundler-audit et la nécessité de renforcer la sécurité des gems Ruby
Un vaste écosystème implique de grandes responsabilités. C’est bien vrai. C’est là qu’intervient le projet communautaire bundler-audit. Cette gem Ruby analyse les dépendances répertoriées dans le fichier de verrouillage du projet (Gemfile.lock), les compare à une base de données de gems Ruby vulnérables et signale les versions correspondant à une ou plusieurs vulnérabilités.
Premiers pas avec bundler-audit pour détecter les vulnérabilités des gems Ruby
Pour commencer à détecter les vulnérabilités avec bundler-audit, nous devons d’abord l’installer, comme n’importe quelle autre gem Ruby :
Une fois installé, bundler-audit doit télécharger des avis de sécurité depuis des ressources telles que ruby-adivsory-db, une base de données gérée par la communauté qui puise elle-même ses données dans GitHub Advisory et dans la base de données Open Source Vulnerability gérée par Google :
Si tout se passe bien, la commande bundler-audit devrait afficher un résultat similaire à celui-ci, indiquant que tout est à jour :
Nous pouvons ensuite exécuter bundle-audit sans argument supplémentaire pour rechercher des vulnérabilités de sécurité. Voici le résultat obtenu pour mon projet Ruby on Rails local :
Le résultat semble satisfaisant, mais il peut être trompeur et vous exposer à des risques inutiles. En réalité, il s’agit d’un faux négatif : des vulnérabilités de sécurité existent bel et bien dans certaines versions des dépendances que j’ai installées.
Tout le respect dû au travail de la communauté pour créer des outils de sécurité, ses équipes disposent probablement de moyens et de ressources insuffisants pour assurer une couverture adéquate des vulnérabilités. C’est là qu’intervient le scanner de sécurité de Snyk Open Source.
Snyk propose un outil CLI gratuit, soutenu par une entreprise de sécurité qui place les développeurs au premier plan et dispose d’une base de données très complète de rapports sur les vulnérabilités des gems Ruby. Vous pouvez l’installer pour analyser vos dépendances.
Sécurisez gratuitement vos gems Ruby avec Snyk
Essayons Snyk et voyons quelles vulnérabilités de sécurité il détecte dans notre projet Rails. Si vous utilisez un MacBook Pro M1 comme moi, exécutez la commande suivante :
Cette commande télécharge le binaire Snyk autonome, le rend exécutable et l’ajoute à votre chemin d’accès. Si vous préférez une autre méthode d’installation (par exemple brew sur macOS, scoop sur Windows ou une autre méthode), consultez la documentation de prise en main de la CLI Snyk.
Une fois la CLI Snyk installée, nous pouvons l’exécuter comme suit :
Si c’est la première fois que vous l’utilisez, le message suivant s’affiche :
Vous devrez alors saisir snyk auth, puis suivre les instructions pour copier une URL d’authentification dans votre navigateur et vous connecter ou vous inscrire afin de recevoir votre clé API. Vous reviendrez rapidement à l’invite de commande pour poursuivre l’analyse :
Eh bien, deux problèmes et 59 chemins vulnérables… Notre projet est moins sûr que nous le pensions. Pour le moment, il semble qu’aucune version plus récente ne permette de mettre à niveau ces bibliothèques dans l’arbre de dépendances imbriquées. Pour que Snyk surveille en continu le Gemfile de notre projet et recherche les nouvelles versions correctives à appliquer, nous pouvons procéder de l’une des façons suivantes :
Rendez-vous sur https://apps.snyk.io et connectez Snyk au dépôt de code source sur GitHub ou ailleurs. Snyk pourra ainsi surveiller ce projet en arrière-plan.
Exécutez la commande
snyk monitorpour créer un instantané des fichiersGemfileetGemfile.lockactuels et les surveiller en continu. Veuillez noter que vous devrez l’exécuter dans un environnement d’intégration continue ou de compilation automatisée afin qu’à chaque mise à jour des fichiers manifestes de packages Ruby, un nouvel instantané soit envoyé à Snyk, qui pourra ainsi les surveiller et en assurer le suivi.
Dois-je utiliser bundle-audit ou Snyk ?
Utilisez les deux. Ce n’est pas une réponse diplomatique : ils sont véritablement complémentaires de plusieurs façons :
Snyk propose une base de données complète de vulnérabilités de sécurité dans l’écosystème Ruby, organisée manuellement et tenue à jour, souvent même avant bundle-audit et les autres outils.
Bundle-audit effectue d’autres vérifications en plus de l’analyse des vulnérabilités, notamment pour s’assurer que vos gems Ruby ne sont pas récupérées depuis des sources non sécurisées telles que
http://etgit://, qui pourraient permettre une attaque de l’intercepteur ou une injection dans le fichier de verrouillage, et ainsi altérer le code source que vous recevez et exécutez.
En résumé
Nous avons vu comment gérer les gems Ruby en tant que dépendances de projet, pourquoi il est important d’utiliser un fichier de verrouillage, ainsi que d’autres aspects et bonnes pratiques recommandées, comme analyser vos dépendances Ruby avec des outils tels que Snyk et bundler-audit pour les utiliser en toute sécurité.
Autres ressources Ruby :
Si vous pratiquez également le développement JavaScript, je vous recommande vivement de lire ce qu’est package-lock.json et comment fonctionne un fichier de verrouillage pour les packages Yarn et npm.
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis de capture du drapeau en regardant à la demande notre atelier virtuel d’initiation.



