Branch protection sur main (réglage GitHub — audit P7 #29)
Configurée côté GitHub (non versionnable, documentée ici pour mémoire) :
Pull request obligatoire (pas de push direct — doublé par le hook
no-direct-push-to-main).
12 checks requis avant merge : prettier, yamllint, shellcheck,
kubeconform, ansible-lint, commitlint, trivy, bats, jscpd,
markdownlint, ansible-syntax, scripts-extra. Tout job CI doit être
ajouté à cette liste : un job non requis se contourne par l’auto-merge et
peut casser main (vécu deux fois — trivy, puis lychee). (lychee
retiré avec la migration Astro, ADR 0089 : la validation des liens de doc est
désormais bloquante au build via starlight-links-validator.) Règle :
nouveau job → l’ajouter aux required checks une fois vu vert.
⚠️ Écart à combler : les jobs python (ruff + tests unittest) et
gitleaks (secret scanning) tournent en CI mais ne sont pas encore dans
les required checks — à ajouter une fois éprouvés (gitleaks est non
bloquant de propos délibéré ; python devrait l’être). C’est précisément la
règle ci-dessus, non encore appliquée à ces deux jobs récents.
strict: true : la branche doit être à jour avec main (checks
rejoués sur le dernier état) avant merge.
Résolution des conversations requise.
0 review requise : choix assumé pour un repo mono-mainteneur — exiger
une approbation bloquerait l’auto-merge des PR de release (cf. release-please
ci-dessous : aucun second relecteur disponible).
Vérifier / réappliquer :
gh api repos/univ-lehavre/cluster/branches/main/protection.
À chaque push sur main :
release-please ouvre (ou met à
jour) une PR de release qui bumpe package.json et CHANGELOG.md d’après les
Conventional Commits. L’auto-merge est activé sur cette PR dès sa création
: GitHub la fusionne automatiquement quand les checks requis sont verts, ce
qui pousse le tag vX.Y.Z et publie une
GitHub Release. →
Publication 100 % automatique ; aucune version flottante en main, chaque
tag lié à un set de commits validé par la CI.
✅ Token : PAT fine-grained (RELEASE_PLEASE_TOKEN). L’organisation
univ-lehavre verrouille le GITHUB_TOKEN par défaut en lecture seule
(default_workflow_permissions ne peut pas passer à write au niveau repo →
409 Write permissions for workflows are disabled by the organization). Avec
ce token bridé, release-please ouvrait la PR mais ne pouvait ni pousser le tag
ni publier la release. On utilise donc un PAT fine-grained (scope = ce
repo, Contents: RW + Pull requests: RW) déposé en secret
RELEASE_PLEASE_TOKEN et injecté via with: token: dans release.yml. Il
débloque tag + release et redéclenche la CI sur la PR de release — sans
quoi l’auto-merge resterait en attente de checks qui ne tournent jamais.
Réglage repo associé : allow_auto_merge=true.
⚠️ Rotation : un PAT expire. À renouveler avant échéance (même scope, même
nom de secret), sinon les releases se rebloquent silencieusement.
🛟 Filet de sécurité — symptôme d’un token absent/expiré : la PR de
release n’aboutit plus, et faute de tag publié release-please re-propose une
version toujours plus haute à chaque push (boucle observée le 2026-05-29 :
2.0.0 jamais taguée → 3.0.0 reproposée). Rattrapage manuel (le contenu
de main est déjà bon : package.json, .release-please-manifest.json et
CHANGELOG.md portent la bonne version) :
Fenêtre de terminal
# 1. Publier le tag + la release sur le HEAD de main
bench/ — valider sur vrai Debian 13 avant de toucher
les serveurs.
bench/lima/ — banc multi-nœuds (ADR 0038, seul banc local)
3 VMs Lima Debian 13 arm64 (réseau user-v2 192.168.104.0/24) + disques bruts
pour Ceph. Orchestré par
bench/lima/run-phases.sh
à gates : up → bootstrap → ceph → sc → datalake → dataops → monitoring.
Deux profils — léger (local-path/SeaweedFS, ~11 min) et Ceph (RGW, ~30 min).
Couvre la chaîne complète Phase 1-5 + DataOps.
Toujours valider sur le banc avant la prod — c’est le seul endroit où le
multi-VM et les disques Ceph sont exercés (validation = run e2e from-scratch,
ADR 0034).
Isolation banc ↔ prod
Le banc Lima est volontairement isolé (mounts: [], réseau user-v2 dédié
192.168.104.0/24, disjoint de la plage de production 10.0.0.0/22). Il n’a
pas d’interface host-only susceptible de capturer les routes vers les vrais
serveurs.
Tableau de bord lecture-seule par hôte : services actifs, sshd -T, dernier
unattended-upgrades.log, alias root, IPs bannies par fail2ban, règles auditd,
état UFW, expiration mot de passe. Le hardening est 100 % opt-in
(bootstrap/security/IMPLICATIONS.md)
— chaque couche s’active explicitement.
Chaque playbook bootstrap appose une ligne dans /var/log/cluster-bootstrap.log
du nœud cible : timestamp UTC, nom du playbook, opérateur $USER@hostname côté
contrôle. Lu par la couche 0 de state.sh pour corréler “ce qui a été appliqué”
et “ce qui est observé”.
Timer systemd horaire qui exécute etcdctl snapshot save ; rétention 24
snapshots (1 jour glissant). Procédure de restauration documentée dans
bootstrap/RUNBOOK.md.
Dépose la clé SSH, configure sudo NOPASSWD, pose le drop-in sshd hardening.
Strictement idempotent : un 2ᵉ run ne change rien si l’état est déjà conforme
(compare avec cat avant install).
Les ADR (Architecture Decision Records) au format Contexte / Décision / Statut
/ Conséquences. Couvrent les choix architecturaux (réplication ×3, control
plane unique, hyperconvergence, EC 2+1 datalake) et les compromis sécurité (HTTP
sans auth, dashboard cluster-admin, RStudio sans login). Voir
index ADR.
Phasage gated banc → prod
L’ordre de déploiement (canari cp1 → workers → stockage cluster-wide) et les
gates par étape sont décrits dans
bootstrap/RUNBOOK.md § Ordre de déploiement ;
tout changement de cette nature doit passer par le banc
(bench/) avant la prod. Le pourquoi de chaque choix
structurant est tracé dans les ADR. Le reste-à-faire
priorisé vit dans
docs/audit/2026-05-29/12-plan-action.md.