Vous avez investi dans votre supply chain : SBOM générés avec Syft, images signées avec Cosign, attestations SLSA produites par vos pipelines. Mais quand un développeur ouvre une pull request qui ajoute une dépendance risquée, qui décide si le merge est autorisé ? Souvent, personne, la PR est mergée avant même que la sécurité n'ait pu réagir.
C'est le problème que Kusari adresse : transformer vos métadonnées supply chain en décisions exploitables au moment où elles comptent, dans les pull requests, avant le merge.
Qu'est-ce que Kusari ?
Section intitulée « Qu'est-ce que Kusari ? »Kusari est l'éditeur d'une plateforme de sécurité de la supply chain logicielle, connu de la communauté pour avoir créé GUAC. Son produit destiné aux équipes de développement s'appelle Kusari Inspector : il analyse le diff de chaque pull request et rend un avis go/no-go avant le merge.
Concrètement, Inspector :
- Analyse le diff de la PR : secrets, code, dépendances, licences, configuration
- Compare les résultats à un fichier
kusari.yamlversionné avec le code - Commente la pull request, à la fois en synthèse et ligne par ligne
- Conserve les dérogations approuvées dans un registre d'espace de travail
Où Kusari se place dans la chaîne
Section intitulée « Où Kusari se place dans la chaîne »Inspector ne génère pas de SBOM et ne signe pas d'artefact : il intervient avant que l'artefact existe, sur le code proposé. Les briques du tableau ci-dessous ne sont donc pas des concurrentes mais des étapes différentes de la même chaîne. La colonne de droite est celle qui compte : c'est le livrable de chaque outil qui détermine où il se branche.
| Outil | Rôle | Ce qu'il produit |
|---|---|---|
| Syft | Génère un SBOM | Liste des composants |
| Cosign | Signe et atteste | Preuve cryptographique |
| Trivy/Grype | Scanne les vulnérabilités | Liste de CVE |
| GUAC | Corrèle et visualise | Graphe interrogeable |
| Kusari Inspector | Analyse le diff et se prononce | Avis go/no-go dans la PR |
Le problème que Kusari résout
Section intitulée « Le problème que Kusari résout »Le fossé entre production de métadonnées et action
Section intitulée « Le fossé entre production de métadonnées et action »La plupart des équipes qui investissent dans la supply chain security rencontrent le même blocage :
- Elles génèrent des SBOM à chaque build
- Elles signent leurs images avec Cosign
- Elles produisent des attestations SLSA
- Elles scannent les vulnérabilités en CI
- Mais rien n'empêche une pull request dangereuse d'être mergée
Toutes ces preuves portent sur un artefact déjà construit. Or le moment où une dépendance douteuse entre dans le projet, c'est la revue de code, avant qu'aucun build n'ait eu lieu. Les rapports s'accumulent en aval pendant que la décision se prend en amont, sans eux.
Les contrôles existants sont insuffisants
Section intitulée « Les contrôles existants sont insuffisants »Les protections de branche natives de GitHub savent exiger que les tests passent, qu'une revue soit approuvée et qu'il n'y ait pas de conflit. Ce sont des conditions sur le processus, pas sur le contenu du changement.
Elles ne savent pas répondre à :
- « Cette PR ajoute une dépendance dont le nom ressemble à un paquet populaire. »
- « Ce changement introduit une licence copyleft forte. »
- « Ce workflow référence une action par tag mobile. »
- « Cette chaîne ajoutée dans le code est un jeton d'API. »
Kusari Inspector comble ce fossé en analysant le contenu du diff et en publiant son verdict là où la discussion a lieu, sur la pull request.
Kusari Inspector : contrôles dans les pull requests
Section intitulée « Kusari Inspector : contrôles dans les pull requests »Kusari Inspector est le produit principal de Kusari. Il existe sous quatre formes qui partagent le même moteur et le même fichier de configuration : application GitHub, workflow GitHub Actions, template GitLab et client en ligne de commande. Le choix ne change pas les résultats, seulement la manière de déclencher l'analyse.
Ce que Kusari Inspector vérifie
Section intitulée « Ce que Kusari Inspector vérifie »Le tableau ci-dessous liste les familles de contrôles documentées par Kusari.
Chacune correspond à un interrupteur du fichier kusari.yaml que vous
committez à la racine du dépôt : vous pouvez désactiver une famille entière si
elle fait doublon avec un outil déjà en place. Retenez surtout la colonne de
droite : Inspector regarde le diff de la pull request, pas l'intégralité du
dépôt, ce qui explique pourquoi les premières exécutions sont rapides même sur
un gros monorepo.
| Catégorie | Contrôles effectués |
|---|---|
Secrets (secret_scan_enabled) | Identifiants, jetons et clés privées exposés dans le diff |
| Dépendances | Vulnérabilités connues avec sévérité et probabilité d'exploitation, typosquatting de noms de paquets, dépendances directes et transitives |
Licences (license_scan_enabled) | Licences des dépendances, classées par type de copyleft |
Code et configuration (code_scan_enabled, misconfig_scan_enabled, workflow_scan_enabled) | Analyse statique du code, workflows GitHub Actions, Dockerfile, Terraform, Helm |
Épinglage de version (container_version_pinning_check_enabled) | Images de conteneur et actions GitHub référencées par tag mobile plutôt que par version figée |
Fonctionnement dans une PR
Section intitulée « Fonctionnement dans une PR »Quand un développeur ouvre une pull request, Kusari Inspector :
-
Calcule le diff
Compare la branche de la PR à sa branche de base et isole les fichiers modifiés, dont les manifestes de dépendances (
package.json,go.mod,requirements.txt,Dockerfile). -
Analyse le diff
Passe les changements dans ses moteurs de détection : secrets, analyse statique, dépendances (vulnérabilités et typosquatting), licences, configuration.
-
Applique votre
kusari.yamlRetire du verdict les paquets listés dans
allowed_packages, ainsi que les familles de scanners que vous avez désactivées, puis les exceptions déjà approuvées sur l'espace de travail. -
Publie le verdict
Ajoute un commentaire de synthèse sur la PR, plus des commentaires posés directement sur les lignes de code concernées. Une nouvelle exécution remplace le commentaire précédent au lieu d'en empiler un de plus.
Ce que le commentaire contient
Section intitulée « Ce que le commentaire contient »Le commentaire de la PR n'est pas une liste brute de findings : il est trié par gravité et chaque entrée porte la remédiation attendue. Le réflexe de lecture est donc de partir du bas de la ligne, la recommandation, plutôt que de l'identifiant de vulnérabilité. L'extrait ci-dessous montre la forme du rapport, avec un exemple réel de dépendance JavaScript vulnérable.
### Kusari Inspector
Status: changes requested (3 findings)
- Dependency: lodash 4.17.20 -> CVE-2021-23337 (CVSS 7.2, High) Command injection via the template function. Fixed in 4.17.21. Recommendation: bump to 4.17.21 before merge.
- License: dependency added under AGPL-3.0 (strong copyleft) Recommendation: confirm compatibility with the distribution model.
- Workflow: .github/workflows/release.yml uses actions/checkout@v4 Recommendation: pin the action to a full commit SHA.Installation et configuration
Section intitulée « Installation et configuration »Prérequis
Section intitulée « Prérequis »- Un dépôt GitHub ou GitLab sur lequel vous pouvez installer une application, ou un accès administrateur au projet.
- Un compte Kusari : l'analyse tourne sur la plateforme Kusari, pas sur votre machine. Les projets CNCF et OpenSSF y ont accès gratuitement.
- Pour l'usage en ligne de commande : un couple
KUSARI_CLIENT_IDetKUSARI_CLIENT_SECRETstocké dans les secrets du dépôt.
Intégration GitHub App
Section intitulée « Intégration GitHub App »L'application GitHub est la voie la plus courte : elle commente les pull
requests sans qu'aucun workflow ne soit ajouté au dépôt. Le comportement se
règle ensuite par un fichier kusari.yaml committé à la racine, ce qui rend la
configuration revue en pull request comme le reste du code.
-
Installer l'application GitHub
Depuis la console Kusari, autorisez l'application sur l'organisation puis sélectionnez les dépôts concernés. L'accès gratuit se demande via le programme OpenSSF / CNCF pour les projets éligibles.
-
Générer le fichier de configuration
La commande ci-dessous écrit un
kusari.yamlaux valeurs par défaut dans le répertoire courant. Partir de ce fichier évite d'inventer des clés que le produit ne lit pas.Fenêtre de terminal kusari config generatecat kusari.yamlSortie obtenue avec la version 2.9.0 du client :
github_action_version_pinning_check_enabled: truecontainer_version_pinning_check_enabled: truepost_comment_on_failure: truepost_comment_on_success: falsesbom_generation_enabled: false -
Ajuster les scanners et les exemptions
Les interrupteurs de scanners valent
truepar défaut : vous ne les écrivez que pour en désactiver un.allowed_packagesattend des PURL (identifiants de paquet normalisés), avec ou sans version.# kusari.yaml, à la racine du dépôtsecret_scan_enabled: truecode_scan_enabled: truemisconfig_scan_enabled: false # déjà couvert par Checkov en CIworkflow_scan_enabled: truelicense_scan_enabled: true# Paquets exclus de l'analyse de dépendancesallowed_packages:- pkg:npm/lodash # toutes les versions de lodash- pkg:npm/express@4.18.0 # cette version précise uniquement# Épinglagegithub_action_version_pinning_check_enabled: truecontainer_version_pinning_check_enabled: true# Exceptions : false = un administrateur valide chaque propositionauto_approve_exceptions: false# Commentaires GitHubpost_comment_on_failure: truepost_comment_on_success: false -
Rendre le résultat bloquant
L'application publie un statut sur la pull request. Pour qu'il empêche réellement le merge, exigez-le dans les règles de protection de branche : Settings, Branches, Branch protection rules, Require status checks.
Utilisation en ligne de commande
Section intitulée « Utilisation en ligne de commande »Le client kusari sert à deux choses : rejouer une analyse en local avant
d'ouvrir la PR, et intégrer Inspector dans une CI qui n'est ni GitHub ni
GitLab. Aucun script d'installation n'est à exécuter à l'aveugle : le projet
publie des archives et un fichier de sommes qu'on vérifie avant d'extraire.
VERSION=2.9.0BASE="https://github.com/kusaridev/kusari-cli/releases/download/v${VERSION}"
# Archive + fichier de sommes publié par le projetcurl -sSfLO "${BASE}/kusari-cli_${VERSION}_linux_amd64.tar.gz"curl -sSfLO "${BASE}/kusari-cli_${VERSION}_checksums.txt"
# Refuser d'installer si l'empreinte ne correspond passha256sum --check --ignore-missing "kusari-cli_${VERSION}_checksums.txt"
tar -xzf "kusari-cli_${VERSION}_linux_amd64.tar.gz" kusarisudo install -o root -g root -m 0755 kusari /usr/local/bin/kusariLa vérification doit afficher kusari-cli_2.9.0_linux_amd64.tar.gz: OK. Tout
autre message signifie que l'archive est corrompue ou substituée : arrêtez-vous
là. Contrôlez ensuite la version installée, elle doit correspondre à celle que
vous avez téléchargée.
kusari --version# kusari version v2.9.0 (commit: ..., built at: ...)L'analyse compare le répertoire de travail à une révision Git de référence : les deux arguments sont positionnels et obligatoires. Le second peut être une branche, un tag ou un hash.
# S'authentifier (ouvre le navigateur, puis choix de l'espace de travail)kusari auth login
# Comparer le dépôt courant à la branche mainkusari repo scan . main
# Sortie SARIF, exploitable par l'onglet Security de GitHubkusari repo scan . main --output-format sarif > kusari.sarif
# Résultat complet plutôt que tronqué, et trace détaillée en cas de soucikusari repo scan . main --full-output --verboseIntégration avec vos outils existants
Section intitulée « Intégration avec vos outils existants »Dans un workflow GitHub Actions
Section intitulée « Dans un workflow GitHub Actions »Quand l'application GitHub ne convient pas, par exemple parce que vous voulez
maîtriser le déclencheur ou récupérer le SARIF en artefact, Kusari publie un
workflow réutilisable. Il ne s'appelle pas au niveau d'une étape mais au
niveau du job (jobs.<id>.uses), ce qui explique l'absence de runs-on
dans l'extrait. Épinglez-le par empreinte de commit : le tag mobile v1
peut être redéplacé sur un autre commit à tout moment.
name: Kusari Security Scan
on: pull_request: branches: [main]
permissions: {}
jobs: kusari-scan: uses: kusaridev/kusari-ci-templates/.github/workflows/kusari-scan-v1.yml@e43cf4ff8e08218bdb4a3cfa830316e5432d68c5 # v1.5.1 permissions: contents: read pull-requests: write secrets: KUSARI_CLIENT_ID: ${{ secrets.KUSARI_CLIENT_ID }} KUSARI_CLIENT_SECRET: ${{ secrets.KUSARI_CLIENT_SECRET }} with: fail_on_issues: true # false par défaut : le job passe même en cas de finding post_comment: trueLe point à retenir est fail_on_issues. Sa valeur par défaut est false :
sans ce réglage, le workflow réutilisable réussit toujours et vous n'avez qu'un
commentaire informatif, jamais un blocage. Passez-le à true seulement une fois
le bruit calibré, sinon vous entraînez l'équipe à contourner le contrôle.
Avec GUAC et vos SBOM
Section intitulée « Avec GUAC et vos SBOM »GUAC (Graph for Understanding Artifact Composition) est né chez Kusari : c'est le composant qui stocke et corrèle les métadonnées, là où Inspector travaille sur le diff d'une pull request. Les deux ne se configurent pas au même endroit. Pour alimenter la plateforme avec un SBOM produit par Syft, on utilise l'action d'ingestion, distincte du scan de PR.
- name: Générer le SBOM uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 with: format: spdx-json output-file: sbom.spdx.json
- name: Ingérer le SBOM dans la plateforme Kusari uses: kusaridev/kusari-ingest@f84027b8069ff1561403db4046c2319fcb0f6d52 # v4.8.0 with: file-path: ./sbom.spdx.json tenant-endpoint: ${{ vars.KUSARI_TENANT_ENDPOINT }} client-id: ${{ secrets.KUSARI_CLIENT_ID }} client-secret: ${{ secrets.KUSARI_CLIENT_SECRET }}tenant-endpoint est propre à votre organisation, de la forme
https://<identifiant-tenant>.api.us.kusari.cloud. Ne le codez pas en dur dans
le workflow : une variable de dépôt évite de repasser sur chaque fichier le jour
où le tenant change.
Positionnement face à Kyverno
Section intitulée « Positionnement face à Kyverno »Une question revient dès qu'un cluster Kubernetes entre dans l'équation : faut-il choisir entre Inspector et Kyverno ? Non, parce qu'ils n'agissent pas au même moment. Inspector se prononce avant le merge, sur du code que personne n'a encore construit ; Kyverno se prononce à l'admission, sur un manifeste qui demande à tourner. Une image peut très bien passer la revue de PR puis être refusée au déploiement parce que sa signature manque.
Kusari n'exporte pas ses règles vers Kyverno : les deux configurations se
maintiennent séparément. Le point de jonction pratique reste l'inventaire des
images autorisées, à garder cohérent entre le dépôt applicatif et les
ClusterPolicy du cluster.
Comparaison avec les alternatives
Section intitulée « Comparaison avec les alternatives »Ce tableau n'existe pas pour désigner un gagnant : les quatre outils répondent à des questions différentes. La ligne qui décide vraiment est la première, Focus principal. Si votre douleur est « je découvre les CVE trop tard », Dependabot suffit. Si c'est « personne ne relit la licence ni les workflows des PR », Inspector apporte quelque chose que les trois autres ne couvrent pas ensemble. Les lignes marquées d'un avertissement signalent une capacité indirecte, obtenue via un autre composant, pas une case à cocher.
| Critère | Kusari | GUAC | Dependabot | Snyk |
|---|---|---|---|---|
| Focus principal | Analyse du diff de PR, avis go/no-go | Visualisation graphe | Mises à jour de dépendances | Scan de vulnérabilités |
| Intégration PR | ✅ Native | ⚠️ Via intégration | ✅ Native | ✅ Native |
| Consomme SBOM | ⚠️ Via ingestion plateforme | ✅ | ❌ | ⚠️ Partiel |
| Consomme SLSA | ⚠️ Via ingestion plateforme | ✅ | ❌ | ❌ |
| Policies personnalisées | ⚠️ Interrupteurs et liste d'exemptions | ⚠️ Via requêtes | ❌ | ✅ Payant |
| Analyse licences | ✅ | ❌ | ❌ | ✅ |
| Analyse de configuration CI | ✅ Workflows, Dockerfile, Terraform, Helm | ❌ | ❌ | ✅ |
| Open source | ⚠️ Client open source, plateforme SaaS | ✅ | ✅ | ❌ |
Cas d'usage concrets
Section intitulée « Cas d'usage concrets »1. Intercepter un paquet typosquatté
Section intitulée « 1. Intercepter un paquet typosquatté »Problème : une pull request ajoute reqeusts au lieu de requests. Le nom
est plausible à la relecture humaine, le test passe parce que le paquet
malveillant expose la même interface.
Ce qui joue : la détection de typosquatting de l'analyse de dépendances, active par défaut. Aucune configuration n'est nécessaire, il faut seulement ne pas avoir désactivé le scanner.
Résultat : le commentaire de PR pointe la ligne du manifeste et signale la proximité avec un paquet légitime beaucoup plus téléchargé. C'est le cas où Inspector rend le service que ni Dependabot ni un scanner de CVE ne rendent : le paquet est nouveau, il n'a donc aucune vulnérabilité connue.
2. Rendre visible un changement de licence
Section intitulée « 2. Rendre visible un changement de licence »Problème : une dépendance transitive bascule vers l'AGPL-3.0, incompatible avec la distribution de votre produit. Personne ne relit les licences des dépendances indirectes.
Ce qui joue : le scanner de licences, qui classe les dépendances par type de copyleft.
license_scan_enabled: trueRésultat : le commentaire de PR nomme la dépendance et la catégorie de licence. La décision reste humaine : Inspector ne connaît pas votre modèle de distribution, il fournit le signal que personne n'allait chercher.
3. Faire respecter l'épinglage dans les workflows
Section intitulée « 3. Faire respecter l'épinglage dans les workflows »Problème : un contributeur ajoute uses: actions/checkout@v4. Le tag est
mobile, un compromis du dépôt de l'action donnerait à ce workflow un accès au
GITHUB_TOKEN du projet.
Ce qui joue : github_action_version_pinning_check_enabled et
container_version_pinning_check_enabled, tous deux à true par défaut.
github_action_version_pinning_check_enabled: truecontainer_version_pinning_check_enabled: trueRésultat : un commentaire est posé sur la ligne fautive, en demandant une empreinte de commit complète. Ce contrôle est le plus rentable des trois parce qu'il porte sur une règle objective, sans discussion possible et sans faux positif.
Bonnes pratiques
Section intitulée « Bonnes pratiques »Déploiement progressif
Section intitulée « Déploiement progressif »Le blocage se règle au niveau du déclencheur, pas dans kusari.yaml : le
fichier de configuration pilote les scanners, pas la sévérité. Ce qui décide de
l'échec, c'est fail_on_issues dans le workflow réutilisable, ou l'inscription
du statut dans les protections de branche. Les trois étapes ci-dessous
correspondent donc à trois réglages distincts, pas à trois valeurs d'une même
clé.
-
Observer sans bloquer
Laissez
fail_on_issues: falseet n'ajoutez pas le statut aux protections de branche. Comptez deux à quatre semaines pour mesurer le volume réel de findings sur vos PR habituelles. -
Réduire le bruit
Désactivez les scanners qui font doublon avec un outil déjà en place, et listez dans
allowed_packagesles paquets internes que l'analyse ne sait pas résoudre. Une équipe qui reçoit trois faux positifs par PR cesse de lire les commentaires. -
Rendre le contrôle bloquant
Passez
fail_on_issues: true, puis exigez le statut dans les protections de branche. À ce stade seulement, un finding empêche le merge.
Exceptions maîtrisées
Section intitulée « Exceptions maîtrisées »Une exception ne se déclare pas dans un fichier YAML : elle se demande depuis
la pull request, ce qui garde la justification à côté du contexte qui l'a
motivée. Un membre de l'équipe répond au commentaire d'Inspector avec
@kusari-inspector feedback suivi de son argumentaire ; Kusari classe la
réponse et crée une proposition en attente.
@kusari-inspector feedbackFaux positif : cette chaîne est un identifiant de test, pas un secret.Elle est générée à chaque exécution par le script de fixtures.La proposition apparaît ensuite dans l'onglet Exceptions de l'espace de
travail, où un administrateur doit l'approuver pour qu'elle prenne effet.
Gardez auto_approve_exceptions: false : avec true, les propositions
deviennent des exceptions actives sans relecture, et la personne qui écrit le
code devient celle qui accorde la dérogation.
Intégration avec la gouvernance
Section intitulée « Intégration avec la gouvernance »Le rapport d'Inspector n'est pas une preuve d'audit en soi : il vit sur une pull request qui sera fermée. Pour le CRA ou NIS2, ce qui est demandé est la trace durable des décisions, en particulier des dérogations. Deux points d'ancrage existent dans le produit.
- Le SARIF produit par
--output-format sarifs'archive en artefact de workflow, se relit hors ligne et s'ingère dans l'onglet Security de GitHub. - L'onglet Exceptions de l'espace de travail conserve qui a demandé une dérogation, sur quel motif, et qui l'a approuvée. C'est ce registre qu'un auditeur demandera, pas les commentaires de PR.
Revoyez ce registre à intervalle fixe. Une exception créée pour une migration « provisoire » survit à l'équipe qui l'a demandée si personne ne la relit.
Dépannage
Section intitulée « Dépannage »Problèmes courants
Section intitulée « Problèmes courants »Deux causes expliquent la majorité des tickets, et aucune n'est un défaut de
l'outil : les permissions du workflow appelant et l'état du checkout.
Le workflow réutilisable a besoin de pull-requests: write pour commenter, et
d'un historique Git complet pour calculer un diff. Lisez la colonne du milieu
avant de toucher à la configuration des scanners.
| Symptôme | Cause probable | Solution |
|---|---|---|
| Aucun commentaire sur la PR | Permission pull-requests: write absente du job appelant | Déclarer les permissions au niveau du job uses:, elles ne sont pas héritées |
| Le job échoue au calcul du diff | Checkout superficiel, la branche de base est absente | Le workflow réutilisable fait déjà fetch-depth: 0 ; en CLI, récupérer la révision de comparaison avant de lancer le scan |
| Branche rapportée incorrecte | HEAD détaché en CI | Passer --override-branch à kusari repo scan |
| Findings sur un paquet interne | Paquet non résolvable par l'analyse | Ajouter son PURL dans allowed_packages |
| Le job passe malgré des findings | fail_on_issues laissé à false | Le passer à true une fois le bruit calibré |
Journaux et diagnostic
Section intitulée « Journaux et diagnostic »Quand une exécution se comporte autrement qu'attendu, reproduisez-la en
local avant de modifier le workflow : le client accepte les mêmes arguments
que la CI, et la boucle de retour se compte en secondes au lieu d'un cycle de
pipeline. --verbose est un drapeau global, il se place avant ou après la
sous-commande sans changer de sens.
# Trace détaillée des appels à la plateformekusari repo scan . main --verbose
# Résultat complet plutôt que tronqué, archivé en SARIFkusari repo scan . main --full-output --output-format sarif > kusari.sarif
# Régénérer une configuration propre en écrasant l'existantekusari config generate --forceSi kusari repo scan échoue immédiatement sans produire de rapport, le
problème est presque toujours l'authentification : rejouez kusari auth login et vérifiez l'espace de travail sélectionné avant de suspecter le
scanner.
À retenir
Section intitulée « À retenir »-
Inspector analyse le diff de la pull request, il ne se contente pas de relire les rapports d'autres outils : secrets, code, dépendances, licences et configuration passent par ses propres moteurs
-
Le moment compte plus que la couverture, un finding posé avant le merge change le comportement de l'équipe, un rapport publié après ne le change pas
-
Un seul fichier de configuration,
kusari.yamlà la racine du dépôt, composé d'interrupteurs de scanners et d'une liste d'exemptions par PURL -
Rien ne bloque par défaut,
fail_on_issuesvautfalseet le statut doit être ajouté aux protections de branche pour empêcher un merge -
Les exceptions se demandent depuis la PR avec
@kusari-inspector feedback, puis un administrateur les approuve : gardezauto_approve_exceptions: false -
La preuve auditable est ailleurs que dans la PR, archivez le SARIF et revoyez périodiquement le registre des exceptions pour le CRA et NIS2