Premier pipeline de sécurité avec GitHub Actions ou GitLab CI¶
Objectifs pédagogiques¶
À la fin de ce TP, vous devez être capables de :
- expliquer ce qu'est un pipeline et quand il se déclenche
- ajouter pas à pas trois contrôles de sécurité automatiques : secrets, code et dépendances
- générer l'inventaire des composants du projet (SBOM)
- lire les rapports produits et comprendre pourquoi le pipeline échoue
- prouver que le pipeline bloque l'ajout d'un secret
Prérequis¶
- Un compte GitHub ou GitLab.com : choisissez l'onglet correspondant dans chaque étape, les deux chemins sont équivalents
- Git installé sur votre poste
- Aucune installation d'outil de sécurité : tout tourne dans le pipeline
Testé
Les trois analyses ont été jouées sur le dépôt SecurePay avec les versions de ce TP. Gitleaks trouve 2 clés d'API, Semgrep signale l'eval(), et Trivy relève 16 vulnérabilités de niveau HIGH dans les dépendances : les trois jobs échouent, comme attendu. Le workflow GitHub Actions a aussi été vérifié avec actionlint.
Contexte¶
Vous partez du dépôt securepay-api, une API de paiement écrite sans précaution. Plutôt que de chercher les failles à la main à chaque modification, vous allez demander à la forge de le faire automatiquement, à chaque push.
flowchart LR
P["git push"] --> S["Secrets\nGitleaks"]
P --> C["Code\nSemgrep"]
P --> D["Dépendances et SBOM\nTrivy"]
S --> R{"Tout est vert ?"}
C --> R
D --> R
R -->|"oui"| OK["Modification acceptée"]
R -->|"non"| KO["Pipeline en échec :\nlire le rapport, corriger"] Atelier 1 : Récupérer le projet¶
Travail demandé¶
- Sur la page du dépôt securepay-api, cliquez sur Fork pour en créer une copie sur votre compte.
-
Clonez votre copie :
Critère de réussite¶
Le projet est sur votre forge et sur votre poste.
Atelier 2 : Un premier job, la détection de secrets¶
Un pipeline est une suite de jobs que la forge exécute automatiquement. Chaque job démarre une machine propre, récupère votre code et lance des commandes. Si une commande échoue, le job échoue.
Travail demandé¶
- Créez le fichier du pipeline avec un seul job : Gitleaks analyse tout l'historique Git à la recherche de clés, de jetons et de mots de passe.
Fichier .github/workflows/securite.yml :
name: securite
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
secrets:
name: Secrets (Gitleaks)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # tout l'historique, pas seulement le dernier commit
- name: Gitleaks sur tout l'historique
run: |
docker run --rm -v "$PWD:/repo" ghcr.io/gitleaks/gitleaks:v8.30.1 \
git /repo --report-format json --report-path /repo/gitleaks.json
- uses: actions/upload-artifact@v7
if: always() # garder le rapport même en cas d'échec
with:
name: rapport-gitleaks
path: gitleaks.json
Fichier .gitlab-ci.yml :
stages: [securite]
variables:
GIT_DEPTH: "0" # tout l'historique, pas seulement le dernier commit
secrets:gitleaks:
stage: securite
image:
name: ghcr.io/gitleaks/gitleaks:v8.30.1
entrypoint: [""]
script:
- gitleaks git --report-format json --report-path gitleaks.json .
artifacts:
when: always # garder le rapport même en cas d'échec
paths: [gitleaks.json]
-
Poussez le fichier, puis ouvrez l'onglet Actions (GitHub) ou Build → Pipelines (GitLab).
-
Le job échoue : téléchargez le rapport et repérez les secrets trouvés, avec leur fichier et leur commit.
Ce que vous devez observer¶
- Gitleaks trouve deux clés Stripe, dans
src/routes/payments.jset dans.env.example - Le job est rouge : c'est le comportement voulu, le pipeline vous a protégé
Un secret trouvé est un secret compromis
Supprimer la ligne ne suffit pas : la clé reste dans l'historique Git. Dans la réalité, il faut d'abord révoquer la clé chez le fournisseur, puis la remplacer. Ici, les clés sont factices.
Critère de réussite¶
Le pipeline se déclenche seul à chaque push, et vous savez lire le rapport de Gitleaks.
Atelier 3 : Analyser le code¶
L'analyse statique (SAST) lit le code sans l'exécuter et repère les constructions dangereuses.
Travail demandé¶
- Ajoutez un deuxième job, Semgrep, avec les règles de sécurité pour JavaScript :
À ajouter sous jobs: :
sast:
name: Code (Semgrep)
runs-on: ubuntu-latest
container:
image: semgrep/semgrep:1.183.0
steps:
- uses: actions/checkout@v7
- name: Analyse statique
run: semgrep scan --config p/javascript --metrics=off --error --json --output semgrep.json
- uses: actions/upload-artifact@v7
if: always()
with:
name: rapport-semgrep
path: semgrep.json
- Poussez, puis lisez le rapport : quelle ligne est signalée, et pourquoi est-elle dangereuse ?
Ce que vous devez observer¶
- Semgrep signale
src/routes/payments.js, à la ligne qui appelleeval()sur une formule envoyée par l'utilisateur : n'importe qui pourrait faire exécuter du code au serveur - L'option
--errorfait échouer le job dès qu'une faille est trouvée
Critère de réussite¶
Les deux jobs tournent en parallèle, et vous savez expliquer la faille signalée par Semgrep.
Atelier 4 : Les dépendances et le SBOM¶
Votre application utilise des bibliothèques écrites par d'autres, qui en utilisent elles-mêmes d'autres. Une faille dans l'une d'elles est une faille de votre application.
Travail demandé¶
- Ajoutez un troisième job, Trivy. Il génère d'abord le SBOM (l'inventaire des composants), puis cherche les vulnérabilités connues de niveau HIGH et CRITICAL :
dependances:
name: Dépendances et SBOM (Trivy)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: SBOM CycloneDX
run: docker run --rm -v "$PWD:/src" aquasec/trivy:0.76.0 fs -q --format cyclonedx --output /src/sbom.cdx.json /src
- name: Vulnérabilités HIGH et CRITICAL
run: docker run --rm -v "$PWD:/src" aquasec/trivy:0.76.0 fs -q --scanners vuln --severity HIGH,CRITICAL --exit-code 1 /src
- uses: actions/upload-artifact@v7
if: always()
with:
name: sbom
path: sbom.cdx.json
-
Lisez le journal du job : quelles bibliothèques sont vulnérables ? Lesquelles n'apparaissent pas dans
package.json? -
Ouvrez
sbom.cdx.json: combien de composants contient le projet ?
Ce que vous devez observer¶
- Trivy relève des vulnérabilités HIGH dans
axios,jsonwebtokenetlodash, mais aussi dansfollow-redirectsetbody-parser, qui ne sont pas danspackage.json: ce sont des dépendances indirectes - Le SBOM recense environ 85 composants, alors que
package.jsonn'en déclare qu'une poignée
Pourquoi HIGH et pas seulement CRITICAL ?
Sur ce projet, Trivy ne trouve aucune vulnérabilité CRITICAL : un seuil limité à CRITICAL laisserait passer 16 vulnérabilités HIGH. Le seuil se choisit en regardant ce qu'il bloque réellement.
Versions épinglées
Toutes les images et les actions portent une version précise, jamais latest. En mars 2026, l'image Trivy publiée sous les tags latest et 0.69.4 a été remplacée par une version compromise : un pipeline qui épingle une version vérifiée n'aurait pas été touché. Pour aller plus loin, épinglez les actions GitHub par l'empreinte de leur commit.
Critère de réussite¶
Le pipeline compte trois contrôles et conserve le SBOM du projet à chaque exécution.
Atelier 5 : Prouver que le pipeline protège¶
Travail demandé¶
- Créez une branche, ajoutez un faux jeton dans un fichier, et ouvrez une Pull Request (GitHub) ou une Merge Request (GitLab) :
git switch -c test-secret
echo 'GITHUB_TOKEN=ghp_FauxJetonDeTest0123456789abcdefABCD' > config.txt
git add config.txt
git commit -m "test : ajout volontaire d'un faux secret"
git push -u origin test-secret
-
Observez le job de secrets sur la PR ou la MR, puis retrouvez le faux jeton dans le rapport.
-
Empêchez la fusion tant que le pipeline n'est pas vert :
Settings → Branches (ou Rules → Rulesets) : protégez main et exigez la réussite des jobs du workflow securite avant toute fusion.
Settings → Merge requests : activez Pipelines must succeed. Dans Settings → Repository → Protected branches, interdisez le push direct sur main.
- Supprimez la branche de test.
Critère de réussite¶
Une modification qui introduit un secret ne peut pas être fusionnée.
Pour aller plus loin¶
- Corrigez les failles une par une jusqu'à obtenir un pipeline vert : supprimer
eval(), retirer les clés du code et les passer en variables masquées, mettre à jour les dépendances - Analysez l'image Docker du projet avec
trivy image, comme dans le TP Trivy - Approfondissez chaque outil : TP Gitleaks, TP SonarQube, TP Renovate
Questions de synthèse¶
- Pourquoi analyser tout l'historique Git, et pas seulement la dernière version ?
- Quelle différence entre l'analyse du code (Semgrep) et celle des dépendances (Trivy) ?
- Qu'est-ce qu'une dépendance indirecte, et pourquoi est-elle dangereuse ?
- À quoi sert le SBOM, une fois le pipeline terminé ?
- Pourquoi épingler la version des outils plutôt qu'utiliser
latest?