← API et intégrations

Agent CI lysbor-scan

Un script shell qui enchaîne des scanners open source reconnus et envoie leurs résultats à Lysbor. Il est distribué par cette instance : aucun accès à un dépôt de code n'est nécessaire.

Ce qu'il fait

ÉtapeOutilCe qu'il trouveOnglet Lysbor
SBOM (toujours, sauf --no-sbom)Syft (Apache 2.0)Inventaire CycloneDX de toutes les dépendances (npm, PyPI, Go, Maven, Cargo, NuGet, RubyGems, Composer, paquets Debian/Alpine des images), confronté à OSV par LysborVulnérabilités
--sastSemgrep (LGPL 2.1)Failles dans votre code : injections, désérialisation, crypto faible, secrets codés en durCode et configuration
--trivyTrivy (Apache 2.0)Dockerfile, Kubernetes, Terraform, CloudFormation mal configurés. Secrets commis (clés AWS, jetons, clés privées)Code et configuration
--sarif FICHIERtout outil produisant du SARIF 2.1ZAP, gitleaks, Checkov, tfsec, CodeQL, Bandit, ESLint securityCode et configuration

Les scanners produisent les rapports. Lysbor les centralise, compare chaque envoi au précédent, n'alerte que sur ce qui est nouveau, conserve vos décisions (faux positif, risque accepté) d'un envoi à l'autre et produit le rapport attendu par un auditeur. Une seule intégration dans le pipeline, pas de tableau de bord supplémentaire à surveiller.

