Introduction
Un contributeur propose une modification avec un titre et une description. Une tâche de build transforme ces métadonnées en artefact de prévisualisation. L’intégration continue (CI) consiste à lancer automatiquement ces tâches à l’arrivée de modifications. Un exécuteur est le programme chargé de les réaliser. Ici, vous lancez vous-même un petit exécuteur local fourni.
Personnes et événements sont synthétiques. L’exécuteur utilise réellement Bash dans un conteneur jetable, sans réseau ni identifiants de déploiement. production dans release.conf est une valeur de test locale : elle ne déploie rien. L’atelier modélise substitution de texte et exécution shell, pas les déclencheurs ou permissions d’une plateforme hébergée. Le terminal CI Workshop est votre espace de maintenance ; Topology explique le flux et affiche les canaux réels après actualisation.
Vous lancerez un build ordinaire, suivrez une injection, modifierez deux petits fichiers et retesterez la conservation exacte des métadonnées. Une familiarité élémentaire avec le terminal suffit ; JSON et la syntaxe Bash nécessaires sont expliqués avant utilisation.
Exécuter un build ordinaire
Dans cette étape, vous découvrirez le résultat attendu avant d’examiner le problème : le titre exact devient un artefact et le canal reste preview.
Sélectionnez l’onglet CI Workshop dans l’interface du laboratoire pour commencer cette étape.
Passez à l’onglet CI Workshop. pwd affiche le répertoire courant ; ls liste ses fichiers. L’espace de travail est /home/labex/project/ci-workshop.
Passez à l’onglet CI Workshop avant d’exécuter la commande suivante.
pwd
ls
cat affiche un fichier texte. Un objet JSON entoure des champs nommés d’accolades ; deux-points relient chaque nom à sa valeur. Les chaînes utilisent des guillemets doubles. Dans une chaîne, \n représente un saut de ligne. Lisez l’événement ordinaire :
cat events/ordinary.json
Son title est Improve search results. body est une description multiligne. Ces valeurs viennent d’un contributeur : le build doit les traiter comme des données, pas comme des commandes fiables.
Lisez la petite définition de tâche et son script :
cat job.json
cat build.sh
| Élément | Sens dans cet exécuteur local |
|---|---|
script |
Fichier Bash à exécuter, actuellement build.sh |
env |
Mappage de noms d’environnement vers des chaînes ; vide {} actuellement |
{{event.title}} |
Remplacer ce marqueur exact par le titre avant le démarrage de Bash |
{{event.body}} |
Même remplacement pour la description |
artifact.txt |
Fichier de métadonnées créé par le build |
release.conf |
Canal initialisé à preview pour chaque exécution |
Bash lit des instructions shell. TITLE="..." affecte une variable, sans espace autour de =. "$TITLE" développe sa valeur en un seul argument, conservant espaces et sauts de ligne. printf '%s' écrit une chaîne sans ajouter de saut ; les apostrophes maintiennent %s littéral. > redirige la sortie vers un fichier et remplace son contenu. Le point-virgule sépare deux commandes. set -euo pipefail arrête le script pour les erreurs courantes de commandes, de variables non définies et de pipelines ; cela n’empêche pas l’injection.
ci est la commande de l’exécuteur fourni. run prend un nom d’événement sans .json et un nouveau nom de répertoire de sortie. Chaque exécution commence avec une configuration preview neuve :
ci run ordinary first
Attendez channel=preview et exit=0. Zéro signifie que Bash s’est terminé correctement. Inspectez le script généré, l’artefact et la configuration avec show :
ci show first
L’artefact apparaît comme chaîne JSON, "Improve search results", afin de rendre visibles plus tard les sauts de ligne. C’est le vrai contenu du fichier, pas un indicateur simulé. La dernière section doit afficher preview. Passez à l’onglet Topology et actualisez : la ligne first lit ce même fichier.
Réutiliser first avec run provoque volontairement une erreur de répertoire existant : les anciennes observations ne sont pas écrasées. Choisissez un nom neuf comme first-again. Un build échoué conserve aussi son script et build.log dans runs/NAME pour le diagnostic.
Suivre la substitution dangereuse
Dans cette étape, vous verrez des données devenir du code et modifier le canal dans une démonstration isolée.
Sélectionnez l’onglet CI Workshop dans l’interface du laboratoire pour commencer cette étape.
Le flux est événement → tâche → source shell générée → Bash → artefact. Le danger est la substitution avant l’analyse des guillemets par Bash. Les guillemets doubles protègent le développement d’une variable dans une commande déjà analysée ; ils ne protègent pas une valeur brute insérée dans la source avant analyse.
Lisez l’événement de démonstration inoffensif fourni :
Passez à l’onglet CI Workshop avant d’exécuter la commande suivante.
cat events/hostile.json
Le title contient un guillemet double, un point-virgule, printf, un autre point-virgule et #. Dans Bash, le guillemet termine la chaîne initiale, le point-virgule lance une commande et # commente la fin de la ligne. Ce printf ne change que le release.conf synthétique de cette exécution. \" encode un guillemet en JSON ; il ne le sécurise pas lors d’une insertion ultérieure dans du code shell.
Exécutez l’événement dans un nouvel espace :
ci run hostile demo
ci show demo
Attendez channel=production, bien que l’exécuteur ait initialisé preview. Repérez le printf entre les points-virgules de generated.sh : Bash l’a réellement exécuté. L’artefact peut ne contenir que Update, le reste étant devenu de la syntaxe plutôt que des données. C’est le défaut à corriger.
demo est distinct de first ; aucune exécution ne modifie job.json ni build.sh. Passez à l’onglet Topology et actualisez la page pour comparer les canaux. Une ligne production signifie une fixture modifiée, jamais une publication réelle. N’exécutez pas vous-même le texte de l’événement dans votre shell de maintenance.

