Un ruleset décide qui peut écrire sur main, donc qui peut modifier vos
workflows. C'est le contrôle qui donne du poids à tous les autres. Cette page
montre comment le configurer, en quoi il diffère de la protection de branche
classique, et pourquoi sa bypass list mérite une décision explicite : sans
elle, personne ne passe outre, pas même le propriétaire du dépôt.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Distinguer ruleset et protection de branche classique, et leurs API distinctes
- Configurer les règles qui comptent pour la sécurité de la CI
- Décider de la bypass list en connaissance de cause
- Sauvegarder et restaurer un ruleset sans passer par l'interface
- Anticiper l'impasse que crée un assouplissement temporaire
Ruleset ou protection de branche classique ?
Section intitulée « Ruleset ou protection de branche classique ? »GitHub propose deux mécanismes qui font un travail proche, coexistent sur le même dépôt, et ne se règlent ni au même endroit ni avec la même API. La confusion coûte du temps au moment où l'on cherche pourquoi une fusion est refusée.
| Protection de branche classique | Ruleset | |
|---|---|---|
| Emplacement | Settings > Branches | Settings > Rules |
| Portée | Une branche à la fois | Un motif de références, plusieurs branches |
| Cumul | Une seule règle s'applique | Plusieurs rulesets s'additionnent |
| Contournement admin | Possible sauf option contraire | Uniquement via la bypass list |
| Mode test | Non | evaluate, qui journalise sans bloquer |
| API | /branches/{branch}/protection | /repos/{owner}/{repo}/rulesets |
Le mode evaluate est l'argument décisif pour un dépôt existant : il
applique le ruleset sans rien bloquer et journalise ce qui aurait été
refusé. Vous mesurez la friction réelle avant de l'imposer.
Les règles qui comptent pour la CI
Section intitulée « Les règles qui comptent pour la CI »Toutes les règles ne se valent pas du point de vue de la sécurité des pipelines. Les quatre ci-dessous ferment les chemins réellement empruntés.
| Règle | Ce qu'elle empêche |
|---|---|
| Pull request obligatoire | Un commit direct sur main qui ajoute ou modifie un workflow |
| Revue code owner | Une modification de .github/workflows/ relue par quelqu'un qui n'y connaît rien |
| Checks requis | Une fusion alors que les scanners de workflow sont rouges |
| Force push interdit | La réécriture de l'historique qui masquerait l'ajout d'un workflow |
La troisième mérite une précision : exiger les checks au vert n'a de valeur que si vos checks vérifient quelque chose. Un ruleset qui exige un job de tests mais ignore le scanner de workflows laisse passer exactement ce que ce module cherche à bloquer.
Créer le ruleset
Section intitulée « Créer le ruleset »L'interface suffit pour la création. En ligne de commande, la lecture est plus utile que l'écriture : c'est elle qui permet de vérifier, de sauvegarder, et de détecter une dérive.
REPO=mon-org/mon-projet
# Lister les rulesets actifsgh api "repos/$REPO/rulesets" --jq '.[] | {id, name, enforcement}'
# Lire les paramètres de la règle pull_requestgh api "repos/$REPO/rulesets/RULESET_ID" \ --jq '.rules[] | select(.type=="pull_request") | .parameters'La sortie attendue sur un dépôt gouverné ressemble à ceci :
{ "required_approving_review_count": 1, "require_code_owner_review": true, "dismiss_stale_reviews_on_push": true, "require_last_push_approval": true}dismiss_stale_reviews_on_push et require_last_push_approval sont les
deux réglages qu'on oublie, et ce sont ceux qui ferment la faille la plus
évidente : obtenir une approbation sur un diff anodin, puis pousser le workflow
malveillant avant la fusion.
La bypass list, décision à prendre avant d'en avoir besoin
Section intitulée « La bypass list, décision à prendre avant d'en avoir besoin »C'est la différence de comportement qui surprend le plus, et elle se découvre généralement au mauvais moment.
Sur une protection de branche classique, un administrateur passe outre par défaut. Sur un ruleset, personne ne passe outre : ni l'administrateur, ni le propriétaire du dépôt. Le contournement n'existe que pour les acteurs inscrits dans la bypass list. Une bypass list vide signifie littéralement que la règle s'applique à tout le monde.
La conséquence pratique est nette : sur un dépôt à mainteneur unique, avec une
revue code owner obligatoire et une bypass list vide, plus rien ne peut être
fusionné. GitHub interdit d'approuver sa propre pull request, il n'y a donc
aucun chemin. Même gh pr merge --admin est refusé, contrairement à ce que son
nom laisse espérer.
Sauvegarder et restaurer
Section intitulée « Sauvegarder et restaurer »Toute modification d'un ruleset doit être précédée d'une sauvegarde. L'API attend un objet complet en écriture : renvoyer une structure partielle écrase ce qui manque.
-
Sauvegarder l'état courant, avant toute modification.
Fenêtre de terminal gh api "repos/$REPO/rulesets/$RULESET_ID" > ruleset-backup.json -
Construire la version modifiée à partir de la sauvegarde, en ne touchant que la règle visée. Le filtre final écarte les clés nulles, que l'API refuse.
Fenêtre de terminal jq '{name, target, enforcement, conditions, bypass_actors,rules: (.rules | map(if .type == "pull_request"then .parameters.required_approving_review_count = 0else . end))}| with_entries(select(.value != null))' ruleset-backup.json > ruleset-relaxed.json -
Appliquer, puis vérifier la valeur réellement en place plutôt que le code de retour.
Fenêtre de terminal gh api -X PUT "repos/$REPO/rulesets/$RULESET_ID" --input ruleset-relaxed.jsongh api "repos/$REPO/rulesets/$RULESET_ID" \--jq '.rules[] | select(.type=="pull_request") | .parameters' -
Restaurer depuis la sauvegarde dès que l'opération est terminée, et relancer le scanner de posture pour confirmer le retour à la conformité.
La dernière étape n'est pas cosmétique. Un PUT qui renvoie 200 prouve que
l'API a accepté le corps, pas que la protection attendue est en place. Seule la
relecture, ou mieux le passage au vert du scanner, le démontre.
Ce qu'un scanner voit de votre ruleset
Section intitulée « Ce qu'un scanner voit de votre ruleset »Un point souvent ignoré : la protection de branche est lisible par API, donc auditable en continu. Un scanner de posture la compare à vos attentes déclarées et signale l'écart.
Deux conséquences utiles. La première est défensive : un affaiblissement
temporaire oublié devient visible au prochain passage de la CI, au lieu de
s'installer. La seconde est une contrainte d'outillage : le GITHUB_TOKEN par
défaut ne peut pas lire la configuration complète de protection de branche.
Un scanner qui s'en contente ne voit qu'une partie des réglages et conclut à
tort que la revue code owner n'est pas exigée. Il faut lui fournir un jeton
disposant de la permission Administration en lecture, idéalement un jeton
éphémère de GitHub App plutôt qu'un secret de longue durée.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »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
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
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Ruleset et protection classique coexistent, se règlent à deux endroits et s'interrogent par deux API distinctes ; le message de refus permet de les distinguer.
- Le mode
evaluateapplique un ruleset sans bloquer et journalise ce qui aurait été refusé : c'est la bonne façon de l'introduire sur un dépôt existant. - Quatre règles comptent pour la CI : pull request obligatoire, revue code owner, checks requis et force push interdit.
dismiss_stale_reviews_on_pushetrequire_last_push_approvalferment la faille de l'approbation obtenue sur un diff anodin.- Sur un ruleset, personne ne contourne hors de la bypass list, pas même le propriétaire :
gh pr merge --adminest refusé. - Assouplir pour fusionner crée une non-conformité qu'un scanner détecte, et qui peut bloquer la fusion visée : la bypass list se décide à froid.
- Une écriture d'API réussie ne prouve rien : relire la valeur en place, et confirmer par le passage au vert du scanner.
- Un scanner de posture a besoin d'un jeton Administration en lecture pour voir la protection complète ; le
GITHUB_TOKENpar défaut ne suffit pas.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Restreindre les actions autorisées : Le contrôle d'organisation qui décide quel code tiers peut s'exécuter, indépendamment de qui écrit le workflow.
- Runner groups et frontière réseau : Borner ce qu'une exécution compromise peut atteindre sur votre infrastructure.
- ActionLint : Le check le plus rapide à rendre obligatoire dans les règles de fusion.