Aller au contenu
English
CI/CD & Automatisation medium

Releases GitHub et images GHCR : publier ce qu'on déploie

Read this page in English

30 min de lecture

Déployer sur votre propre infrastructure ne demande qu'un artefact. Publier en demande davantage : une release datée et versionnée, une image adressable par un tiers, un rattachement visible entre le paquet et le code source. Cette page couvre les deux canaux que GitHub offre nativement, les Releases et le registre GHCR, et ce qui les relie à la chaîne de promotion.

  • Déclencher un workflow à la publication d'une release plutôt qu'à chaque push
  • Attacher des artefacts à une release depuis un workflow
  • Pousser une image sur GHCR avec le bon jeton et les bonnes permissions
  • Rattacher le paquet au dépôt pour qu'il cesse d'être un objet orphelin
  • Comprendre la visibilité d'un paquet et l'accès anonyme

La release comme déclencheur, pas comme conséquence

Section intitulée « La release comme déclencheur, pas comme conséquence »

Le réflexe courant consiste à publier sur chaque push de main. Le résultat est un flux continu de versions sans signification, et une signature apposée sur des états intermédiaires que personne n'a décidé de livrer.

Le déclencheur release: [published] inverse la logique : la publication est un acte délibéré, et le workflow ne s'exécute que pour les versions explicitement taguées.

name: Release
on:
release:
types: [published]
permissions: {}

L'avantage dépasse la propreté du flux. Une release porte un tag, donc une version lisible, donc une référence stable pour un ticket, un changelog ou un rollback. C'est aussi la granularité à laquelle les contrôles de posture attendent une signature : le contrôle Signed-Releases d'OpenSSF Scorecard examine les dernières releases, pas les commits.

Deux voies existent pour joindre des fichiers à une release. La plus directe utilise la CLI gh, déjà présente sur les runners, ce qui évite une dépendance supplémentaire :

permissions:
contents: write # nécessaire pour écrire sur la release
steps:
- name: Attacher les artefacts à la release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.event.release.tag_name }}
run: gh release upload "$TAG" dist/mon-app.tar.gz provenance.intoto.jsonl --clobber

La seconde passe par une action dédiée, utile quand vous créez la release depuis le workflow plutôt que depuis l'interface :

- name: Créer la release et joindre les fichiers
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
with:
files: |
dist/mon-app.tar.gz
sbom.cdx.json

Dans les deux cas, contents: write est requis au niveau du job seulement. C'est exactement le genre de permission qui ne doit jamais remonter au niveau du workflow : elle autorise l'écriture sur le dépôt.

GHCR (ghcr.io) est le registre de conteneurs de GitHub. Depuis un workflow du dépôt, l'authentification ne demande aucun secret à créer : le GITHUB_TOKEN de l'exécution suffit, à condition d'ouvrir la permission packages: write sur le job.

publish:
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
packages: write # push vers GHCR
id-token: write # OIDC keyless pour l'attestation
attestations: write
env:
IMAGE: ghcr.io/mon-org/mon-app
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Login GHCR
uses: docker/login-action@06fb636fac595d6fb4b28a5dfcb21a6f5091859c # v4.5.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build et push
id: build
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
push: true
tags: ${{ env.IMAGE }}:${{ github.event.release.tag_name }}
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}

En dehors d'un workflow, sur un poste ou un serveur, l'authentification passe par un jeton personnel portant le scope write:packages pour pousser.

Un paquet publié sans lien visible vers son code source est un objet orphelin : le consommateur voit une image, pas le dépôt qui la produit, ni ses sources, ni sa licence. Deux mécanismes règlent le problème.

Le premier est le label OCI org.opencontainers.image.source, qui porte l'URL du dépôt associé au paquet. C'est lui qui alimente le lien affiché sur la page du paquet.

Le second est plus simple encore : publier depuis un workflow du dépôt avec le GITHUB_TOKEN. C'est la voie que la documentation GitHub présente comme la plus directe pour connecter un dépôt à un paquet de conteneur. Les deux se cumulent sans conflit, et le label garde l'avantage d'être lisible hors de GitHub.

Un point surprend régulièrement : à sa première publication, un paquet est privé par défaut. La visibilité du paquet se règle indépendamment, sur sa propre page. Publier depuis un dépôt public ne suffit donc pas à rendre l'image téléchargeable.

Une fois le paquet rendu public, les images se récupèrent anonymement, sans authentification. C'est ce qui permet à un lecteur de votre documentation de tirer l'image pour la vérifier, et c'est aussi ce qui rend la vérification de provenance utile : n'importe qui peut contrôler ce que vous publiez.

Élément publiéCe qu'il apporte au consommateur
Release taguéeUne version nommée, datée, référençable
Artefact attachéLe binaire ou l'archive, sans passer par un build
SBOML'inventaire des composants, analysable par un scanner
Bundle de provenanceLa preuve de l'origine, vérifiable hors registre
Image GHCR par digestUne cible d'exécution immuable
Label image.sourceLe lien vers le code source et sa licence

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
6 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

  • Déclencher sur release: [published] fait de la publication un acte délibéré, et donne la granularité qu'attendent les contrôles de posture.
  • La CLI gh attache des fichiers à une release sans dépendance supplémentaire ; contents: write reste au niveau du job.
  • Sur GHCR, le GITHUB_TOKEN du workflow suffit avec packages: write ; hors workflow, il faut un jeton portant write:packages.
  • Le label org.opencontainers.image.source et la publication depuis le workflow du dépôt rattachent le paquet à son code source.
  • Un paquet est privé à sa première publication : la visibilité se règle séparément, même sur un dépôt public.
  • Un paquet public se tire anonymement, ce qui rend vos attestations vérifiables par n'importe qui.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn