Guide participant
TP4 — Gouverner le Skill sur GitHub
Variante GitHub — faire du Skill un actif revu, évalué et protégé, puis organiser sa réduction lorsque le modèle progresse.
Variante GitHub. Le même TP existe pour GitLab ; la page d’entrée du TP4 donne la correspondance des termes. Suivez la variante de la forge préparée par le formateur, sans mélanger.
Objectif et livrables
Obtenez une pull request relue, un workflow GitHub Actions qui évalue la génération de cette PR et des règles de protection vérifiées. Définissez aussi qui peut charger le Skill et comment le faire évoluer.
Entrées : Skill et références du TP2, harnais complété du TP3, accès à un dépôt GitHub d’atelier dans une organisation, et à un runner Actions, hébergé par GitHub ou auto-hébergé. Certaines protections dépendent de l’offre : sur github.com, les règles de branche d’un dépôt privé et la revue obligatoire par les propriétaires demandent GitHub Team ou Enterprise, et les propriétaires doivent être des équipes de l’organisation. Vérifiez les possibilités avec le formateur.
Essentiel et approfondissement
| Parcours | Sections concernées | Preuve de sortie |
|---|---|---|
| Préparation formateur — avant séance, hors 14 h | 1, 3 et 4 : dépôt, runner, environnement OpenCode, modèle, fournisseur du juge et secrets autorisés prévalidés | Workflow de PR réellement générateur et évaluateur dans un contexte de confiance ; infrastructure prête pour les versions des participants |
| Essentiel — 1 h 30 cible | 1 à 6 : import des travaux, protections, inspection du workflow et des secrets préparés, permissions et PR ; 7 : définir le protocole de suppression | main protégé, revue Code Owners selon l’offre, vraie génération depuis la PR avec évaluation, blocage rouge puis retour vert, chargement Skill allow/deny observé |
| Approfondissement — hors 14 h ou si avance | 3 et 4 : installation CI depuis zéro / parcours autonome ; 3 : plusieurs générations ; 6 : diagnostics supplémentaires ; 7 : test de suppression répété | Chaîne autonome éprouvée, résultats par cas, comparaison répétée avec/sans instruction |
Les participants configurent et prouvent les protections et la revue ; la préparation du runner ne fait pas cet exercice à leur place. Si l’infrastructure n’est pas prête, allongez l’atelier ou annoncez une démonstration partielle et non validée. Le temps cible ne justifie ni génération fictive ni suppression de test.
Les fichiers livrés dans
tp4-gouvernance/sont des exemples à adapter. Le workflow contient unecho "TODO atelier…": il ne génère aucun serveur en l’état. Les permissions OpenCode sont elles aussi un exemple, pas une configuration à recopier aveuglément.
1. Préparer le dépôt de gouvernance
Essentiel : utilisez le dépôt GitHub d’atelier prévalidé par le formateur, dans l’organisation prévue. Sa création depuis zéro relève de la préparation ou du parcours autonome. Pour garder les chemins fournis cohérents, conservez cette organisation à sa racine :
.github/
workflows/evaluer-le-skill.yml
CODEOWNERS
domaine/
tp2-skill/
skills/create-quarkus-mcp-server/SKILL.md
references/conventions-quarkus-mcp.md
tp3-eval/
pom.xml
src/test/...
Dans un clone de ce dépôt, copiez vos versions complétées des supports,
pas les squelettes initiaux. Copiez aussi le .gitignore des supports, puis ajoutez
les exclusions nécessaires pour les sorties de génération et les secrets.
Utilisez le workflow adapté et prévalidé par le formateur, sans l’écraser par le
template contenant l’echo. Adaptez le CODEOWNERS fourni.
En préparation ou en parcours autonome, partez des fichiers de tp4-gouvernance/
et effectuez les adaptations des sections 3 et 4 avant d’en attendre une validation.
Vérifiez git status avant tout commit.
Si vous reprenez le clone de formation plutôt qu’un dépôt séparé, ajoutez un remote
distinct, sans remplacer origin :
git remote add atelier-github <URL_DU_DEPOT_GITHUB>
git remote -v
Remplacez <URL_DU_DEPOT_GITHUB> avant exécution. Faites valider l’import initial
de main selon les droits du dépôt, puis travaillez uniquement sur des branches de
contribution. Ne poussez pas de clés, de configuration personnelle ou de sorties
du modèle contenant des données non autorisées.
2. Protéger main et rendre la revue effective
Dans les paramètres du dépôt, ouvrez Rules / Rulesets, ou Branches / Branch
protection rules sur les dépôts qui utilisent encore l’ancien modèle. Créez une
règle qui cible main :
- Require a pull request before merging : le push direct est refusé.
- Require approvals avec au moins une approbation, Require review from Code Owners, et rejet des approbations obsolètes après un nouveau commit.
- Require status checks to pass before merging : ajoutez le check du job d’évaluation, sous le nom exact qu’il porte dans le workflow.
- Block force pushes et Restrict deletions.
- N’autorisez aucun contournement, administrateurs compris. Une règle que les propriétaires du dépôt peuvent ignorer ne prouve rien pendant l’exercice.
Le fichier fourni contient :
/tp2-skill/skills/ @platform-team
Sur GitHub, un propriétaire est un utilisateur ou une équipe d’organisation
notée @organisation/nom-de-l-equipe, avec un accès en écriture au dépôt.
Remplacez @platform-team par l’équipe réelle. Ajoutez la propriété des
références et du harnais : changer la convention ou affaiblir le test peut
contourner une protection portant seulement sur le Skill. Si vous avez déplacé le
Skill sous /skills/, adaptez aussi le motif. GitHub signale les erreurs de
syntaxe et les propriétaires inconnus dans l’affichage du fichier : vérifiez-le.
Un fichier CODEOWNERS n’impose pas à lui seul une approbation bloquante. C’est la case « Require review from Code Owners » de la règle de branche qui la rend obligatoire. Vérifiez sur une PR réelle que les propriétaires sont sollicités et que la fusion reste bloquée sans leur approbation. Si l’offre ne le permet pas, documentez cette limite et organisez une revue manuelle ; ne la présentez pas comme une protection automatique.
3. Remplacer la génération fictive du workflow
Préparation formateur / parcours autonome : les opérations d’installation et de câblage de cette section se font avant la séance, ou en approfondissement hors 14 h. Dans l’essentiel, inspectez le workflow préparé, repérez chacune des étapes ci-dessous et prouvez leur exécution sur votre PR en section 6. Le dépôt ne livre pas cette chaîne opérationnelle clé en main.
Ouvrez .github/workflows/evaluer-le-skill.yml. Le job fourni s’exécute sur
l’événement pull_request vers main, sur ubuntu-latest, installe un JDK 21
Temurin avec le cache Maven, puis appelle le harnais. Il n’installe pas OpenCode :
prévoyez une installation explicite à version fixée, par exemple avec
npm install -g opencode-ai@<version>, ou un runner auto-hébergé préparé selon
les pratiques de votre organisation.
Remplacez le echo TODO par une vraie séquence :
- Créer un dossier
serveur-genere/vide dans le checkout du job. - Y copier le catalogue et le Skill issu de la PR, avec sa référence.
- Lancer OpenCode en mode non interactif, avec modèle et permissions maîtrisés.
- Vérifier qu’un POM a été produit, compiler et tester le serveur.
- Vérifier séparément le démarrage et les appels MCP ; le harnais ne le fait pas.
- Exécuter le harnais complété du TP3, juge inclus pour le parcours complet, sur cette sortie et conserver les rapports.
Voici un point de départ pour la commande de génération, à intégrer dans une
étape run après installation d’OpenCode et configuration du fournisseur :
mkdir -p serveur-genere/.opencode/skills/create-quarkus-mcp-server/references
cp domaine/catalogue-services.json serveur-genere/
cp tp2-skill/skills/create-quarkus-mcp-server/SKILL.md \
serveur-genere/.opencode/skills/create-quarkus-mcp-server/
cp tp2-skill/references/conventions-quarkus-mcp.md \
serveur-genere/.opencode/skills/create-quarkus-mcp-server/references/
(
cd serveur-genere
opencode run --model "$GENERATION_MODEL" \
"Charge le Skill create-quarkus-mcp-server et sa référence. Crée ici un serveur MCP Quarkus pour catalogue-services.json : tools find_service et get_owner, resource service://{name}, prompt fiche_service. Compile et teste le projet."
)
test -f serveur-genere/pom.xml
mvn -B -f serveur-genere/pom.xml test
mvn -B -f tp3-eval/pom.xml -Dserveur.genere.dir="$GITHUB_WORKSPACE/serveur-genere" test
Le harnais vérifie les conventions du Skill, les noms de tools demandés dans ce prompt et, si les variables du juge sont présentes, la note du LLM-as-a-judge.
Cet extrait illustre la génération, le build et l’appel au harnais : il ne constitue pas un job complet et ne vérifie pas le démarrage ni les appels MCP. Le formateur prépare aussi ce contrôle séparé, la collecte des traces et la vérification de présence du juge de la section 4. Les participants en inspectent les preuves.
Ces commandes supposent que le répertoire courant est la racine du checkout,
GITHUB_WORKSPACE. GENERATION_MODEL contient un identifiant fournisseur/modèle.
Vérifiez les options de votre version avec opencode run --help ; le --skill
figurant dans le texte TODO du squelette ne doit pas être présumé disponible. Le
Skill se découvre dans le projet et se charge via l’outil skill.
Sur l’événement pull_request, actions/checkout récupère par défaut le commit
de fusion de la PR sur main, pas le dernier commit de la branche. C’est la
version qui serait fusionnée : c’est bien elle qu’il faut évaluer. Relevez le SHA
évalué dans le journal du job pour le compte rendu.
Le modèle peut ne pas charger le Skill malgré le prompt : conservez les traces de génération et vérifiez ce chargement. Ne remplacez pas cette étape par un serveur préfabriqué ou mis en cache : le workflow doit évaluer la modification proposée. Une génération réellement issue de la PR par exécution du workflow suffit au parcours essentiel : relevez son prompt et sa provenance. En approfondissement, étendez le job à plusieurs générations indépendantes, un répertoire par génération, pour mesurer la stabilité du Skill.
Le code de sortie d’OpenCode seul ne suffit pas. Les étapes Maven doivent bloquer
le job en cas d’échec : pas de || true, pas de continue-on-error: true pour le
contrôle de conformité, pas de suppression des tests rouges.
4. Configurer les secrets et les preuves
Préparation formateur / parcours autonome : configurez et testez ces accès avant séance. Essentiel participants : inspectez les noms, les portées et la politique d’accès sans révéler les valeurs, puis constatez que génération et juge ont été réellement exécutés sur la PR. Ne passez pas les 1 h 30 à installer un fournisseur.
Définissez secrets et variables dans Settings / Secrets and variables / Actions,
jamais dans le YAML. Le workflow les lit avec secrets.NOM et vars.NOM :
| Nom | Type | Usage |
|---|---|---|
GENERATION_MODEL |
Variable | Modèle utilisé par OpenCode |
| Identifiants du fournisseur OpenCode | Secret | Génération ; nom selon le fournisseur |
LLM_ENDPOINT, LLM_MODEL |
Variables | Juge du TP3 |
LLM_API_KEY |
Secret | Juge du TP3, requis pour le parcours complet |
Les variables du juge ne configurent pas automatiquement le fournisseur OpenCode.
GitHub masque les secrets dans les journaux, mais un echo volontaire ou un fichier
d’artefact peut les exposer : ne les écrivez nulle part.
Les secrets ne sont pas transmis aux workflows pull_request déclenchés depuis
un fork. C’est une protection, pas un bug. Ne la contournez pas avec
pull_request_target : cet événement s’exécute avec les secrets du dépôt de base
et, combiné à un checkout puis une exécution du code proposé, livre vos clés à
n’importe quel contributeur. Ne le résolvez pas en exposant vos clés aux PR non
fiables.
Choisissez une politique explicite :
- workflow d’évaluation complète uniquement pour les PR internes, ou derrière un Environment GitHub à approbation requise : le job attend qu’un relecteur désigné l’autorise avant d’accéder aux secrets de cet environnement ;
- ou démonstration partielle sans juge, explicitement non validée pour le parcours complet, avec génération réalisée dans un environnement de confiance et évaluation complète à reprendre lorsque les accès seront disponibles.
Pour la validation complète de l’atelier, faites échouer le job lorsque les
variables du juge sont absentes : le test JUnit est sinon ignoré lorsque
LLM_ENDPOINT est vide. Vérifiez aussi dans le rapport qu’il a été exécuté.
Un workflow vert ne doit pas cacher cette absence ni autoriser une fusion
présentée comme entièrement évaluée.
Conservez les rapports avec actions/upload-artifact et la condition
if: always(), sur tp3-eval/target/surefire-reports/. Conservez aussi le commit
du Skill, le modèle, les cas utilisés et les sorties utiles, après suppression des
secrets. Limitez le jeton du workflow avec permissions: contents: read.
Les sources produites par l’agent sont du code à exécuter dans un runner isolé,
avec des droits minimaux : les runners hébergés par GitHub sont éphémères ; un
runner auto-hébergé doit l’être aussi, jamais sur une machine contenant des accès
de production, et jamais sur un dépôt public.
5. Contrôler les permissions de Skills
Lisez opencode-permissions.example.json : il illustre une intention, mais précise
qu’il doit être adapté au schéma courant. Dans la
documentation OpenCode, le réglage passe par
permission.skill, au singulier.
Exemple à intégrer à un opencode.json d’atelier, en conservant les autres réglages :
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"build": {
"permission": {
"skill": {
"create-quarkus-mcp-server": "allow"
}
}
},
"plan": {
"permission": {
"skill": {
"create-quarkus-mcp-server": "deny"
}
}
}
}
}
Ici, build peut charger le Skill et plan ne le peut pas. Pour un agent de revue
personnalisé, utilisez son nom réel et sa configuration. Dans deux nouvelles
sessions, essayez le chargement avec chacun des agents et conservez le résultat.
Un refus d’accès au Skill n’interdit pas à lui seul de lire un fichier, d’exécuter une commande ou de pousser du code. Complétez par les permissions d’outils et les droits GitHub ; ne confondez pas ces couches de contrôle :
- GitHub contrôle contributions, secrets Actions, revue et fusion.
- OpenCode contrôle notamment le chargement du Skill via
permission.skill; ses identifiants fournisseur permettent les appels au modèle. - L’authentification et l’autorisation MCP contrôlent l’accès à un serveur et
à ses capacités ; elles ne sont ni configurées ni prouvées par un
allow/denyde Skill. N’extrapolez pas ce test à la sécurité d’accès du serveur MCP.
6. Ouvrir une PR et tester le blocage
Créez une branche, modifiez une règle du Skill et ouvrez une pull request vers
main. Dans sa description, indiquez l’écart ciblé, les cas d’évaluation concernés
et les résultats avant/après.
Contrôlez que les propriétaires sont demandés en relecture automatiquement et que
le workflow démarre. Vérifiez le commit évalué, le chargement du Skill, la
génération neuve et les rapports du harnais, y compris le juge. Le bouton de fusion
doit indiquer les conditions manquantes : check requis en attente ou en échec,
revue des propriétaires absente. Avec un rôle contributeur, constatez aussi le refus
du push direct sur main et conservez la preuve :
git push atelier-github HEAD:main
# attendu : refus de la branche protégée (message GH006 ou règle de ruleset)
Essentiel : utilisez une mutation contrôlée déjà éprouvée au TP3 pour démontrer
le blocage. Sur cette branche d’exercice, jamais sur main, ajoutez
temporairement une étape qui injecte ce défaut dans la sortie après la vraie
génération et avant l’évaluation. Gardez tous les tests actifs. Le check doit
devenir rouge et la fusion impossible. Conservez le rapport et l’état de la PR.
Retirez l’injection dans un nouveau commit et relancez la chaîne complète :
génération neuve, build/MCP et évaluation doivent revenir au vert. Cette correction
ne consiste pas à retirer le test qui détectait le défaut.
Approfondissement / diagnostic : une assertion JUnit temporaire explicitement en échec permet aussi d’isoler la mécanique de blocage GitHub. Si vous l’utilisez, retirez uniquement cette assertion ajoutée pour le diagnostic, jamais les tests du harnais ; cette preuve seule ne démontre pas la détection d’une non-conformité. Obtenez l’approbation prévue avant toute fusion ; si l’offre ne la rend pas bloquante, conservez la preuve de revue manuelle et indiquez cette limite.
7. Organiser le test de suppression
Essentiel : définissez avec le binôme quand lancer ce test, qui relit les résultats, quels cas comparer et quels critères imposeraient de conserver la règle. L’exécution répétée n’est pas requise pour terminer les 1 h 30.
Approfondissement : quand le modèle change, créez une PR retirant une instruction devenue peut-être inutile. Comparez avec et sans cette instruction, sur les mêmes cas et plusieurs générations, en consignant le nouveau modèle.
Supprimez la règle seulement si les résultats restent acceptables. En cas de régression, conservez-la et joignez les preuves. Le but n’est pas de réduire le Skill à tout prix : c’est d’éviter qu’il accumule des instructions devenues sans effet.
Bilan et dépannage
| Symptôme | Vérification |
|---|---|
| Workflow absent de la PR | Emplacement .github/workflows/, déclencheur pull_request et filtre de branches, YAML valide dans l’onglet Actions |
| Check requis « Expected — Waiting for status » | Le nom du check requis doit être exactement le nom du job ; le workflow doit se déclencher sur la PR |
opencode: command not found |
Étape d’installation à version fixée, ou runner auto-hébergé préparé |
| Projet généré introuvable | TODO remplacé, commande réellement exécutée, bon dossier de sortie |
| Secrets vides dans le job | PR ouverte depuis un fork, Environment non approuvé, nom du secret |
| Juge ignoré en CI | Disponibilité des variables et politique de validation choisie |
| CODEOWNERS sans effet bloquant | Case « Require review from Code Owners », équipe avec accès en écriture, syntaxe @organisation/equipe, offre du dépôt |
| Fusion possible malgré le rouge | Contournement autorisé pour les administrateurs, ou check non déclaré requis |
| Mauvaise version du Skill évaluée | Checkout de la PR, pas de main ni d’un cache |
Le passage essentiel réunit la PR, main protégé, la preuve d’un blocage rouge
puis d’un retour vert après correction, une génération réelle du checkout de
la PR, son build/MCP et son évaluation (juge exécuté), la revue selon l’offre et
les permissions allow/deny constatées. Indiquez le périmètre exact et le protocole
de suppression prévu ; ni le dataset complet ni les suppressions répétées ne sont
requis ici. Sans infrastructure préparée, génération réelle ou juge, le résultat
reste partiel et non validé. La boucle complète est :
générer → formaliser → évaluer → gouverner.