> ## Documentation Index
> Fetch the complete documentation index at: https://api-documentation.kare-app.fr/llms.txt
> Use this file to discover all available pages before exploring further.

# CI sur les PR

> Les gates d'une pull request, et le seul check qui bloque le merge

## Un seul check bloquant

<Warning>
  **`CI Status`** — le job agrégateur de `ci.yml` — est le **seul contexte requis** par la protection
  de branche `main`. Tous les autres workflows rendent la PR rouge sans empêcher le merge : un bouton
  vert ne veut donc **pas** dire « tout est passé ».
</Warning>

Pourquoi : chaque workflow annexe est filtré par `paths` au niveau du trigger, donc il ne démarre
pas du tout sur une PR hors de son périmètre. Un contexte requis qui ne démarre jamais laisse la PR
en attente indéfiniment. Rendre l'un d'eux bloquant impose de descendre son filtre du trigger vers
une condition de job, pour que le workflow démarre toujours et qu'un job de gate rende le verdict.

## Les workflows

| Workflow                | Déclencheur                                                 | Contenu                                                                                                                                                         |
| ----------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ci`                    | PR, push `main`, merge queue                                | `Checks` (lint, typecheck, tests hors API, `lingui:check --strict` sur les 4 fronts) → `Build` (`turbo build --affected`) → `E2E (kare)` (opt-in) → `CI Status` |
| `ci-api-integration`    | PR touchant l'API                                           | Postgres + Redis éphémères, migrations, suite unit + intégration de `apps/api`                                                                                  |
| `ci-docker`             | PR touchant un `Dockerfile`, `.dockerignore` ou le lockfile | build de l'image de chaque app modifiée, **sans push**                                                                                                          |
| `ci-infra`              | PR touchant `infrastructure/`                               | `tofu fmt -check` + `tofu validate` (sans backend, sans credentials)                                                                                            |
| `pr-openapi`            | PR touchant l'API                                           | régénère les specs et **échoue si `openapi/` n'est pas à jour**                                                                                                 |
| `pr-quality`            | toute PR                                                    | titre au format conventional commit                                                                                                                             |
| `auto-assign` / `stale` | PR / planifié                                               | hygiène du repo                                                                                                                                                 |

<Note>
  `pr-openapi` ne commite pas la spec régénérée : un commit de bot relancerait toute la CI requise
  pour un JSON généré. Lance `yarn docs:openapi` dans `apps/api` et commite le résultat.
</Note>

## Turbo `--affected`

`ci.yml` fixe explicitement `TURBO_SCM_BASE` / `TURBO_SCM_HEAD` (PR, merge queue ou push) : dans un
checkout détaché, Turbo ne résout pas le ref `main` et retomberait sur « tout reconstruire ». Le
checkout utilise `fetch-depth: 0` pour la même raison.

## Runners auto-hébergés

Les jobs tournent sur un serveur dédié, répartis par profil de ressources :

| Pool         | Pour                                                                  |
| ------------ | --------------------------------------------------------------------- |
| `kare-light` | jobs courts sans install (parse, gates, promote, GC)                  |
| `kare-ci`    | `yarn install` + lint / tsc / tests                                   |
| `kare-build` | builds d'images Docker                                                |
| `kare-heavy` | suites d'intégration, E2E, `turbo build` (pool plafonné)              |
| `kare-api`   | suite API et drill de backup (adresse présente dans l'ACL de la base) |

Le cache Yarn et le cache Turbo sont persistés sur le NVMe de l'hôte et **partagés** entre
`ci-api-integration` et le gate `qa-api` du déploiement : un merge dont les sources API sont
identiques à celles de la PR relit le résultat au lieu de rejouer la suite. Une suite en échec
n'est jamais mise en cache.

<Warning>
  Le code d'une PR s'exécute sur l'hôte qui construit les images de déploiement. Risque résiduel
  assumé et connu : un `postinstall` npm malveillant (via un bump Dependabot) s'exécuterait sur cet hôte.
</Warning>

## Normes de sécurité

| Norme                                              | Raison                                                                   |
| -------------------------------------------------- | ------------------------------------------------------------------------ |
| Actions tierces épinglées au **SHA**               | `@v4` peut être déplacé ou compromis ; Dependabot fait les bumps         |
| `permissions` minimales par workflow               | un token qui fuit ne peut rien faire                                     |
| CLI (`scw`, `tofu`, `oasdiff`) épinglés + checksum | plus de téléchargement non vérifié exécuté directement                   |
| Concurrency                                        | la CI annule les runs obsolètes ; un déploiement n'est **jamais** annulé |
| Environments GitHub                                | les secrets `staging` sont cloisonnés dans l'environment `staging`       |

## E2E Playwright

`E2E (kare)` ne démarre que si les variables de repo `E2E_KARE=true` et
`E2E_API_URL=https://api.rs.staging.kare-app.fr` sont posées, avec `E2E_EMAIL` / `E2E_PASSWORD` en
secrets. Sinon le job est `skipped` et `CI Status` reste vert.