Le risque général est décrit dans l’explication GitHub sur l’injection de script. Notre syntaxe de marqueurs et notre format sont volontairement plus petits que GitHub Actions ; le mécanisme commun est la substitution avant analyse.
Transmettre la valeur comme donnée
Dans cette étape, vous garderez le texte hors du code shell tout en conservant espaces, guillemets et lignes multiples.
Sélectionnez l’onglet CI Workshop dans l’interface du laboratoire pour commencer cette étape.
Une variable d’environnement est une chaîne nommée transmise à un nouveau processus. Le mappage env peut la définir directement, sans générer d’affectation shell. En JSON, un mappage est un objet entre accolades. Définissez BUILD_TITLE depuis {{event.title}}, puis laissez Bash développer "$BUILD_TITLE" à l’exécution. Bash ne réinterprète pas les guillemets, points-virgules, $() ou accents graves contenus dans cette valeur comme de nouvelles commandes. N’utilisez ni eval ni bash -c avec cette valeur : ils l’analyseraient à nouveau.
Remplaçons deux fichiers avec des here-documents. cat > filename <<'JSON' écrit les lignes suivantes jusqu’à une ligne contenant seulement JSON. Les guillemets du délimiteur empêchent le shell de maintenance de développer $ et les autres syntaxes. Copiez le bloc complet, délimiteur final inclus. Il remplace tout le fichier et permet donc aussi de réparer une faute de frappe.
Passez à l’onglet CI Workshop avant d’exécuter la commande suivante.
cat > job.json <<'JSON'
{
"script": "build.sh",
"env": {
"BUILD_TITLE": "{{event.title}}"
}
}
JSON
Remplacez maintenant le script. BASH remplit la même fonction d’écriture littérale. Le script utilise directement la variable et ne contient plus de marqueur de contributeur.
cat > build.sh <<'BASH'
set -euo pipefail
printf '%s' "$BUILD_TITLE" > artifact.txt
printf 'channel='; cat release.conf
BASH
Relisez les deux fichiers avec cat. Une virgule ou accolade oubliée donne une erreur JSON ; un nom d’environnement mal écrit, une variable non définie. Réécrivez le bloc complet concerné et réessayez. Une ancienne exécution reflète l’ancien script ; choisissez un nouveau nom :
ci run ordinary repaired
ci show repaired
La source générée contient maintenant "$BUILD_TITLE", pas les caractères du titre. L’artefact contient toujours Improve search results et le canal est preview.
Lisez les fixtures de ponctuation et de texte multiligne :
cat events/quotes.json
cat events/multiline.json
\n représente un vrai saut de ligne ; le dernier \n doit lui aussi subsister. L’apostrophe de O'Brien et les guillemets d’un titre sont des données légitimes. Le même mappage transmet un body multiligne : la référence devient {{event.body}}, mais la règle des guillemets autour de la variable reste la même. Vous réutiliserez ce mécanisme dans le défi des notes de version.
ci test normal exécute votre tâche et votre script inchangés sur les événements ordinaires, ponctués et multilignes dans des répertoires temporaires jetables. Il compare les octets exacts et vérifie preview. Seuls ces répertoires sont supprimés ; vos fichiers et exécutions sauvegardées restent intacts.
ci test normal
Chaque fixture doit afficher exact metadata; channel=preview. Supprimer la ponctuation, aplatir les lignes, coder un titre en dur, refuser tous les événements ou sauter le build fait échouer ce contrôle de fonctionnalité. Un échec nomme la fixture : lisez-la et corrigez vos deux fichiers avant de réessayer.
Retester la frontière du build
Dans cette étape, vous confirmerez que la même tâche corrigée conserve les métadonnées normales et empêche l’effet démontré.
Sélectionnez l’onglet CI Workshop dans l’interface du laboratoire pour commencer cette étape.
Relancez la fixture hostile avec un nouveau nom de sortie :
Passez à l’onglet CI Workshop avant d’exécuter la commande suivante.
ci run hostile repaired-hostile
ci show repaired-hostile
L’artefact doit maintenant contenir le titre hostile entier comme texte. Les guillemets et points-virgules apparaissent dans la chaîne JSON et release.conf reste preview. Les anciennes observations de demo sont inchangées car elles appartiennent à un autre espace.
Une autre fixture contient $() et des accents graves : ces formes réalisent une substitution de commande lorsqu’elles apparaissent dans une source shell. Dans une valeur d’environnement développée entre guillemets doubles, leurs caractères restent des données. Lisez-la :
cat events/substitution.json
Testez les cinq fixtures avec les mêmes fichiers soumis :
ci test all
ordinary, quotes, multiline, hostile et substitution doivent préserver les métadonnées exactes et preview, puis afficher le message de nettoyage. Les tests contrôlent de vrais fichiers et une véritable exécution Bash, pas une phrase de journal ni un résultat inventé secure=true. Le contrôle de fin répète ces tests temporaires sans modifier tâche, script ou exécutions sauvegardées.
Si seul le cas hostile échoue, cherchez un marqueur restant dans la source ou une réanalyse de la valeur. Si ponctuation ou multilignes échouent, vérifiez printf '%s' avec une variable entre guillemets doubles. Ne supprimez pas les entrées difficiles : conserver les métadonnées légitimes est exigé. Passez à l’onglet Topology et actualisez la page pour voir repaired-hostile à côté de l’ancien demo.

Résumé
Vous avez suivi les métadonnées jusqu’à Bash via un exécuteur local, reproduit une modification de configuration isolée et réparé la frontière avec un mappage d’environnement et un développement entre guillemets. Les tests exacts ont préservé ponctuation, multilignes et canal de prévisualisation. Appliquez ensuite ce raisonnement aux notes de version.



