Aller au contenu
CI/CD & Automatisation medium

Plumber : sécuriser vos pipelines GitLab CI et GitHub Actions

34 min de lecture

Logo Plumber

Si votre pipeline GitLab CI/CD utilise des images Docker non épinglées, des includes sur main ou un build basé sur Docker-in-Docker, ou si vos workflows GitHub Actions référencent encore des actions tierces par tag mutable, vous exposez votre chaîne à une attaque de supply chain. Plumber est un scanner de sécurité de pipelines : vous créez une configuration minimale au schéma v2.0, vous lancez plumber analyze, vous lisez trois ou quatre problèmes concrets, puis vous intégrez le contrôle dans votre CI avec le composant officiel. Ce guide s'adresse aux débutants et intermédiaires ; on commence volontairement par la CLI, ensuite par le composant GitLab, puis on termine par le PBOM, le score A-E et la Platform.

  • Créer une configuration minimale au schéma v2.0 avec plumber config init, puis la valider avant le premier scan
  • Migrer une configuration v1 existante vers le schéma v2.0 avec plumber config migrate
  • Lancer une analyse de sécurité locale sur un dépôt GitLab ou un dépôt GitHub et comprendre l'auto-détection
  • Corriger les failles fréquentes : image non épinglée, action tierce non pinnée par SHA, source d'action non autorisée, branche non protégée
  • Ajouter le composant GitLab CI/CD officiel sans créer de doubles pipelines ni de job .pre inutilisable
  • Exporter un PBOM et l'exploiter avec Trivy ou Grype

Plumber est un scanner de sécurité pour GitLab CI/CD et GitHub Actions. Côté GitLab, il interroge l'API du projet et lit la configuration mergée ; côté GitHub, il analyse en local les fichiers de .github/workflows via le moteur Rego. Dans les deux cas, il signale les écarts les plus dangereux : images non fiables, tags mutables, actions tierces non épinglées par SHA, sources d'actions non autorisées, branches non protégées, includes obsolètes, scripts téléchargés sans vérification ou usage de Docker-in-Docker. Chaque problème porte un code d'issue (ISSUE-XXX) que vous pouvez détailler avec plumber explain.

Votre situationPorte d'entrée recommandéePourquoi
Vous découvrez PlumberCLI localeVous comprenez d'abord ce que l'outil détecte et comment lire la sortie
Vous voulez l'ajouter rapidement à un pipeline existantComposant GitLab CI/CDVous évitez d'écrire un job manuel complet
Vous devez centraliser plusieurs projetsPlatformVous passez de l'analyse projet par projet à la gouvernance

Avant de lancer votre premier scan, vous avez besoin de :

  • un dépôt Git lié à un projet GitLab ou GitHub ;
  • côté GitLab : un token avec les scopes read_api et read_repository (rôle Maintainer sur le projet, ou un Project Access Token doté de ce rôle) ;
  • côté GitHub : la CLI gh authentifiée (gh auth login). Plumber lit le token depuis ~/.config/gh automatiquement ; aucune variable d'environnement n'est nécessaire ;
  • un terminal interactif si vous voulez utiliser plumber config init ;
  • au moins une configuration .plumber.yaml si vous passez par la CLI.
Fenêtre de terminal
mise use -g github:getplumber/plumber

Vérification :

Fenêtre de terminal
plumber version

La sortie doit afficher plumber version 0.3.82 (ou la version plus récente que vous avez installée) avec le hash de commit et la date de build.

Le chemin le plus simple est toujours le même : configurer, valider, scanner, corriger. Plumber détecte automatiquement le provider en lisant votre remote origin : si l'URL pointe vers GitLab, il bascule sur le chemin API GitLab ; si elle pointe vers GitHub, il scanne en local le dossier .github/workflows via le moteur Rego.

  1. Créez une configuration minimale avec le wizard interactif

    Fenêtre de terminal
    plumber config init
    plumber config validate

    plumber config init pose des questions ciblées puis génère un fichier court au schéma v2.0, adapté à votre projet. plumber config validate vérifie ensuite que le YAML est correct et signale les fautes de frappe dans les noms de contrôles ou de clés.

  2. Authentifiez-vous auprès de votre provider

    Côté GitLab, créez un token via User Settings -> Access Tokens avec read_api et read_repository, puis exportez-le :

    Fenêtre de terminal
    export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx

    Côté GitHub, authentifiez-vous une fois via la CLI gh, Plumber lit ensuite le token depuis ~/.config/gh sans variable d'environnement :

    Fenêtre de terminal
    gh auth login
    gh auth status
  3. Lancez l'analyse depuis le dépôt Git

    Fenêtre de terminal
    cd mon-projet
    plumber analyze

    Si votre dépôt possède un remote origin pointant vers GitLab ou GitHub, Plumber détecte automatiquement le provider, l'URL et le chemin du projet. Sur GitHub, l'analyse repose sur les fichiers locaux : aucun appel API n'est requis pour les contrôles workflow (l'API n'est appelée que pour la protection de branche).

  4. Lisez d'abord le résumé, pas toute la sortie

    Cherchez en priorité :

    • le pourcentage de conformité global ;
    • les contrôles en échec ;
    • les codes ISSUE-XXX ;
    • le nom précis du job ou du workflow concerné ;
    • le score A-E et les points sur 100.

