Repository navigation
Merge pull request #184 from mathiscapart/feat/unitlead-decisions #394
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| pull_request: | |
| # Annule les runs obsolètes d'une même branche/PR quand un nouveau push arrive. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| # GITHUB_TOKEN en lecture seule : aucun job ci-dessous ne pousse de commit, | |
| # de tag, ni n'écrit sur les Pull Requests. | |
| permissions: | |
| contents: read | |
| jobs: | |
| quality: | |
| name: Qualité (lint, typecheck, build) | |
| runs-on: ubuntu-latest | |
| env: | |
| # `prisma.config.ts` appelle env("DATABASE_URL") au chargement — nécessaire | |
| # y compris pour `prisma generate`, qui ne se connecte jamais réellement à | |
| # une base. `src/lib/auth.ts` plante volontairement (fail-fast) si | |
| # BETTER_AUTH_SECRET est absent. Aucune de ces deux valeurs n'est une vraie | |
| # base/un vrai secret : le build Next.js ne fait que du SSR à la demande | |
| # (aucune page ne requête la DB au moment du build), ces placeholders | |
| # suffisent et ne servent jamais à une authentification réelle. | |
| DATABASE_URL: "file:./ci-build.db" | |
| BETTER_AUTH_SECRET: "ci-build-placeholder-non-secret-0000000000000000" | |
| steps: | |
| - name: Récupération du code | |
| uses: actions/checkout@v7 | |
| - name: Installation de pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: 11.15.1 | |
| - name: Installation de Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: "24" | |
| cache: pnpm | |
| - name: Installation des dépendances | |
| run: pnpm install --frozen-lockfile | |
| - name: Génération du client Prisma | |
| run: pnpm db:generate | |
| # Garde-fou anti-régression P3018 : une migration non rejouable sur base | |
| # vierge (table/colonne déjà créée par une migration précédente, etc.) | |
| # passe inaperçue sur la prod baselinée (qui ne rejoue jamais l'historique | |
| # complet) mais fait tomber `migrate deploy` sur un déploiement neuf. | |
| # On rejoue donc tout l'historique sur une base SQLite jetable, puis on | |
| # vérifie qu'aucune dérive ne subsiste entre les migrations et | |
| # `schema.prisma` (une divergence indiquerait un schéma modifié sans | |
| # migration correspondante, ou une migration qui ne reconstruit pas | |
| # fidèlement le schéma). Placé juste après `prisma generate` : c'est une | |
| # vérification de la couche base de données, indépendante du lint/tsc/ | |
| # build applicatifs, et rapide à faire échouer en premier sur SQLite. | |
| - name: Migrations Prisma rejouables sur base vierge | |
| env: | |
| DATABASE_URL: "file:./ci-migrate-check.db" | |
| run: | | |
| pnpm prisma migrate deploy | |
| pnpm prisma migrate diff --from-migrations prisma/migrations --to-schema prisma/schema.prisma --exit-code | |
| - name: Lint (ESLint) | |
| run: pnpm lint | |
| - name: Vérification des types (tsc) | |
| run: pnpm typecheck | |
| # Avant le build : ce sont des tests unitaires de logique pure (aucune | |
| # dépendance au build Next.js), plus rapides à faire échouer que | |
| # d'attendre `pnpm build` pour un bug qu'un test aurait déjà signalé. | |
| - name: Tests unitaires (Vitest) | |
| run: pnpm test | |
| - name: Build (Next.js) | |
| run: pnpm build | |
| security: | |
| name: Sécurité (secrets, dépendances, SAST) | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Historique complet : gitleaks scanne les commits, pas juste l'arbre courant. | |
| - name: Récupération du code | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| # Détection de secrets commités. On invoque le binaire gitleaks (OSS, | |
| # MIT) directement via son image Docker officielle plutôt que via | |
| # l'action `gitleaks/gitleaks-action`, qui exige une licence payante dès | |
| # qu'elle tourne sur un dépôt privé — ce repo l'est probablement. | |
| # `detect` (sans `--no-git`) parcourt l'historique des commits suivis | |
| # par git, ce qui exclut naturellement node_modules/.pnpm-store. | |
| - name: Scan de secrets (gitleaks) | |
| uses: docker://zricethezav/gitleaks:v8.30.1 | |
| with: | |
| args: detect --source=. --redact -v | |
| - name: Installation de pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: 11.15.1 | |
| - name: Installation de Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: "24" | |
| cache: pnpm | |
| - name: Installation des dépendances | |
| run: pnpm install --frozen-lockfile | |
| # Politique : bloquant uniquement sur "critical". Au moment d'écrire ce | |
| # workflow, un `pnpm audit` complet remonte 18 vulnérabilités (2 low / | |
| # 11 moderate / 5 high), toutes dans des dépendances transitives d'outils | |
| # de build (chaîne ESLint, `@prisma/dev` embarqué par `prisma`) sans | |
| # correctif amont disponible aujourd'hui et sans exposition en | |
| # production (dev/build only). Faire échouer la CI dessus serait rouge | |
| # en permanence pour un risque non actionnable — contre-productif. | |
| - name: "Audit des dépendances — bloquant (critical)" | |
| run: pnpm audit --audit-level=critical | |
| # Rapport informatif, non bloquant : rend visibles les vulnérabilités | |
| # moderate/high dans les logs sans casser la CI. À remonter en bloquant | |
| # dès qu'un correctif amont existe pour les entrées actuelles. | |
| - name: "Audit des dépendances — rapport (moderate+), non bloquant" | |
| run: pnpm audit --audit-level=moderate | |
| continue-on-error: true | |
| # SAST sur le code TS/TSX applicatif. `semgrep-action` (le wrapper | |
| # GitHub Marketplace) est archivé/déprécié depuis 2024 ; on invoque donc | |
| # directement l'image Docker officielle et maintenue `semgrep/semgrep`. | |
| # L'image `semgrep/semgrep` ne définit pas d'entrypoint (contrairement à | |
| # celle de gitleaks) : `args` est donc pris comme commande complète et | |
| # doit commencer par le binaire `semgrep`, sans quoi Docker cherche un | |
| # exécutable nommé `scan`. | |
| # Rulesets publics (`p/security-audit`, `p/typescript`, `p/react`), | |
| # `--metrics=off` : aucun compte, aucun token Semgrep App requis. | |
| # Scan de référence à la rédaction de ce workflow : 0 finding sur les | |
| # 394 fichiers suivis par git — bloquant dès le départ. | |
| - name: SAST (semgrep) | |
| uses: docker://semgrep/semgrep:1.170.0 | |
| with: | |
| args: >- | |
| semgrep scan --config=p/security-audit --config=p/typescript --config=p/react | |
| --metrics=off --error --exclude=node_modules --exclude=.next |