Prérequis : un projet (son identifiant est dans l'onglet « Intégration CI ») et une clé API (Paramètres › Clés API) avec les portées lecture et envoi, valeurs par défaut. Avec --fail-on critical|high|medium|low, le script sort avec le code 2 dès qu'un envoi laisse des résultats ouverts au niveau demandé. Les résultats ignorés dans Lysbor ne comptent pas, une décision prise dans l'interface débloque le pipeline sans toucher au code.

1. Script

curl -sSfL -o /usr/local/bin/lysbor-scan https://lysbor.com/agent/lysbor-scan.sh && chmod +x /usr/local/bin/lysbor-scan
lysbor-scan install-tools              # Syft et Trivy depuis leurs archives publiées, empreinte SHA-256 vérifiée (ou : install-tools syft)
pip install semgrep                   # facultatif (--sast)

export LYSBOR_URL=https://lysbor.com LYSBOR_API_KEY=lys_... LYSBOR_PROJECT=<uuid>
lysbor-scan .                          # SBOM du dépôt courant
lysbor-scan --all .                    # SBOM + Semgrep + Trivy
lysbor-scan --trivy registry/app:1.2.3 # image de conteneur : SBOM + configuration/secrets de l'image
lysbor-scan package-lock.json          # un lockfile, envoyé tel quel
lysbor-scan --sarif zap.sarif --no-sbom .   # seulement un rapport ZAP
lysbor-scan --fail-on high --all .     # bloque le pipeline à partir de « élevée »
SYFT_ARGS="--exclude './**/test/**'" SEMGREP_CONFIG=p/security-audit TRIVY_ARGS="--severity HIGH,CRITICAL" lysbor-scan --all .

Variables : LYSBOR_URL, LYSBOR_API_KEY, LYSBOR_PROJECT, LYSBOR_FAIL_ON, LYSBOR_INCLUDE_DEV, SYFT_ARGS, SEMGREP_CONFIG, TRIVY_ARGS. Les dépendances de développement npm, yarn et pnpm sont incluses par défaut (--no-dev pour les écarter). Semgrep n'envoie aucune métrique.

2. GitHub Actions

name: Lysbor
on: [push]
jobs:
  lysbor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Installer l'agent Lysbor et les scanners
        run: |
          curl -sSfL -o /usr/local/bin/lysbor-scan https://lysbor.com/agent/lysbor-scan.sh && chmod +x /usr/local/bin/lysbor-scan
          lysbor-scan install-tools
          pipx install semgrep
      - name: Scanner et envoyer à Lysbor
        env:
          LYSBOR_URL: https://lysbor.com
          LYSBOR_API_KEY: ${{ secrets.LYSBOR_API_KEY }}   # Settings > Secrets and variables > Actions
          LYSBOR_PROJECT: ${{ vars.LYSBOR_PROJECT }}
        run: lysbor-scan --all --fail-on high .        # ou : lysbor-scan registry/app:${{ github.sha }}

3. GitLab CI

include:
  - remote: 'https://lysbor.com/agent/lysbor-gitlab-ci.yml'
variables:
  LYSBOR_URL: https://lysbor.com
  LYSBOR_PROJECT: <uuid>
  LYSBOR_OPTS: --all      # vide pour le SBOM seul
  LYSBOR_FAIL_ON: high
# LYSBOR_API_KEY : Settings > CI/CD > Variables, masquée

4. Image Docker

curl -sSfLO https://lysbor.com/agent/lysbor-scan.Dockerfile && curl -sSfLO https://lysbor.com/agent/lysbor-scan.sh
docker build -t lysbor-scan -f lysbor-scan.Dockerfile .                 # python:3.11-slim + Syft 1.20 + Trivy 0.70 + Semgrep 1.177. Publiez-la sur votre registre
docker run --rm -v "$PWD:/src" -e LYSBOR_URL -e LYSBOR_API_KEY -e LYSBOR_PROJECT lysbor-scan --all /src
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -e LYSBOR_URL -e LYSBOR_API_KEY -e LYSBOR_PROJECT lysbor-scan --trivy registry/app:1.2.3

5. Sans l'agent

semgrep scan --config p/default --sarif -o semgrep.sarif .
curl -sS -f -X POST "https://lysbor.com/api/v1/projects/<uuid>/sarif" -H "Authorization: Bearer $LYSBOR_API_KEY" -F "file=@semgrep.sarif"

6. Garde de pull request

Avant fusion, l'agent compare le lockfile de la branche à celui de la branche cible et vérifie uniquement les paquets ajoutés ou montés de version : paquet malveillant (flux OSV), interdit par votre organisation, vulnérabilité connue avec sa version corrigée, version trop récente. Rien n'est téléchargé par Lysbor : il voit des noms et des versions, comme dans un inventaire. Une clé API avec la seule portée lecture suffit.

# GitHub Actions : à ajouter dans un workflow déclenché sur pull_request (permissions: pull-requests: write pour le commentaire)
      - name: Lockfile de la branche cible
        run: git fetch --depth=1 origin ${{ github.base_ref }} && (git show origin/${{ github.base_ref }}:package-lock.json > /tmp/base.lock || true)
      - name: Garde Lysbor
        env:
          LYSBOR_URL: https://lysbor.com
          LYSBOR_API_KEY: ${{ secrets.LYSBOR_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: lysbor-scan gate --base /tmp/base.lock --comment package-lock.json

# GitLab CI : avec GITLAB_TOKEN (jeton de projet, portée api) pour la note sur la merge request
lysbor-scan gate --base <(git show origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME:package-lock.json) --comment package-lock.json

# En local, avant de pousser (crochet pre-commit ou à la main)
lysbor-scan gate --base <(git show HEAD:package-lock.json) package-lock.json

# Codes de sortie : 0 rien à signaler. 2 paquet refusé. 3 avertissement avec --strict. 4 Lysbor injoignable (0 avec --soft)

Questions des développeurs

Pourquoi ma pull request est refusée ?
Un paquet ajouté ou monté de version est soit connu comme malveillant (flux OSV, la raison cite l'identifiant MAL-…), soit interdit par votre organisation (la raison est écrite par elle), soit porteur d'une vulnérabilité au niveau que votre organisation a choisi de bloquer. Le commentaire de la PR nomme le paquet, la version et, quand elle existe, la version corrigée.
Un avertissement bloque-t-il la fusion ?
Non, sauf si le job est lancé avec --strict. Un avertissement signale une vulnérabilité sous le seuil de blocage ou une version publiée depuis moins de N jours (7 par défaut).
Comment obtenir une exception ?
Elle se décide dans Lysbor, pas dans la PR : un propriétaire ou un administrateur de votre organisation ajuste la politique (Paramètres › Politique de paquets) ou lève une interdiction. La décision est tracée dans le journal d'activité et s'applique à la prochaine exécution de la garde.
Que se passe-t-il si Lysbor ne répond pas ?
La garde affiche « NON VÉRIFIÉ » et sort en code 4 : le statut est rouge, jamais vert par défaut. Avec --soft, elle laisse passer en le disant. À votre équipe de choisir le réglage.
Quels fichiers sont lus ?
Les mêmes que pour l'import : package-lock.json, pnpm-lock.yaml, yarn.lock, requirements.txt épinglé, poetry.lock, uv.lock, Pipfile.lock, go.sum, Cargo.lock, composer.lock, Gemfile.lock, packages.lock.json, ainsi qu'un SBOM CycloneDX ou SPDX. Le fichier de base et celui de la branche doivent être du même format.
Mes paquets privés sortent-ils de chez moi ?
La garde envoie des noms et des versions de paquets, rien d'autre : ni code, ni fichier, ni jeton. Un paquet privé inconnu des bases publiques ressort simplement « sans remarque ».
Pourquoi un paquet que j'ai depuis longtemps n'est-il pas signalé ?
La garde ne regarde que ce que la PR change. L'existant est couvert par l'inventaire du projet et ses vérifications planifiées, qui alertent quand une vulnérabilité apparaît sur un paquet déjà en place.
Pourquoi une version « trop récente » est-elle signalée ?
La plupart des versions compromises publiées ces dernières années ont été retirées en moins d'une semaine. Attendre quelques jours avant d'adopter une version neuve élimine l'essentiel de ce risque. Le délai est réglé par votre organisation. 0 le désactive.
La garde remplace-t-elle npm audit ou pip-audit ?
Elle les complète : mêmes sources publiques, plus les paquets malveillants, les interdictions propres à votre organisation, la règle d'âge et une décision commune tracée. Et elle ne s'arrête pas à un écosystème.
Faut-il un proxy de paquets ?
Non. La garde agit à l'entrée du dépôt, sans se placer sur le chemin des téléchargements. Si votre entreprise possède déjà un Nexus, un Artifactory ou un Verdaccio, il peut consommer la liste de blocage de Lysbor (GET /api/v1/policy/blocklist.json, format documenté) pour refuser les mêmes paquets au téléchargement.

Correspondance des sévérités

Chaque résultat SARIF est normalisé en critique / élevée / moyenne / faible : d'abord security-severity (score 0 à 10 : 9 et plus critique, 7 élevée, 4 moyenne, sinon faible), sinon un tag ou une propriété severity explicite, sinon le niveau SARIF (error élevée, warning moyenne, note faible). Les résultats marqués pass ou supprimés dans l'outil ne sont pas importés. Chaque rapport remplace le précédent du même outil. Les nouveautés sont détectées par empreinte stable (outil, règle, fichier, extrait), une décision « ignorer » survit aux envois suivants. Limites : 5 000 résultats par rapport, 25 Mo par fichier.

Vérification du script : voir la page d'état pour la version en service. Le script affiche son aide avec lysbor-scan --help.