Sur le dépôt de lab Bob74/pipeline-craft, la commande suivante analyse une branche de solution :

Fenêtre de terminal
export GITLAB_TOKEN=glpat-xxxx
plumber analyze --branch solution/lab-12 --score

Voici le résumé observé :

Auto-detected GitLab URL: https://gitlab.com
Auto-detected project: Bob74/pipeline-craft
Using configuration: .plumber.yaml
Analyzing project: Bob74/pipeline-craft on https://gitlab.com
Status: FAILED ✗
Total (required: 100%): 72.7%
Controls in failure:
- ISSUE-103 ×5 : images non épinglées par digest
- ISSUE-412 ×1 : Docker-in-Docker détecté
- ISSUE-401 ×5 : jobs hardcodés
Plumber Score: D (34 / 100 pts)
Poor - High-severity issues impacting the pipeline
Critical 0 High 6 Medium 6 Low 0

Le provider GitHub ne nécessite ni --gitlab-url ni GITLAB_TOKEN. Une fois gh auth login fait, lancez simplement :

Fenêtre de terminal
git clone <url-du-depot>
cd <depot>
plumber config generate --output .plumber.yaml --force
plumber analyze --score

Voici l'extrait d'un scan réel mené sur un projet open source très populaire (plusieurs dizaines de milliers d'étoiles), dont les workflows référencent 368 actions. La sortie est volontairement résumée et anonymisée :

Third-party actions must be pinned by commit SHA (0.0% compliant)
Total Action Refs: 368
Pinned By SHA: 79 Not Pinned By SHA: 148 Trusted-Owner Exempt: 141
HIGH [ISSUE-701] job "…" references action "…@main" with a mutable
ref - pin by commit SHA instead
HIGH [ISSUE-713] job "…" references action "…" from an unauthorized
source - restrict actions to authorized owners or an allowlist
CRIT [ISSUE-703] action "…" carries a published security advisory
Status: FAILED ✗
Total (required: 100%): 70.6%
Plumber Score
Critical 1 High 127 Medium 119 Low 0
▲ Critical malus applied (points capped at 30 while any Critical remains)

ISSUE-701 est l'apport phare du provider GitHub : il détecte les uses: qui référencent une action tierce par tag ou branche au lieu d'un SHA de 40 caractères. C'est la classe de faille exploitée par la compromission tj-actions/changed-files (CVE-2025-30066) en mars 2025. Sur ce dépôt, 148 références sur 368 ne sont pas épinglées par SHA, et un CVE connu (ISSUE-703) suffit à plafonner le score à cause du malus critique.

Le cas le plus fréquent est simple : le dépôt n'a pas de remote origin, ou l'URL du remote ne pointe ni vers GitLab ni vers GitHub.

Passez alors explicitement les paramètres :

Fenêtre de terminal
# GitLab self-hosted
plumber analyze --gitlab-url https://gitlab.com --project mon-groupe/mon-projet
# GitHub Enterprise Server
plumber analyze --github-url https://github.example.com --project mon-org/mon-projet

Plumber documente 64 codes d'issues organisés en neuf familles (voir l'annexe en bas de guide). Mais sur un projet qui n'a jamais été audité, ce sont presque toujours les mêmes quatre erreurs qui dominent, quel que soit le provider. Commencez par celles-ci.

Dans le lab pipeline-craft testé, Plumber a signalé :

HIGH [ISSUE-103] Job 'pytest' uses image without digest pinning: docker.io/python:3.12-slim
HIGH [ISSUE-103] Job 'docker-build' uses image without digest pinning: docker.io/docker:27

