Leçon 6 / 6
Leçon 06 · GitHub Actions

Bonnes pratiques

Mettre en cache les dépendances

Chaque fois qu'un workflow tourne, GitHub Actions télécharge tes dépendances depuis internet. Avec le cache, ces téléchargements sont évités si les fichiers de lock n'ont pas changé. Résultat : des workflows deux à cinq fois plus rapides.

L'action actions/cache sauvegarde un dossier entre les exécutions. La clé de cache inclut un hash du fichier de lock — elle se régénère automatiquement quand les dépendances changent.

.github/workflows/ci.yml — cache npm
- name: Cache node_modules
  uses: actions/cache@v4
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

- name: Installer les dépendances
  run: npm ci
Cache pip (Python) et Composer (PHP)
# Python — cache pip
- name: Cache pip
  uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}

# PHP — cache Composer
- name: Cache Composer
  uses: actions/cache@v4
  with:
    path: vendor
    key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}

Pour Node.js, l'action actions/setup-node intègre directement le cache via l'option cache: 'npm' — pas besoin d'ajouter actions/cache séparément. C'est la méthode recommandée pour les projets Node.

Les matrices de tests

La stratégie matrix permet de lancer le même job en parallèle sur plusieurs configurations : plusieurs versions de Node, plusieurs OS, plusieurs navigateurs. Tu multiplies la couverture sans dupliquer le code du workflow.

strategy.matrix — plusieurs versions Node et OS
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
      fail-fast: false   # continuer même si une combinaison échoue

    steps:
      - uses: actions/checkout@v4
      - name: Setup Node ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      - run: npm test

Avec cet exemple, GitHub Actions lance 6 jobs en parallèle (3 versions × 2 OS). Si une combinaison échoue, fail-fast: false laisse les autres se terminer — utile pour voir exactement sur quelles configurations les tests cassent.

💡

Tu peux aussi exclure certaines combinaisons avec exclude: ou en ajouter des spécifiques avec include:. Pratique pour éviter de tester des combinaisons qui n'ont pas de sens (ex. une version Windows uniquement pour Node 20).

Réutiliser des workflows

Quand plusieurs dépôts partagent la même logique CI (tests, lint, déploiement), copier-coller le YAML partout devient un cauchemar à maintenir. GitHub Actions propose deux solutions : les workflows réutilisables (workflow_call) et les actions composites.

Workflow réutilisable — .github/workflows/reusable-test.yml
on:
  workflow_call:         # ce workflow peut être appelé par d'autres
    inputs:
      node-version:
        required: false
        type: string
        default: '20'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: 'npm'
      - run: npm ci && npm test
Appel du workflow réutilisable depuis un autre repo
jobs:
  run-tests:
    uses: mon-org/shared-workflows/.github/workflows/reusable-test.yml@main
    with:
      node-version: '22'

Timeouts pour éviter les workflows bloqués

Un test qui attend indéfiniment, une connexion réseau qui ne répond pas, une tâche bloquée sur une entrée interactive — sans timeout, le job tourne jusqu'à la limite GitHub (6 heures) et consomme inutilement des minutes de CI.

Définis timeout-minutes au niveau du job ou d'un step individuel. Choisir une valeur raisonnable selon la durée habituelle du job.

timeout-minutes — job et step
jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15   # timeout pour tout le job

    steps:
      - name: Tests e2e
        run: npm run test:e2e
        timeout-minutes: 10   # timeout pour ce step uniquement
⚠️

Sans timeout-minutes, un job peut tourner jusqu'à 6 heures par défaut sur GitHub. Cela consomme ton quota de minutes CI gratuites et bloque les autres workflows en attente. Mets toujours un timeout adapté, même conservateur.

Permissions minimales

Par défaut, le token GITHUB_TOKEN a des permissions en écriture sur le dépôt. Si un job est compromis (dépendance malveillante, injection de commande), l'attaquant peut modifier le code, créer des releases, etc.

La bonne pratique : déclarer des permissions explicites au niveau du workflow ou du job, en accordant uniquement ce qui est nécessaire.

permissions minimales par job
# Permissions globales restrictives pour tout le workflow
permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    # Ce job hérite de "contents: read" — suffisant pour les tests
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test

  deploy:
    runs-on: ubuntu-latest
    # Ce job a besoin d'écrire des packages
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - run: docker push ghcr.io/mon-org/mon-app:latest

Pinning des actions à un SHA

Quand tu écris uses: actions/checkout@v4, tu utilises un tag Git mutable. Si le mainteneur de l'action pousse du code malveillant sur ce tag (attaque supply chain), ton workflow exécuterait ce code sans que tu le voies.

La solution : épingler l'action à son hash de commit SHA, qui est immuable. Un tag peut bouger, un SHA ne change jamais.

Pinning SHA vs tag — comparaison
# Moins sûr — le tag v4 peut pointer vers un nouveau commit demain
- uses: actions/checkout@v4

# Plus sûr — SHA immuable + commentaire pour savoir quelle version
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af  # v4.1.0
💡

Le pinning SHA est surtout important pour les dépôts publics ou les pipelines de production critiques. Pour des projets personnels ou d'apprentissage, @v4 est acceptable. Des outils comme Dependabot ou Renovate peuvent automatiser la mise à jour des SHA pinned.

Récapitulatif du module

En six leçons, tu as parcouru l'essentiel de GitHub Actions :

  • Leçon 01 — Comprendre les concepts : workflow, job, step, runner, déclencheurs.
  • Leçon 02 — Écrire ton premier workflow CI : linter, tests automatiques à chaque push.
  • Leçon 03 — Utiliser les secrets et variables d'environnement de façon sécurisée.
  • Leçon 04 — Construire et publier des images Docker sur le GitHub Container Registry.
  • Leçon 05 — Déployer automatiquement sur un serveur via SSH ou un service cloud.
  • Leçon 06 — Optimiser et sécuriser : cache, matrices, réutilisation, timeouts, permissions, pinning.

Prochaines étapes

GitHub Actions est souvent le point d'entrée vers des pratiques DevOps plus avancées. Voici ce que tu peux explorer ensuite :

  • Ansible — automatiser la configuration de tes serveurs (installation de paquets, gestion des fichiers de config, déploiements répétables).
  • Terraform — provisionner ton infrastructure cloud (VMs, bases de données, réseaux) sous forme de code versionné.
  • Kubernetes — orchestrer des conteneurs Docker à grande échelle, avec gestion automatique de la disponibilité.
  • OpenID Connect (OIDC) — s'authentifier auprès des fournisseurs cloud (AWS, GCP, Azure) sans stocker de clé secrète dans les secrets GitHub.
// À retenir
  • Cache les dépendances avec actions/cache ou l'option cache: de setup-node — gain de temps significatif.
  • strategy.matrix lance le même job sur plusieurs configurations en parallèle sans dupliquer le YAML.
  • workflow_call permet de centraliser la logique CI dans un workflow réutilisable appelé par d'autres dépôts.
  • Définis toujours un timeout-minutes pour éviter les jobs bloqués qui consomment ton quota.
  • Déclare des permissions: minimales par job — le principe du moindre privilège.
  • Épingle les actions à un SHA immuable plutôt qu'à un tag mutable pour sécuriser ta supply chain.