Article · 10 septembre 2026 · 7 min de lecture

Debug Detective : la bibliothèque fermée

Un pipeline qui refusait de démarrer. Aucun job en échec, aucun log, aucune croix rouge à côté d'une étape, parce que rien n'était jamais allé jusqu'à s'exécuter. Juste un refus à la porte, et un message d'erreur écrit pour m'en dire le moins possible.

Didi, une grenouille en trench et feutre, se tient dans la lumière barrée devant la porte fermée d'une bibliothèque, Sudo la mouche à son épaule.

La scène

Le montage était volontaire. La logique de pipeline ne vit pas dans le dépôt applicatif ; elle vit dans un projet de composants, une bibliothèque de petits fichiers YAML versionnés que chaque projet inclut et étend. Un correctif, tous les consommateurs, zéro copier-coller. C'est tout l'intérêt.

Puis un pipeline a cessé de démarrer. Pas d'échouer : de démarrer. Aucun graphe de jobs à consulter, aucun log à ouvrir, aucune étape à déplier. GitLab avait refusé d'assembler la configuration, et tout ce qu'il consentait à me dire était ceci :

Project `group/components-ci` not found or access denied!

Premières vérifications

J'ai fait les choses évidentes, dans l'ordre évident, et chacune est revenue propre.

Donc : le projet est là, le fichier est là, la référence est là, et GitLab dit que le projet est introuvable. Cette contradiction est l'endroit où j'ai perdu les heures suivantes.

La fausse piste

Je me suis attaqué au .gitlab-ci.yml. Évidemment. L'erreur apparaît au moment où la configuration est analysée, la configuration c'est ce fichier, donc la faute est dans ce fichier. Ce raisonnement est propre, et il est faux.

J'ai réécrit le bloc d'include de trois façons. Avec la référence entre guillemets, puis sans. Je l'ai déplacé en haut du fichier au cas où l'ordre compterait. Je l'ai passé au linter CI, qui m'a répondu que la syntaxe était bonne, ce dont j'ai conclu que le linter ne vérifiait pas assez sérieusement. Quand votre modèle du problème est faux, chaque preuve qui le contredit se fait expliquer au lieu d'être crue.

Puis j'ai attrapé le second piège, et je veux le nommer parce qu'il ressemble tellement à la réponse : la liste d'autorisation du jeton de job. J'en avais lu la documentation, ça parle d'un projet qui accède à un autre, ça se règle dans les paramètres CI/CD, et ajouter mon projet à cette liste ressemblait exactement au correctif. Ça n'a rien fait, parce que le jeton de job gouverne ce qu'un job en cours d'exécution peut appeler. Mon problème survenait avant qu'aucun job n'existe.

Le plus coûteux en débogage n'est pas la mauvaise réponse. C'est la réponse qui sonne juste, dans la mauvaise couche.

L'indice

La rupture est venue d'une lecture attentive du message d'erreur, au lieu de le survoler. Not found or access denied. Deux possibilités, reliées par un ou, et je n'avais enquêté que sur la première.

Cette ambiguïté est volontaire. Si GitLab vous disait qu'un projet privé existe mais que vous ne pouvez pas le lire, il confirmerait l'existence de projets privés à quiconque saurait deviner un chemin. Il fond donc les deux cas dans un seul message. C'est une décision de sécurité défendable, et c'est aussi la raison pour laquelle on prend si facilement la mauvaise branche : elle vous tend une phrase où le mot introuvable occupe toute la place, et enterre discrètement la moitié qui compte.

La révélation

Un include: project: n'est pas résolu par le pipeline. Il est résolu au nom de l'utilisateur qui a déclenché le pipeline.

GitLab lit la configuration pour le compte de cette personne, et applique ses permissions sur l'autre projet. Pour un projet privé, l'utilisateur déclencheur doit avoir au moins le rôle Reporter dessus. Pour un projet interne, n'importe quel utilisateur authentifié non externe suffit. Pour un projet public, rien n'est requis.

Ma bibliothèque de composants n'était pas lisible par le compte qui lançait ce pipeline. Le fichier était exactement là où je le disais ; le pipeline n'avait simplement pas le droit de le savoir. Toutes mes vérifications, je les avais faites en tant que moi-même, dans un navigateur où j'avais l'accès. Je confirmais, encore et encore, que moi je voyais le fichier, alors que la question n'a jamais porté sur moi.

Le détail qui aurait résolu l'affaire en cinq minutes

Comme le contrôle est par utilisateur, cette panne n'est pas homogène dans une équipe. Le même pipeline, le même commit, la même configuration, passe au vert quand une personne le lance et au rouge quand une autre le lance. Si vous entendez un jour « ça marche quand je le déclenche et ça casse quand c'est lui », arrêtez de regarder le YAML. Ce symptôme n'appartient pas à un fichier. Les fichiers ne changent pas selon qui les lit ; les permissions, si.

Je n'avais pas cet indice à l'époque parce que je travaillais seul. C'est la première chose que je demanderais aujourd'hui.

Le correctif, et ce qu'il coûte

Il y a deux réponses honnêtes, et le choix dépend de ce à quoi sert la bibliothèque.

J'ai choisi la visibilité. Non pour éviter le travail d'appartenance, mais parce que devoir répondre à la question était utile : si une bibliothèque partagée a besoin que son contenu reste secret, le secret est au mauvais endroit. La rendre publique a transformé un problème de permissions en une vérification de conception, qu'elle a passée.

Note du détective

Les permissions de qui votre pipeline utilise-t-il ?

La plupart des configurations CI comportent au moins un endroit où l'accès est accordé à une personne plutôt qu'à un système, et ça reste invisible jusqu'à ce que la personne parte en vacances. Les trouver, c'est l'objet d'un audit de plateforme : une semaine, une liste classée, un plan à quatre-vingt-dix jours. Dites-nous ce que votre pipeline va chercher.

Contactez-nous