Le problème n'est pas seulement l'usage de latest. Un tag de version comme python:3.12-slim reste mutable : si le registre republie l'image, votre pipeline peut exécuter autre chose demain.

Pour activer le mode strict, la clé se trouve dans le schéma v2.0 sous la section provider :

.plumber.yaml
version: "2.0"
gitlab:
controls:
containerImageMustNotUseForbiddenTags:
enabled: true
containerImagesMustBePinnedByDigest: true

2. Actions tierces non pinnées par SHA (provider GitHub)

Section intitulée « 2. Actions tierces non pinnées par SHA (provider GitHub) »

C'est la faille la plus visible détectée par le provider GitHub, désormais sous le code ISSUE-701 :

HIGH [ISSUE-701] job "…" references action "…@main" with a mutable
ref - pin by commit SHA instead

Un uses: owner/action@v4 ou uses: owner/action@main reste mutable côté maintainer. Si l'action est compromise, comme tj-actions/changed-files en mars 2025 (CVE-2025-30066), votre workflow exécute silencieusement le code modifié avec ses secrets.

Activez le contrôle dans la section GitHub :

.plumber.yaml
github:
controls:
actionsMustBePinnedByCommitSha:
enabled: true
trustGithubOfficialActions: true

L'option trustGithubOfficialActions exempte les actions GitHub de premier rang (actions/*, github/*) pour concentrer le signal initial sur la surface tierce, celle qui n'est pas maintenue par GitHub.

3. Includes sur main, master ou HEAD (provider GitLab)

Section intitulée « 3. Includes sur main, master ou HEAD (provider GitLab) »

Un include pointant sur une branche mutable rend votre pipeline difficile à reproduire et peut casser sans changement dans votre dépôt.

Avant
include:
- project: security/templates
file: /pipelines/sast.yml
ref: main
Après
include:
- project: security/templates
file: /pipelines/sast.yml
ref: v2.4.1

Le contrôle associé est includesMustNotUseForbiddenVersions avec ISSUE-404.

Si la branche par défaut n'est pas protégée, un push direct ou une modification non revue peut contourner vos pratiques de revue et de sécurité. Le contrôle existe sous les deux providers et renvoie ISSUE-501 (absence de protection) ou ISSUE-505 (protection incomplète).

Exemple minimal
gitlab:
controls:
branchMustBeProtected:
enabled: true
defaultMustBeProtected: true
namePatterns:
- main
allowForcePush: false

Une cinquième erreur très courante : Docker-in-Docker

Section intitulée « Une cinquième erreur très courante : Docker-in-Docker »

Le lab a également remonté :

HIGH [ISSUE-412] job "docker-build" uses Docker-in-Docker service "docker:27-dind"
↳ at .gitlab-ci.yml:55
↳ docs: https://getplumber.io/docs/cli/issues/ISSUE-412

Sur des runners partagés, DinD augmente le risque d'évasion de conteneur et de mouvement latéral. Si vous construisez des images, privilégiez Kaniko ou Buildah. Le contrôle existe aussi côté GitHub avec ISSUE-413 (mode daemon non sécurisé).

Une fois les quatre erreurs de base corrigées, Plumber offre une famille de contrôles 7XX dédiée aux actions tierces, la surface la plus attaquée d'un workflow GitHub. Ces contrôles vont plus loin que le simple pinning et méritent d'être activés dès que votre pipeline est stable.

Restreindre les sources d'actions autorisées (ISSUE-713)

Section intitulée « Restreindre les sources d'actions autorisées (ISSUE-713) »

Épingler une action par SHA garantit qu'elle ne change pas, mais pas qu'elle vienne d'un auteur de confiance. Le contrôle githubActionMustComeFromAuthorizedSources signale toute action dont le propriétaire n'est ni GitHub, ni votre organisation, ni sur votre allowlist. C'est la parade directe contre le squat de dépôt ou une action tierce inconnue qui hériterait de vos secrets.

.plumber.yaml
github:
controls:
githubActionMustComeFromAuthorizedSources:
enabled: true
trustGithubOfficialActions: true
trustSameOrgActions: true
# Seuil d'étoiles minimal (0 = désactivé, nécessite l'API GitHub)
minimumStars: 0
trustedGithubActions:
- docker/setup-buildx-action
- docker/login-action
- ossf/scorecard-action

