GitHub Actions
Trois workflows par application, chacun avec un job de son type. Le modèle .github/workflows/{pr,main,release}.yaml est la source de vérité ; ils sont reproduits avec des notes dans references/workflows.md.
pull request ──► pr.yaml vérifications uniquement, rien n'est publié
merge to main ─► main.yaml image construite une fois → ghcr.io/nuvraxis/<app>:sha-<short>, :main
tag vX.Y.Z ────► release.yaml retag de la même image :vX.Y.Z, :latest · chart X.Y.Z → OCI · GitHub Release
Règles pour chaque workflow
-
permissions: contents: readen haut ; élargir par job uniquement si nécessaire.packages: writepour les jobs qui poussent vers GHCR,contents: writeuniquement pour le job qui crée la Release. Pas deid-token: writeouattestations: write: provenance et SBOM proviennent de BuildKit, pas deactions/attest*(qui nécessite GitHub Enterprise pour les dépôts privés). -
GITHUB_TOKENuniquement. La connexion GHCR utilise${{ github.actor }}/${{ secrets.GITHUB_TOKEN }};ghutiliseGH_TOKEN: ${{ github.token }}. Pas de jetons d'accès personnels dans CI. (Le tirage de paquets privés depuis le cluster est une information d'identification différente ; voirhelm-nextjs.) -
Pinner les actions aux versions majeures (
@v7) et tenir à jour le tableau SHA. Le modèle utilise des tags majeurs pour la lisibilité. Si l'organisation exige le pinning SHA, remplacez chaque@vNpar le SHA de references/action-pins.md et conservez le commentaire# vN.M.P. Versions majeures actuelles : checkout v7, setup-node v7, pnpm/action-setup v6, setup-qemu v4, setup-buildx v4, login v4, metadata v6, build-push v7, azure/setup-helm v5. -
Chaîne d'outils :
pnpm/action-setupavantactions/setup-node. action-setup lit la version pnpm depuispackageManager; setup-node lit.node-versionet met en cache le store pnpm (cache: pnpmnécessite pnpm sur PATH d'abord). Ensuitepnpm install --frozen-lockfile. Jamaisnpm ci. -
concurrencypar workflow et ref ; annuler en cours sur les PRs uniquement. Une nouvelle poussée vers une PR annule l'ancien run. Sur main et les tags, les runs se terminent toujours : release.yaml nécessite l'image de cet commit exact. -
Ne jamais afficher de secrets ni interpoler d'entrées non fiables dans
run:. Passer les valeurs viaenv:et les citer ("${APP}").${{ github.event.pull_request.title }}et autres ne doivent jamais se trouver dans un script.persist-credentials: falsesur le checkout lorsque le job ne pousse pas vers git. -
Chaque job a
timeout-minutes. Une construction Docker bloquée brûlerait autrement six heures. -
Les noms sont en minuscules. GHCR rejette les dépôts en majuscules.
IMAGE: ghcr.io/nuvraxis/<app>est écrit en minuscules dansenv; le scaffold met le nom de l'app en minuscules.
pr.yaml
-
on: pull_requestavectypes: [opened, synchronize, reopened, ready_for_review]et sans filtrebranches, afin que les PRs empilées contre des branches de fonctionnalités soient également vérifiées. Chaque job aif: ${{ !github.event.pull_request.draft }}; marquer comme prêt déclenche le run. -
Quatre jobs parallèles :
quality(biome ci --reporter=github, stylelint,turbo run typecheck test --affected,pnpm audit --audit-level high),build(turbo run build --affected),docker(construire une plateforme avecload: true, l'exécuter en lecture seule avec les capacités supprimées, curl/api/health),helm(helm lint --strictet kubeconform sur les deux fichiers values).--affectednécessitefetch-depth: 0. -
Rien n'est poussé depuis une PR.
push: false, cache en lecture seule (cache-fromuniquement), pas de connexion au registre.
main.yaml
-
on: push: branches: [main]construit l'image une fois, pour les deux architectures, et la pousse. Tags dedocker/metadata-action:type=sha,format=short,prefix=sha-ettype=raw,value=main,flavor: latest=false.latestappartient aux releases. -
provenance: mode=max,sbom: true,cache-from/to: type=gha,scope=<app>,mode=max. La provenance et le SBOM sont attachés à l'index d'image ; release.yaml les transporte lorsqu'il retague.NEXT_DEPLOYMENT_ID=${{ github.sha }}est l'argument de build pour la protection contre le skew. -
main.yaml ne publie pas le chart et ne relance pas les vérifications PR. La protection de branche nécessite pr.yaml ; main ne produit que l'artefact.
release.yaml
-
on: push: tags: ['v*.*.*'], puis dans l'ordre :- Échouer sauf si le tag est exactement
vMAJOR.MINOR.PATCHet que son commit est un ancêtre deorigin/main. - Ne pas reconstruire. Si
ghcr.io/nuvraxis/<app>:sha-<short>n'existe pas, échouer avec « laissez main.yaml se terminer, puis relancez ». Pas de construction de repli. docker buildx imagetools create --tag :vX.Y.Z --tag :latest <sha-image>: une copie au niveau du manifeste qui conserve les deux architectures, la provenance et le SBOM, au même digest.helm package --version X.Y.Z --app-version vX.Y.Z,helm pushversoci://ghcr.io/nuvraxis/charts.gh release create vX.Y.Z --verify-tag --generate-notesavec le chart.tgz,image-digest.txtetsbom.spdx.jsonjoints.
- Échouer sauf si le tag est exactement
-
Le rituel de release : merger vers main → attendre que main.yaml devienne vert →
git tag vX.Y.Z && git push origin vX.Y.Z. Tagger avant que main.yaml ne se termine fait échouer l'étape 2 intentionnellement ; relancez le job de release une fois que l'image existe. Une mauvaise release est corrigée avec un nouveau tag de patch, jamais en déplaçant un tag.
Accélérer (uniquement si nécessaire)
- arm64 sous QEMU est la partie lente de main.yaml. Remplacer par une matrice sur
ubuntu-24.04-arm+ubuntu-latesten poussant par digest, puis un job de fusion avecimagetools create. Conserver les tags et l'index unique. - Cache distant Turborepo pour pr.yaml : voir
pnpm-turborepo.
Vérifier
docker run --rm -v "$PWD:/repo" -w /repo rhysd/actionlint:latest # linter tous les workflows
gh workflow list && gh run list --limit 5
gh run view <run-id> --log-failed
Après une release : docker buildx imagetools inspect ghcr.io/nuvraxis/<app>:vX.Y.Z affiche les deux plateformes, et helm show chart oci://ghcr.io/nuvraxis/charts/<app> --version X.Y.Z affiche appVersion: vX.Y.Z.
Sources
- https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions
- https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions
- https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
- https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry
- https://github.com/pnpm/action-setup
- https://github.com/actions/setup-node
- https://github.com/docker/metadata-action
- https://github.com/docker/build-push-action
- https://docs.docker.com/build/ci/github-actions/cache/#github-cache
- https://docs.docker.com/build/metadata/attestations/
- https://docs.docker.com/reference/cli/docker/buildx/imagetools/create/
- https://helm.sh/docs/topics/registries/
- https://cli.github.com/manual/gh_release_create
- https://turborepo.dev/docs/reference/run#--affected