Bloquer les actions portant un CVE connu (ISSUE-703)

Section intitulée « Bloquer les actions portant un CVE connu (ISSUE-703) »

Le contrôle actionsMustNotCarryKnownCVEs croise chaque action épinglée avec les avis de sécurité publiés. Une seule action vulnérable remonte en Critical et, par le malus critique, plafonne le score global tant qu'elle n'est pas corrigée. Le contrôle complémentaire actionsMustNotBeArchived (ISSUE-702) signale les actions dont le dépôt amont est archivé, donc qui ne recevra plus aucun correctif.

.plumber.yaml
github:
controls:
actionsMustNotCarryKnownCVEs:
enabled: true
actionsMustNotBeArchived:
enabled: true

Le contrôle pullRequestTargetMustNotCheckoutHead détecte un workflow déclenché par pull_request_target qui fait un checkout de la HEAD de la pull request. C'est exactement le motif exploité par la compromission tj-actions/changed-files : le code non fusionné d'un contributeur externe s'exécute avec les secrets du dépôt.

.plumber.yaml
github:
controls:
pullRequestTargetMustNotCheckoutHead:
enabled: true

Fichier de configuration : schéma v2.0 par provider

Section intitulée « Fichier de configuration : schéma v2.0 par provider »

Le schéma v2.0 introduit en 0.3 organise les contrôles par provider : tout ce qui concerne GitLab CI/CD vit sous gitlab.controls:, tout ce qui concerne GitHub Actions vit sous github.controls:. Le top-level controls: de la v1 disparaît, et le bloc engine: aussi (le moteur Rego est désormais le seul disponible et tourne par défaut).

.plumber.yaml
version: "2.0"
gitlab:
controls:
containerImageMustNotUseForbiddenTags:
enabled: true
tags:
- latest
- dev
- main
containerImagesMustBePinnedByDigest: true
containerImageMustComeFromAuthorizedSources:
enabled: true
trustDockerHubOfficialImages: true
trustedUrls:
- $CI_REGISTRY_IMAGE:*
- registry.gitlab.com/security-products/*
branchMustBeProtected:
enabled: true
defaultMustBeProtected: true
namePatterns:
- main
allowForcePush: false
includesMustNotUseForbiddenVersions:
enabled: true
forbiddenVersions:
- latest
- main
- HEAD
github:
controls:
actionsMustBePinnedByCommitSha:
enabled: true
trustedOwners:
- actions
- github
branchMustBeProtected:
enabled: true
defaultMustBeProtected: true
namePatterns:
- main

Si vous arrivez d'une version antérieure et que votre .plumber.yaml utilise encore le top-level controls:, plumber config migrate ré-écrit le fichier au schéma v2.0 en préservant commentaires et ordre :

Fenêtre de terminal
# Crée .plumber.yaml.v2 à côté du fichier original
plumber config migrate
# Ou écrase en place (le fichier original part en .plumber.yaml.bak)
plumber config migrate --in-place

La migration encapsule le bloc controls: existant sous gitlab.controls:, upgrade version: "1.0" vers "2.0" et supprime le bloc engine: devenu obsolète. Les sections gitlab: ou github: déjà présentes sont laissées intactes.

Fenêtre de terminal
# Vérifier le fichier
plumber config validate
# Voir la configuration effective sans commentaires
plumber config view
# Comparer la configuration locale au défaut (sortie colorisée)
plumber config diff
# Générer le template complet officiel (sections gitlab: et github:)
plumber config generate --output .plumber.yaml --force

plumber config diff est apparu en 0.3 et permet de voir d'un coup d'œil ce qui diffère du template officiel : vert pour ce que vous avez ajouté ou modifié, rouge pour ce que vous avez retiré. Utile sur un projet hérité avant de proposer un durcissement.

Ajouter Plumber à GitLab CI avec le composant officiel

Section intitulée « Ajouter Plumber à GitLab CI avec le composant officiel »

Une fois le premier scan local compris, le bon point d'entrée côté GitLab est le composant CI/CD officiel.

Ajoutez d'abord le token GITLAB_TOKEN dans Settings -> CI/CD -> Variables, puis utilisez ce squelette :

.gitlab-ci.yml
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
- if: $CI_COMMIT_TAG
include:
- component: gitlab.com/getplumber/plumber/plumber@v0.3.9

Ce bloc workflow:rules évite de créer à la fois un pipeline de branche et un pipeline de merge request sur le même push.

.gitlab-ci.yml
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
- if: $CI_COMMIT_TAG
include:
- component: gitlab.com/getplumber/plumber/plumber@v0.3.9
inputs:
stage: test
threshold: 80
config_file: .plumber.yaml
pbom_file: plumber-pbom.json
pbom_cyclonedx_file: plumber-cyclonedx-sbom.json

Le composant recherche la configuration dans cet ordre :

  1. l'input config_file s'il est défini ;
  2. le fichier .plumber.yaml à la racine du dépôt ;
  3. la configuration par défaut embarquée dans l'image.

Gardez cette variante pour les besoins spécifiques. Si vous voulez ajouter --mr-comment et --badge dans un job manuel, séparez-les en deux jobs : le commentaire de merge request n'a de sens qu'en pipeline de MR, et le badge ne se met à jour que sur la branche par défaut.

Sur un GitLab auto-hébergé, vous ne pouvez pas consommer directement le composant depuis gitlab.com. Le chemin correct est le suivant :

  1. Importez le dépôt https://gitlab.com/getplumber/plumber.git dans votre instance.

  2. Activez le CI/CD Catalog dans le projet importé.

  3. Publiez une release en lançant un pipeline sur un tag déjà importé, par exemple v0.3.9.

  4. Consommez ensuite le composant local dans vos pipelines.

.gitlab-ci.yml
include:
- component: gitlab.example.com/infrastructure/plumber/plumber@v0.3.9

Une fois la lecture du scan comprise, vous pouvez passer au PBOM.

Le PBOM (Pipeline Bill of Materials) est l'inventaire des dépendances de votre pipeline : images Docker, composants GitLab, templates et includes.

Fenêtre de terminal
plumber analyze \
--pbom plumber-pbom.json \
--pbom-cyclonedx plumber-cyclonedx-sbom.json
FormatQuand l'utiliserCe qu'il contient
PBOM natifVous voulez comprendre le pipeline en détailMétadonnées riches propres à Plumber
CycloneDXVous voulez brancher un autre outilFormat standard pour Trivy, Grype ou Dependency-Track
Fenêtre de terminal
trivy sbom plumber-cyclonedx-sbom.json --severity HIGH,CRITICAL
Fenêtre de terminal
grype sbom:plumber-cyclonedx-sbom.json --fail-on high

Remonter les findings dans les tableaux de bord sécurité

Section intitulée « Remonter les findings dans les tableaux de bord sécurité »

Le PBOM inventorie le pipeline ; pour faire remonter les écarts de conformité dans les plateformes, Plumber produit deux rapports de findings standardisés. Vous les générez en ajoutant un drapeau à plumber analyze.

  • --sarif écrit un rapport au format SARIF 2.1.0, consommé par GitHub Code Scanning (onglet Security du dépôt) et par le Security Dashboard de GitLab.
  • --glsast écrit un rapport GitLab SAST (gl-sast-report.json) qui alimente le Security Dashboard et le widget de merge request GitLab.
Fenêtre de terminal
# Rapport SARIF - GitHub Code Scanning ou Security Dashboard GitLab
plumber analyze --sarif plumber.sarif
# Rapport SAST natif GitLab - widget de merge request
plumber analyze --glsast gl-sast-report.json

Dans un job GitLab manuel, déclarez le fichier produit comme artefact de rapport sast pour que GitLab l'affiche automatiquement dans la merge request :

.gitlab-ci.yml
plumber-scan:
# ... un script qui lance « plumber analyze --glsast gl-sast-report.json »
artifacts:
reports:
sast: gl-sast-report.json

Ces deux formats ne remplacent pas la lecture du résumé : ils servent à historiser les findings et à les rapprocher des autres scanners de sécurité déjà branchés sur vos tableaux de bord.

À ce stade, vous savez déjà lancer Plumber et lire les erreurs les plus utiles. Les fonctionnalités suivantes sont pratiques, mais elles ne doivent pas être votre point d'entrée.

Fenêtre de terminal
plumber explain ISSUE-412
# raccourci accepté : plumber explain 412

Cette commande renvoie la description du problème, son impact, la remédiation et le lien vers la documentation officielle. Trois flags complètent l'usage :

Fenêtre de terminal
# Liste compacte des 64 codes disponibles
plumber explain --list
# Référence exhaustive (description + remédiation pour chaque code)
plumber explain --all
# Sortie JSON, exploitable dans un script
plumber explain ISSUE-701 --json

Le score est désormais toujours calculé à chaque plumber analyze : il alimente automatiquement le badge de conformité et les commentaires de merge request. Le flag --score reste accepté pour afficher le détail à l'écran, et --score-point montre le décompte de points.

Fenêtre de terminal
plumber analyze --score
plumber analyze --score-point

Sur le scan réel présenté plus haut, le résultat était :

Plumber Score
Critical 1 High 127 Medium 119 Low 0
▲ Critical malus applied (points capped at 30 while any Critical remains)

Le score sert à prioriser. Il ne remplace pas la lecture des contrôles en échec. Le scoring-v3 applique des plafonds par code et des poids rééquilibrés : un même nombre d'issues ne produit pas mécaniquement la même note. Surtout, une seule issue Critical déclenche un malus qui plafonne les points tant qu'elle n'est pas corrigée.

Fenêtre de terminal
# Uniquement les images et la protection de branche
plumber analyze --controls containerImageMustNotUseForbiddenTags,branchMustBeProtected
# Tout sauf la protection de branche
plumber analyze --skip-controls branchMustBeProtected

Avec le composant GitLab, activez-les ainsi :

.gitlab-ci.yml
include:
- component: gitlab.com/getplumber/plumber/plumber@v0.3.9
inputs:
mr_comment: true
badge: true

La Platform n'est pas le bon point de départ pour un débutant. Elle devient pertinente quand vous devez :

  • suivre plusieurs projets dans le temps ;
  • disposer d'un tableau de bord centralisé ;
  • gérer des politiques communes à plusieurs équipes ;
  • auditer des variables, des quotas ou des règles de merge request à plus grande échelle.

Plumber v0.3.82 documente 64 codes d'issues organisés en neuf familles, chacun avec une description et une remédiation accessibles via plumber explain ISSUE-XXX. La numérotation a évolué : les actions tierces ont désormais leur propre famille 7XX. Pour obtenir la liste exacte depuis votre installation, utilisez :

Fenêtre de terminal
# Liste compacte (un code = une ligne)
plumber explain --list
# Référence complète (description + remédiation pour chaque code)
plumber explain --all
# Détail d'un code en JSON, exploitable dans un script
plumber explain ISSUE-701 --json

Le tableau ci-dessous donne la grille de lecture pour identifier rapidement la famille concernée par une issue remontée :

FamillePlageCouvreExemples
Images de conteneursISSUE-1XX (3 codes)Sources, tags, digestISSUE-101 source non autorisée, ISSUE-102 tag interdit, ISSUE-103 image non pinnée par digest
Exécution et expressionsISSUE-2XX (12 codes)Variables, injection, contexteISSUE-203 debug trace, ISSUE-207 injection template, ISSUE-209 $GITHUB_ENV écrit, ISSUE-213 toJson(github)
Secrets et jetonsISSUE-3XX (8 codes)Fuites, secrets: inherit, tokensISSUE-302 secrets: inherit, ISSUE-307 credentials persistés, ISSUE-309 toJson(secrets)
Jobs, templates et structureISSUE-4XX (17 codes)Jobs, includes, DinD, OIDCISSUE-401 job hardcodé, ISSUE-404 include mutable, ISSUE-412 DinD, ISSUE-421 publish sans OIDC
Protection de brancheISSUE-5XX (2 codes)branchMustBeProtectedISSUE-501 absence de protection, ISSUE-505 protection incomplète
Hygiène de workflowISSUE-6XX (1 code)NommageISSUE-601 workflow sans name:
Actions tierces (supply chain)ISSUE-7XX (12 codes)Pinning, sources, CVE, archivageISSUE-701 action non SHA, ISSUE-702 dépôt archivé, ISSUE-703 CVE connu, ISSUE-713 source non autorisée
Permissions et déclencheursISSUE-8XX (4 codes)permissions:, triggersISSUE-801 pas de permissions:, ISSUE-802 trigger dangereux, ISSUE-804 pull_request_target piégé
Hygiène du dépôtISSUE-9XX (5 codes)Dependabot, scanners, SECURITY.mdISSUE-903 pas d'outil de mise à jour, ISSUE-904 pas de scanner statique, ISSUE-905 pas de SECURITY.md

La famille 7XX est la plus stratégique pour la supply chain : elle concentre les protections contre les actions tierces compromises, la surface la plus attaquée d'un workflow GitHub. Les familles 8XX et 9XX sont quasi-exclusivement GitHub : elles couvrent ce que l'écosystème Actions expose comme risques (permissions du GITHUB_TOKEN, Dependabot, scanners CI, SECURITY.md).

Avant de parcourir le tableau, gardez en tête deux pièges propres à la 0.3 : la migration v1 → v2 est nécessaire dès que votre .plumber.yaml utilise encore le top-level controls:, et le provider GitHub s'appuie sur la CLI gh pour l'authentification (pas de variable d'environnement à exporter).

SymptômeCause probableSolution
configuration file not foundAucun .plumber.yaml présent pour la CLICréez le fichier avec plumber config init ou plumber config generate
unknown key 'controls' at rootConfiguration encore au schéma v1Lancez plumber config migrate pour passer au schéma v2.0
GITLAB_TOKEN environment variable is requiredVariable manquante côté provider GitLabExportez GITLAB_TOKEN avant plumber analyze
401 Unauthorized (GitLab)Token incomplet ou invalideVérifiez read_api + read_repository sur le token
Aucune authentification GitHub détectéePas de session gh activeLancez gh auth login ; Plumber lit ensuite ~/.config/gh automatiquement
403 Forbidden on MR commentScope insuffisantUtilisez api si vous activez mr_comment
403 Forbidden on badgeScope insuffisant ou rôle trop faibleUtilisez api et un rôle Maintainer
Le composant ne s'exécute pasJob en .pre sans autre stage normalForcez stage: test
Deux pipelines sont créés sur le même pushworkflow:rules absentAjoutez le bloc recommandé par GitLab
Le projet n'est pas auto-détectéRemote Git absent ou mal nomméVérifiez le remote origin ou passez --gitlab-url / --github-url et --project
  • Plumber scanne la sécurité de vos pipelines GitLab CI/CD et GitHub Actions depuis la même CLI (v0.3.82 ; composant GitLab v0.3.9, versionnages distincts)
  • Le chemin débutant est simple : config init, config validate, plumber analyze
  • Le schéma v2.0 sépare les contrôles par provider (gitlab.controls: / github.controls:) ; plumber config migrate fait la conversion depuis la v1
  • Commencez par corriger les images non épinglées, les actions non SHA (ISSUE-701), les includes mutables et les branches non protégées
  • Activez ensuite les protections supply chain : sources autorisées (ISSUE-713), CVE connues (ISSUE-703), pull_request_target piégé (ISSUE-804)
  • Le PBOM sert à inventorier le pipeline ; le CycloneDX facilite l'intégration avec Trivy et Grype
  • Les rapports --sarif et --glsast font remonter les findings dans GitHub Code Scanning et le Security Dashboard GitLab
  • Le score est toujours calculé (scoring-v3) : une seule issue Critical plafonne les points tant qu'elle n'est pas corrigée
  • 64 codes d'issues en neuf familles ; la liste exacte vient toujours de plumber explain --list sur votre version
  • Gardez la Platform pour les besoins de gouvernance multi-projets

Plumber est un scanner de sécurité de pipelines CI/CD qui analyse vos configurations GitLab CI/CD et GitHub Actions pour détecter les failles de supply chain : actions non épinglées, sources non fiables, secrets exposés, branches non protégées. Il rend un score et un rapport de findings exploitable dans vos tableaux de bord.

La CLI et le composant GitLab couverts par ce guide sont utilisables en ligne de commande et en pipeline. La Platform (tableau de bord multi-projets, historique, gouvernance) est un produit distinct, pertinent seulement quand vous pilotez un portefeuille de projets.

Quelle différence entre Plumber et Trivy ou zizmor ?

Section intitulée « Quelle différence entre Plumber et Trivy ou zizmor ? »

Trivy scanne des images et des SBOM à la recherche de CVE. zizmor cible spécifiquement les workflows GitHub Actions. Plumber couvre les deux plateformes (GitLab et GitHub) sous une même configuration, produit un score et un PBOM, et se concentre sur la posture du pipeline plutôt que sur les vulnérabilités des dépendances. Les trois sont complémentaires : Plumber peut d'ailleurs exporter un CycloneDX que Trivy ou Grype analysent ensuite.

Non. Plumber lit et analyse votre configuration, il ne la réécrit pas. Les corrections (épingler une action par SHA, ajouter un bloc permissions:, protéger une branche) restent à votre main. C'est un détecteur, pas un correcteur automatique.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn