FND-004 : Infrastructure d’ingénierie : pipeline CI/CD et automatisation des versions
Prise en charge de v0.7.0 → v1.0.0 · Type : Architecture · Rév. 8
Référence canonique · Ratifiée par l’équipe · Rév. 8 Discussion RFC originale : #5579
Une note à l’équipe avant que vous lisiez ceci.
Ce document porte sur l’échafaudage autour du code : l’automatisation qui le compile, le teste, l’audite et le livre. Cet échafaudage est invisible quand il fonctionne bien et pénible quand ce n’est pas le cas. La plupart des équipes n’y pensent pas avant que cela ne devienne pénible, et à ce moment-là, il s’est transformé en quelque chose que personne ne comprend entièrement. Cette RFC est une tentative d’anticiper cela. Si vous n’avez jamais réfléchi en profondeur au CI/CD auparavant, c’est un bon point de départ. Si c’est déjà le cas, vous reconnaîtrez les schémas. Dans les deux cas, l’objectif est le même : un pipeline qui donne confiance à l’équipe sans lui faire obstacle.
Table des matières
- Context : Les pipelines sont une architecture
- Évaluation honnête : où nous en sommes aujourd’hui
- La conception du pipeline cible
- Analyse de sécurité comme cycle de vie
- Automatisation de la version alignée sur le modèle de distribution
- Standards que nous devrions adopter
- Feuille de route par phases
- Ce que cela signifie pour les contributeurs
Historique des révisions
| Rév | Date | Résumé |
|---|---|---|
| 1 | 2026-04-09 | Brouillon initial |
| 2 | 2026-06-04 | Remplacement du verrouillage séquentiel du formatage et du linting par un verrouillage limité au formatage, suivi de tâches Rust obligatoires exécutées en parallèle (#7111) |
| 3 | 2026-06-10 | Exécutions de master approuvées requises pour initialiser les caches utilisés par les pull requests (#7355) |
| 4 | 2026-06-21 | La cible de compilation et de publication du plugin est passée de wasm32-wasip1 à wasm32-wasip2 (#8061) |
| 5 | 2026-06-30 | Suppression de l’artefact de bureau et des obligations associées au pipeline de publication (#8544) |
| 6 | 2026-07-04 | Restauration de l’artefact de bureau et de ses obligations liées au pipeline de publication (#8565) |
| 7 | 2026-08-07 | Les instructions concernant actions/attest-build-provenance ont été remplacées par une attestation directe des artefacts avec actions/attest (#9717) |
| 8 | 2026-08-20 | Suppression de la classe obsolète de bibliothèques matérielles des directives de publication indépendante après le départ de aardvark-sys et zeroclaw-robot-kit de l’espace de travail (#10152) |
1. Contexte : Les pipelines sont une architecture
La RFC d’architecture (#5574) a établi un principe : les dépendances pointent vers l’intérieur, et la structure est appliquée par le compilateur. Le même principe s’applique au pipeline qui entoure le code. Un pipeline n’est pas une simple automatisation : c’est un ensemble de décisions architecturales sur ce en quoi vous avez confiance, ce que vous vérifiez, quand vous le vérifiez, et comment vous livrez.
Ces décisions ont des conséquences. Un pipeline conçu pour une application monolithique résistera activement à un micro-noyau. Une porte de sécurité sans processus de tri bloquera tout ou sera contournée. Un workflow de release centré sur un seul binaire ne survivra pas à un modèle de distribution avec cinq types d’artefacts. Il ne s’agit pas de problèmes de configuration, mais de problèmes de conception, qui méritent la même attention intentionnelle que l’architecture du code.
Le pipeline actuel s’est développé de manière réactive, de la même façon que loop_.rs a atteint 9 500 lignes. Personne n’a choisi l’état actuel. Il s’est accumulé. La PR #5559, la première étape majeure de la transition vers le micronoyau, a révélé plusieurs endroits où les hypothèses du pipeline ne tiennent plus. C’est un signal utile. Cela signifie que c’est exactement le bon moment pour s’arrêter, évaluer et concevoir intentionnellement.
Ce RFC fait pour le pipeline ce que le RFC sur l’architecture fait pour la base de code : il nomme ce qui existe, identifie les problèmes structurels et propose une voie à suivre cohérente avec l’orientation du projet.
2. Évaluation honnête : Où nous en sommes aujourd’hui
Cette section n’est pas une critique. C’est un diagnostic. Le pipeline actuel reflète les décisions qui semblaient pertinentes à l’époque. L’objectif est de le comprendre suffisamment bien pour l’améliorer.
2.1 Deux workflows effectuant le même travail
Le dépôt dispose actuellement de deux workflows distincts qui s’exécutent lors des pull requests adressées à master :
checks-on-pr.yml, sous l’appellation « Quality Gate »ci-run.yml, intitulé « CI »
Les deux exécutent indépendamment les jobs Lint, Build, Test et Security sur chaque PR. Cela signifie que chaque PR déclenche deux exécutions complètes du pipeline en parallèle. Pour un monolithe avec une seule unité de compilation, cela était coûteux mais gérable. Pour un espace de travail multi-crate, cela double un budget CI déjà important sans apporter de signal supplémentaire.
La duplication a un coût plus subtil que les minutes de calcul : lorsqu’un contrôle échoue dans un workflow mais pas dans l’autre, les contributeurs ne savent pas à quel résultat se fier. Lorsqu’un nouveau contrôle doit être ajouté, il doit l’être à deux endroits. Lorsqu’un comportement doit être modifié, il doit l’être à deux endroits. Avoir deux sources de vérité pose le même problème qu’avoir deux sources de vérité dans le code.
2.2 Les hypothèses relatives aux exécutables uniques sont intégrées partout
L’automatisation des releases, release-stable-manual.yml, release-beta-on-push.yml, publish-crates.yml, pub-aur.yml, pub-homebrew-core.yml, pub-scoop.yml, discord-release.yml, tweet-release.yml, a été conçue autour de l’hypothèse qu’une release est un seul binaire. On le compile, on le signe, on le pousse vers les gestionnaires de paquets, et on l’annonce.
La RFC d’architecture définit un modèle de distribution avec cinq types d’artefacts distincts : le binaire du noyau (plusieurs cibles de plateforme), le binaire du noyau en variante matérielle, le binaire de la passerelle, les fichiers de plugins WASM et l’installateur de bureau Tauri. Aucun des workflows de publication actuels ne prend en compte cette structure. Lorsque la transition d’architecture atteindra la Phase 3 et la Phase 4, chacun de ces workflows devra être modifié, à moins qu’ils ne soient repensés dès maintenant en tenant compte de ce modèle.
2.3 Analyse de sécurité sans cycle de vie
Le job de sécurité exécute cargo audit en tant que contrôle strict. Si une vulnérabilité est présente dans l’arbre des dépendances, le contrôle échoue et la PR ne peut pas être fusionnée. L’intention est correcte. La mise en œuvre présente un problème structurel.
cargo audit signale tous les avis de la chaîne de dépendances : vulnérabilités actives, crates non maintenues et avis informatifs. Il ne fait pas la distinction entre :
- Une vulnérabilité critique dans une crate que le projet appelle activement
- Une vulnérabilité dans une dépendance transitive à trois niveaux de profondeur dans une fonctionnalité optionnelle
- Un avertissement « non maintenu » pour une crate dont le projet dépend indirectement via une bibliothèque tierce qu’il ne peut pas contrôler.
- Un avis préexistant qui était présent avant l’ouverture de cette PR
Lorsque toutes ces situations entraînent une erreur critique, le filtre devient inefficace. Face à ce bruit, la réponse réaliste consiste à abaisser le seuil du filtre, ignorer les échecs ou désactiver les vérifications. Ces trois approches rendent le projet moins sécurisé, et non plus. Un filtre de sécurité qui ne peut pas être maintenu ne le sera pas.
La PR #5559 a fait émerger douze avis RUSTSEC-2026 simultanément. Sans outil pour distinguer un « nouvel avis introduit par cette PR » d’un « avis préexistant présent sur master », l’auteur de la PR et les relecteurs ne peuvent pas savoir si cette PR a détérioré la posture de sécurité.
2.4 Le script de vérification stricte des deltas
ci-run.yml inclut un job qui exécute scripts/ci/rust_strict_delta_gate.sh, un script personnalisé qui compare la sortie de clippy avec le SHA de base de la PR. Le concept est judicieux : vous voulez savoir si cette PR a introduit de nouveaux avertissements, et pas seulement si des avertissements existent dans le code. L’implémentation fonctionne bien pour les PR petites et ciblées sur un crate monolithique.
Une PR qui déplace 260 000 lignes de code à travers 10 nouvelles crates, en modifiant des centaines de fichiers, place ce script dans un territoire pour lequel il n’a pas été conçu. La surface de fichiers modifiés est trop importante pour qu’une comparaison incrémentale produise un signal significatif. Le script doit comprendre la structure du workspace : en particulier, le fait qu’une modification d’un fichier dans crates/zeroclaw-channels/ doit être évaluée dans le contexte de cette crate, et non de la racine.
2.5 Pas de mise en cache ni de portée sensibles à l’espace de travail
La configuration actuelle du cache Rust (Swatinem/rust-cache) est adaptée pour un seul crate. Pour un espace de travail multi-crate, l’efficacité du cache dépend de la compréhension des crates qui ont changé et des artefacts compilés qui peuvent être réutilisés. Sans un balisage explicite de l’espace de travail, une modification dans n’importe quel crate peut invalider les caches dont dépendent d’autres crates, entraînant une recompilation complète à chaque PR.
Plus significativement, il n’existe aucun mécanisme permettant d’exécuter l’intégration continue (CI) uniquement sur les crates affectées par un changement donné. Une PR qui corrige une faute de frappe dans zeroclaw-tool-call-parser n’a pas besoin de reconstruire et de retester la passerelle. À mesure que l’espace de travail évolue vers le modèle de plus de 30 crates envisagé dans la RFC sur l’architecture, le coût de l’exécution du pipeline complet pour chaque PR devient un obstacle significatif à la contribution.
2.6 L’épinglage des actions est une bonne pratique : mais non documentée
Les workflows existants épinglent bien les actions à des SHA de commit complets, ce qui constitue une bonne pratique de sécurité qu’il convient de saluer. Mais il n’existe aucune politique documentée expliquant pourquoi, aucun processus pour déterminer quand ces SHA doivent être mis à jour, et aucune automatisation pour les maintenir à jour. Un bon comportement sans politique est fragile : le prochain contributeur qui ajoutera une étape de workflow ne saura peut-être pas pourquoi l’épinglage par SHA est important et utilisera à la place un tag mutable.
3. La conception du pipeline cible
3.1 Un pipeline, une source de vérité
Les deux workflows parallèles devraient être consolidés en un pipeline unique et bien structuré. La distinction entre « Quality Gate » et « CI » n’a pas de sens pour les contributeurs : il s’agit dans les deux cas de vérifications qu’une PR doit réussir. La consolidation crée un seul endroit où trouver les résultats des vérifications, un seul endroit à mettre à jour lorsque le comportement change, et un seul endroit pour documenter ce que fait chaque vérification et pourquoi.
Le pipeline consolidé suit une structure par étapes où une vérification de formatage très peu coûteuse s’exécute en premier, puis les jobs gourmands en Rust se répartissent en parallèle. Le lint reste obligatoire, mais il ne devrait pas prendre inutilement en otage le préchauffage du cache de build et de test lorsque l’objectif est de raccourcir le chemin critique vers le vert :
Stage 1: Format (cheap serial gate)
└── cargo fmt --check
Post-format quality gate (parallel, required)
└── cargo clippy --workspace --all-targets -- -D warnings
└── Docs quality gate
Post-format Build + Check (parallel, 5–15 min)
└── Build matrix (Linux x86_64, macOS ARM, Windows)
└── cargo check --features ci-all
└── cargo check --no-default-features (kernel profile)
└── cargo check --target i686 (32-bit)
Post-format Test (parallel, 10–30 min)
└── cargo nextest run --workspace
Post-format Security (parallel)
└── cargo deny check (licenses, sources, advisories)
└── Advisory triage gate (see §4)
Required Gate
└── Composite status — branch protection requires only this job
Les jobs post-formatage s’exécutent en parallèle une fois le formatage validé. Cela signifie qu’une erreur de formatage échoue rapidement sans gaspiller de ressources de calcul sur un build qui sera de toute façon abandonné, tandis que clippy, build, test et security peuvent progresser ensemble sur des PR correctement formatées. Le job Required Gate agrège tous les résultats afin que la protection de branche n’ait à suivre qu’un seul nom de job, un modèle déjà présent dans les deux workflows actuels.
3.2 Clippy conscientieux de l’espace de travail
L’invocation actuelle de clippy s’exécute avec l’ensemble de fonctionnalités par défaut du crate racine. L’invocation correcte pour un espace de travail multi-crate est :
sh
cargo clippy --workspace --all-targets -- -D warnings
Le drapeau --workspace garantit que chaque crate de l’espace de travail est analysée, et non seulement celle du répertoire racine. Le drapeau --all-targets inclut les tests, les benchmarks et les exemples. Combiné à --features ci-all pour la vérification conditionnelle, cela offre une vue complète.
Le concept de lint en delta strict, qui consiste à vérifier si cette PR a introduit de nouveaux avertissements plutôt que de vérifier si des avertissements existent tout court, mérite d’être préservé. L’implémentation devrait passer d’un script shell comparant la sortie de diff à une invocation appropriée prenant en compte le workspace, qui évalue chaque crate affecté indépendamment. Une approche plus simple et plus fiable : exiger que --workspace -D warnings passe sans erreur en permanence, rendant ainsi le concept de delta implicite. Si la base de référence est toujours propre, toute PR qui introduit un avertissement échoue. Cela élimine entièrement le besoin d’un script de comparaison personnalisé.
3.3 Détection des crates modifiées
Pour un espace de travail comptant plus de 30 crates, exécuter l’ensemble de la suite de tests à chaque PR, indépendamment des modifications apportées, est une perte de temps. Le pipeline devrait détecter quelles crates ont été affectées par la PR et limiter l’exécution des tests en conséquence.
Le mécanisme est simple : comparer les fichiers modifiés dans la PR avec la liste des membres de l’espace de travail, identifier les crates contenant des fichiers modifiés, étendre l’ensemble pour inclure toutes les crates qui dépendent d’une crate modifiée (impact en aval), et exécuter les tests uniquement pour cet ensemble.
PR changes: crates/zeroclaw-tool-call-parser/src/lib.rs
Affected crates:
zeroclaw-tool-call-parser ← directly changed
zeroclaw-misc ← depends on it
zeroclaw (root) ← depends on it
Not affected:
zeroclaw-channels ← no dependency path
zeroclaw-memory ← no dependency path
zeroclaw-providers ← no dependency path
Cela est implémenté à l’aide de cargo metadata pour extraire le graphe des dépendances et d’un petit script pour le parcourir. L’ensemble complet des tests continue de s’exécuter lors des poussées vers master et sur les branches de release. Les PRs exécutent uniquement le sous-ensemble des crates concernées.
3.4 Stratégie de mise en cache
Swatinem/rust-cache prend en charge la mise en cache sensible aux espaces de travail via sa configuration workspaces. La clé de cache doit inclure la liste des membres de l’espace de travail afin que l’ajout d’un nouveau crate invalide correctement sans invalider les caches des crates non liées.
- utilisations: Swatinem/rust-cache@<sha>
avec:
espaces de travail: |
. -> target
cache-on-failure: true
save-if: ${{ github.ref == 'refs/heads/master' }}
Étant donné que les sauvegardes de cache sont limitées à refs/heads/master, le workflow doit s’exécuter sur les pushes master approuvés. Les PRs lisent le cache initialisé depuis master mais n’écrivent pas d’artefacts de branche concurrents. Cela évite l’instabilité du cache lorsque plusieurs PRs sont ouvertes simultanément, tout en permettant aux exécutions post-fusion de préchauffer les caches de build Linux, macOS et Windows pour le prochain cycle de revue.
4. Analyse de sécurité tout au long du cycle de vie
4.1 Le problème avec une porte binaire
Une porte de sécurité qui bloque en cas d’avis, sans contexte, entraîne l’équipe à considérer les échecs de sécurité comme du bruit. C’est l’opposé de l’effet souhaité. L’objectif est d’avoir une porte qui soit :
- Signal fort : les échecs signifient quelque chose de réel que cette PR a affecté
- Actionnable : le contributeur sait quoi faire et pourquoi
- Durable : la barrière peut être maintenue sans intervention manuelle constante
cargo audit seul ne permet pas d’y parvenir. cargo deny le fait.
4.2 cargo-deny comme outil de sécurité principal
cargo deny est un successeur plus performant de cargo audit pour la politique de dépendances au niveau du projet. Il applique :
- Advisories : base de données RUSTSEC, avec la possibilité de refuser (deny), d’avertir (warn) ou d’ignorer explicitement certains avis avec une justification documentée
- Licences : garantit que toutes les dépendances utilisent des licences acceptables (important à mesure que l’espace de travail grandit et que de nouveaux contributeurs ajoutent des dépendances)
- Sources : garantit que les dépendances proviennent uniquement de registres approuvés (crates.io, path, git avec des hôtes spécifiques)
- Doublons : avertit lorsque plusieurs versions du même crate apparaissent dans l’arbre des dépendances
La fonctionnalité clé est la section [advisories] de deny.toml, qui permet des exclusions explicites et justifiées. Cette approche transforme l’analyse de sécurité d’un simple succès/échec binaire en une politique documentée et auditable. Chaque avis ignoré dispose d’une justification écrite et d’un ticket de suivi. Les relecteurs peuvent voir exactement quels avis sont supprimés et pourquoi. Lorsqu’un avis supprimé prend de l’ampleur (un nouvel exploit est découvert, un correctif est disponible), le ticket de suivi sert de rappel.
4.3 Processus de tri des avis
Lorsqu’un nouvel avis de sécurité apparaît dans l’arborescence des dépendances, que ce soit à partir d’une PR ou de la mise à jour quotidienne de la base de données des avis, le processus est le suivant :
- Classifier l’avis : Le crate concerné est-il une dépendance directe ou transitive ? ZeroClaw appelle-t-il le chemin de code vulnérable ? Existe-t-il une version corrigée disponible ?
- Déterminer la réponse :
- Vulnérabilité dans une dépendance directe avec une correction disponible → mettez à jour la dépendance, aucune exclusion n’est nécessaire
- Vulnérabilité dans une dépendance transitive avec une correction disponible → épingler la version transitive ou attendre que la dépendance directe soit mise à jour ; ouvrir un ticket de suivi
- Avis de non-maintenance, aucune exploitation active → ajouter à la liste d’ignorance de
deny.tomlavec justification et numéro de suivi - Vulnérabilité critique sans correctif → évaluer la solution de contournement ; peut bloquer la PR
- Enregistrez la décision dans
deny.tomlavec l’ID de l’avis, un bref raisonnement et un lien vers le problème de suivi.
Ce processus signifie qu’une PR comme #5559, qui expose douze avis de sécurité préexistants, ne fait pas échouer le contrôle de qualité sans contexte. Les avis de sécurité sont triés, ceux qui sont préexistants sont documentés, et le contrôle de qualité ne signale que les nouveaux avis de sécurité non triés introduits par la PR.
4.4 Analyse quotidienne des avis
Les avis de sécurité sont publiés en continu. Une PR qui a passé la porte de sécurité lors de sa fusion peut contenir une vulnérabilité publiée la semaine suivante. Le pipeline doit inclure un exécution planifiée quotidienne contre master qui vérifie la base de données des avis et ouvre un GitHub Issue si de nouveaux avis non triés sont trouvés.
on:
calendrier:
- cron: '0 9 * * *' # 09:00 UTC quotidiennement
Cela sépare le cycle de triage des avis de sécurité du cycle de fusion des PR. Les contributeurs ne sont pas bloqués par les avis de sécurité apparus après la rédaction de leur PR. L’équipe de sécurité (ou la personne en rotation) traite les résultats du scan quotidien comme une tâche de maintenance régulière.
5. Automatisation de la version alignée sur le modèle de distribution
5.1 Le déséquilibre actuel
La RFC §4.4.2 sur l’architecture définit les artefacts de version suivants :
| Artefact | Cible de construction | Publié à |
|---|---|---|
| Binaire du noyau (standard) | x86_64-linux-musl, aarch64-linux-gnu, armv7-linux-gnueabihf, x86_64-darwin, aarch64-darwin, x86_64-windows | Releases GitHub |
| Binaire du noyau (matériel) | aarch64-linux-gnu, armv7-linux-gnueabihf | Releases GitHub |
| Binaire de passerelle | Même matrice de plateforme | Releases GitHub |
| Fichiers de plugin WASM | wasm32-wasip2 | Registre des plugins |
| Installateur de bureau | x86_64 + aarch64, macOS/Windows/Linux | GitHub Releases, magasins de la plateforme |
Les workflows de publication actuels ne connaissent qu’un seul de ces éléments : le binaire standard. Les autres n’existent pas encore dans l’automatisation. C’est approprié pour le moment : le système de plugins n’est pas encore complet. Mais les workflows de publication devraient être conçus avec ce modèle à l’esprit afin de ne pas devoir être réécrits à chaque introduction d’un nouveau type d’artefact.
5.2 Structure d’un pipeline de release
Le pipeline de version cible est un graphe orienté de jobs, et non un workflow monolithique :
version-bump (release-plz PR merged)
│
├── build-kernel-standard (matrix: 6 targets)
├── build-kernel-hardware (matrix: 2 ARM targets + hardware flags)
├── build-gateway (matrix: 6 targets)
├── build-plugins-wasm (matrix: all plugin crates → wasm32-wasip2)
└── build-desktop (matrix: macOS, Windows, Linux AppImage/deb)
│
├── publish-github-release (attaches all kernel + gateway binaries)
├── publish-plugin-registry (uploads WASM files)
├── publish-aur (kernel binary for Arch Linux)
├── publish-homebrew (kernel binary for macOS)
├── publish-scoop (kernel binary for Windows)
└── announce (Discord, social)
Chaque tâche de build est indépendante et peut être déclenchée séparément pour les versions de correctif urgent (hotfix). Les tâches de publication dépendent de la réussite de toutes les tâches de build pertinentes. La tâche d’annonce s’exécute en dernier.
Cette structure signifie qu’une version uniquement des plugins (une nouvelle version de channel-discord.wasm) peut exécuter uniquement les tâches build-plugins-wasm et publish-plugin-registry sans déclencher une reconstruction complète du noyau. Une version de correctif du noyau exécute les tâches build-kernel-* et les tâches de publication en aval sans toucher au registre des plugins.
5.3 Release-plz pour la gestion de version consciente de l’espace de travail
La RFC d’architecture §4.4.1 spécifie release-plz comme l’outil d’automatisation des versions. release-plz s’intègre directement dans ce modèle de pipeline :
- Lors d’un push sur
master,release-plzouvre une « Pull Request de version » qui met à jour la version de l’espace de travail, met à jour les journaux de modifications à partir de l’historique des commits conventionnels et liste tous les crates qui ont changé depuis la dernière version. - Lorsque la PR de version est fusionnée, le pipeline de version se déclenche automatiquement.
- Les crates avec
version.workspace = truesont versionnées ensemble ; la cratezeroclaw-api, versionnée indépendamment, est traitée séparément conformément à la politique de versionnement
La PR de version sert de point de contrôle pour la revue : l’équipe voit exactement quelle version sera publiée et ce que contient le journal des modifications avant toute publication. Cela remplace les incréments manuels de version et le workflow version-sync.yml.
5.4 Politique d’épinglage des actions
Les workflows actuels épinglent déjà les actions aux SHA de commit complets. Cela est correct et devrait être formalisé en tant que politique explicite afin de survivre au roulement des contributeurs :
Politique : Toutes les références uses: dans les fichiers de workflow doivent être épinglées à un SHA de commit complet, accompagné d’un commentaire de version. Les balises modifiables (@v4, @main, @latest) ne sont pas autorisées. Aucune exception.
# Correct
- utilisations: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Non autorisé
- utilisations: actions/checkout@v4
- utilisations: actions/checkout@main
Justification : Une balise mutable est une promesse faite par un tiers selon laquelle le comportement de l’action ne changera pas. Cette promesse a été violée à maintes reprises dans l’écosystème GitHub Actions. L’utilisation d’un hachage SHA garantit que le workflow s’exécute exactement avec le code qui a été examiné, indépendamment des modifications ultérieures apportées par l’auteur de l’action. Cela est particulièrement important pour les actions disposant de permissions d’écriture ou ayant accès à des secrets.
Le processus de mise à jour : utilisez dependabot ou renovate configuré pour GitHub Actions afin d’ouvrir des PR lorsque de nouvelles versions de SHA sont disponibles. L’équipe examine et fusionne ces PR. Cela permet de maintenir les actions à jour sans nécessiter de surveillance manuelle.
6. Les normes que nous devrions adopter
6.1 SLSA : Cadre de sécurité de la chaîne d’approvisionnement
SLSA (Supply-chain Levels for Software Artifacts, prononcé « salsa ») est un cadre de travail développé par Google et adopté dans l’ensemble de l’industrie pour sécuriser la chaîne d’approvisionnement des logiciels. Il définit quatre niveaux d’intégrité de la construction, allant du basique à l’hermétique.
Pour l’échelle et la taille de l’équipe actuelles de ZeroClaw, SLSA Niveau 2 est l’objectif approprié :
- Les builds s’exécutent sur une plateforme CI hébergée (déjà le cas, GitHub Actions)
- Les scripts de construction sont sous contrôle de version (déjà vrai)
- La provenance de la construction est générée et jointe aux artefacts de la version (l’étape à ajouter)
La provenance SLSA de niveau 2 signifie que chaque artefact de version est livré avec une attestation cryptographiquement signée qui enregistre : quel commit de source l’a produit, quel workflow l’a généré, et que le workflow s’est exécuté sur la plateforme attendue. Les utilisateurs et les gestionnaires de paquets peuvent vérifier cette attestation. Elle comble l’écart entre « nous disons que ce binaire provient de cette source » et « ce binaire provient de manière prouvée de cette source ».
GitHub Actions prend nativement en charge la génération de provenance SLSA de niveau 2 via l’action actions/attest. Son ajout nécessite une étape par tâche de build.
6.2 Conventional Commits (Déjà implicite, à formaliser)
La politique de versionnement de la RFC sur l’architecture et l’intégration avec release-plz dépendent toutes deux du format des commits conventionnels pour la génération du journal des modifications. La RFC sur la gouvernance fait déjà référence aux conventions de titre des PR. Cette RFC formalise le lien : le format des commits conventionnels dans les messages de commit et les titres des PR est une exigence, et non une suggestion, car il constitue l’entrée qui alimente la génération automatisée du journal des modifications.
Les catégories qui comptent pour le journal des modifications de ZeroClaw :
| Préfixe | Section des modifications | Impact de la version |
|---|---|---|
feat: | Nouvelles fonctionnalités | MINEUR |
fix: | Corrections de bugs | PATCH |
feat!: ou fix!: | Modifications incompatibles | MAJEUR |
chore: | Maintenance | Aucune entrée de version |
docs: | Documentation | Aucune entrée de version |
perf: | Performance | PATCH |
sécurité : | Correctifs de sécurité | PATCH (au minimum) |
Le CI applique cette règle via un job de validation du titre des PR, qui vérifie que le titre respecte le format des commits conventionnels avant que tout autre contrôle ne s’exécute.
6.3 Workflows réutilisables
À mesure que le nombre de crates et de types d’artefacts augmente, la duplication des workflows devient un problème de maintenance. GitHub Actions prend en charge les workflows réutilisables : un workflow qui peut être appelé depuis un autre workflow comme une fonction. La matrice de build, l’analyse de sécurité et l’exécuteur de tests devraient chacun être extraits sous forme de workflows réutilisables.
.github/
workflows/
ci.yml ← PR checks (calls reusable workflows)
release.yml ← Release pipeline (calls reusable workflows)
daily-audit.yml ← Scheduled security scan
_workflows/ ← Reusable workflow definitions
build-rust.yml ← Parameterised build job
test-workspace.yml ← Parameterised test job
security-scan.yml ← cargo-deny invocation + triage
publish-release.yml ← Parameterised publish job
Un workflow réutilisable est appelé avec des paramètres :
tâches:
build-kernel:
utilisations: ./.github/_workflows/build-rust.yml
avec:
cible: x86_64-unknown-linux-musl
fonctionnalités: ""
profil: dist
Cela signifie que le workflow CI et le workflow de publication partagent la même définition de build. Une correction apportée au processus de build s’applique partout simultanément.
7. Feuille de route par phases
La migration du pipeline suit la même approche Strangler Fig que la migration du code : construire parallèlement, migrer progressivement, sans jamais compromettre la passerelle existante.
Phase 1 · v0.7.0 : « Rationalise »
Thème : Un pipeline, un signal propre, sans duplication.
Pourquoi cette phase : La transition architecturale est déjà en cours. Le pipeline doit cesser de s’y opposer avant que cela ne rende le travail d’implémentation plus difficile que nécessaire.
Livrables de la phase 1
D1 : Consolider checks-on-pr.yml et ci-run.yml en un seul workflow
Fusionnez les deux workflows de PR en un seul. Le workflow consolidé conserve la structure par étapes définie dans §3.1. La distinction de nommage entre Quality Gate et CI disparaît. Il n’y a plus qu’un seul workflow, un seul ensemble de résultats, et un seul endroit où consulter.
Le job de la porte composite (CI Required Gate) est conservé. La protection de branche continue d’exiger uniquement ce job unique. Cela signifie que la structure interne du pipeline peut évoluer sans qu’il soit nécessaire de mettre à jour les règles de protection de branche.
D2 : Remplacer cargo audit par cargo deny
Ajoutez deny.toml à la racine du dépôt. Configurez les sections [advisories], [licenses] et [sources]. Résolvez tous les avis RUSTSEC actuels sur master : mettez à jour ce qui peut l’être, documentez ce qui ne peut pas l’être avec une justification et des problèmes de suivi associés. Le contrôle de sécurité doit être propre sur master avant que cette phase ne soit terminée.
D3 : Corriger l’invocation de clippy prenant en compte le workspace
Remplacez cargo clippy --all-targets -- -D warnings par cargo clippy --workspace --all-targets -- -D warnings dans le workflow consolidé. Supprimez le script rust_strict_delta_gate.sh : avec --workspace -D warnings toujours appliqué de manière stricte, le concept de delta est implicite.
D4 : Formaliser la politique d’épinglage des actions
Ajoutez une note SECURITY.md et une vérification CI qui valide que toutes les références uses: dans les fichiers de workflow sont épinglées à un SHA. Ajoutez une configuration dependabot pour les mises à jour des GitHub Actions.
D5 : Ajouter un workflow d’analyse quotidienne des avis de sécurité
Ajoutez daily-audit.yml en tant que workflow planifié exécutant cargo deny check advisories sur master à 09:00 UTC. En cas d’échec, ouvrez un GitHub Issue contenant les détails de l’avis d’alerte en utilisant gh issue create.
Indicateurs de succès pour la phase 1
- Fichier de workflow de PR unique, sans duplication
- Les passes de sécurité sont propres sur
masteravec un tri documenté pour tous les avis préexistants. cargo clippy --workspaces’exécute et passe sans erreur.- Aucune référence à un tag d’action modifiable dans aucun fichier de workflow
- Analyse quotidienne des avis opérationnelle
Phase 2 · v0.8.0 : « Prise en charge des espaces de travail »
Thème : Le pipeline comprend l’espace de travail. Retour rapide pour des modifications ciblées.
Pourquoi cette phase : À la version 0.8.0, l’espace de travail aura encore grandi. Exécuter l’intégralité du pipeline à chaque PR deviendra de plus en plus coûteux. Les contributeurs de zeroclaw-tool-call-parser ne devraient pas attendre 30 minutes pour qu’une passerelle soit reconstruite.
Livrables de la phase 2
D1 : Détection des crates modifiées
Ajoutez un script scripts/ci/affected_crates.sh qui utilise cargo metadata pour construire le graphe de dépendances et renvoie l’ensemble des crates affectées par les fichiers modifiés de la PR. Le workflow CI utilise cette sortie pour limiter l’exécution des tests.
D2 : Portée des tests par crate
Ajoutez les indicateurs --package à cargo nextest en fonction de la sortie des crates affectées. Les tests complets de l’espace de travail continuent de s’exécuter sur les poussées vers master et la version nightly. Les PRs exécutent uniquement le sous-ensemble affecté.
D3 : Configuration du cache adaptée à l’espace de travail
Mettez à jour la configuration de Swatinem/rust-cache avec un balisage explicite de l’espace de travail et save-if: ${{ github.ref == 'refs/heads/master' }} pour éviter les problèmes de cache dus aux PR concurrentes.
D4 : Extraire les définitions de workflow réutilisables
Extrayez les jobs de build, de test et de sécurité dans des fichiers de workflow réutilisables sous .github/_workflows/. Mettez à jour ci.yml et le squelette de release.yml pour les appeler.
Indicateurs de succès pour la phase 2
- Une PR qui ne touche que
zeroclaw-tool-call-parserexécute les tests de ce crate et de ses dépendances, et non l’ensemble de l’espace de travail. - Taux de hit de cache sur CI supérieur à 80 % pour les builds incrémentaux
- Flux de travail réutilisables en place pour les tâches de build, de test et de sécurité
Phase 3 · v0.9.0 : “Pipeline de publication”
Thème : Automatisation de la publication qui correspond au modèle de distribution.
Pourquoi cette phase : La phase 3 de la RFC d’architecture extrait zeroclaw-gw en tant que binaire distinct. La première version multi-artefacts est réalisée ici. Le pipeline de publication doit être prêt avant d’être nécessaire.
Livrables de la phase 3
D1 : Introduction de release-plz et suppression de version-sync.yml
Configurez release-plz pour l’espace de travail. Les crates applicatives de l’espace de travail utilisent version.workspace = true. La crate zeroclaw-api, versionnée indépendamment, utilise ses propres paramètres de publication. Le workflow version-sync.yml est retiré.
D2 : Créer le pipeline de release structuré dans release.yml
Implémenter le graphe de publication orienté de la §5.2 : build-kernel-standard, build-kernel-hardware, build-gateway, avec les jobs de publication en aval. Les jobs de build des plugins sont des stubs : ils réussissent sans rien faire jusqu’à la Phase 4.
D3 : Ajouter la provenance SLSA niveau 2
Ajoutez actions/attest à chaque tâche de build. Les attestations de provenance sont jointes aux ressources des versions GitHub. Documentez les instructions de vérification dans SECURITY.md.
D4 : Retirer les workflows de publication redondants
Fusionnez release-stable-manual.yml, release-beta-on-push.yml, pub-aur.yml, pub-homebrew-core.yml, pub-scoop.yml, discord-release.yml, tweet-release.yml dans le pipeline structuré release.yml. Ces workflows ont évolué de manière indépendante ; le pipeline structuré les remplace par un flux unique et auditable.
Indicateurs de succès pour la phase 3
release-plzouvre et gère les PR de version surmaster- Les binaires du noyau et de la passerelle sont construits et publiés à partir d’un seul workflow
release.yml. - Provenance SLSA de niveau 2 attachée à tous les actifs de la version
- Flux de travail de publication redondants supprimés
Phase 4 · v1.0.0 : « Platform Pipeline »
Thème : Le pipeline déploie la plateforme, pas seulement le binaire.
Pourquoi cette phase : v1.0.0 est la version à partir de laquelle les plugins WASM peuvent être publiés. Le pipeline doit gérer la publication des plugins, le téléchargement sur le registre et l’installateur de bureau Tauri en tant qu’artefacts de version de premier ordre.
Livrables de la phase 4
D1 : Activer les jobs de build du plugin WASM
Implémenter build-plugins-wasm dans le pipeline de release. Chaque crate de plugin compile vers wasm32-wasip2 dans un job dédié. Les manifestes des plugins sont générés et signés. Le job publish-plugin-registry téléverse les fichiers WASM signés vers le registry de plugins.
D2 : Compilation et publication du programme d’installation de bureau
Terminez les tâches de build Tauri pour macOS, Windows et Linux. L’installateur inclut les binaires du noyau et de la passerelle. Les informations d’identification pour la signature de code sur macOS et Windows sont documentées en tant que secrets de dépôt requis, avec un guide d’installation.
D3 : Publier les normes CI/CD dans docs/book/src/maintainers/ci-and-actions.md
La politique d’épinglage des actions, le processus de tri des avis, les exigences relatives aux commits conventionnels et la structure du pipeline de release définis dans cette RFC sont extraits vers docs/book/src/maintainers/ci-and-actions.md en tant que référence permanente. Cette RFC reste le registre historique des décisions ; le document extrait est celui que les contributeurs consultent au quotidien.
D4 : Intégration des contributeurs pour le pipeline
Ajoutez une section Exécution de CI en local à la documentation de contribution qui montre aux contributeurs comment reproduire les vérifications de CI sur leur propre machine avant de pousser les modifications :
sh
# Ce que CI exécute — lancez ces étapes avant de pousser
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo nextest run --workspace
cargo deny check
Indicateurs de performance pour la phase 4
- Les fichiers de plugins WASM sont publiés dans le registre dans le cadre du pipeline de release.
- L’installateur de bureau Tauri est construit et publié automatiquement lors de la version.
docs/book/src/maintainers/ci-and-actions.mdexiste et couvre l’épinglage des actions, le tri des avis de sécurité et les commits conventionnels.- Un contributeur peut reproduire localement tous les contrôles CI avec quatre commandes
8. Ce que cela signifie pour les contributeurs
Pour les contributeurs qui ouvrent des PR
Le pipeline consolidé signifie un seul endroit où consulter les résultats. L’étape 1 (formatage et lint) échoue rapidement : si vous avez une erreur de formatage, vous le savez en deux minutes sans attendre une compilation. Si l’étape 1 réussit, les étapes de compilation et de test s’exécutent en parallèle et vous obtenez un résultat complet en moins de 30 minutes pour la plupart des modifications.
L’exigence de commits conventionnels sur les titres de PR est appliquée par la CI. Si votre titre ne correspond pas au format, le job de lint échoue immédiatement avec un message clair. Ce n’est pas de la bureaucratie : c’est la donnée d’entrée qui génère automatiquement le changelog, ce qui signifie que les releases sont publiées plus rapidement et avec moins de travail manuel.
Pour les contributeurs qui ajoutent des dépendances
Chaque nouvelle dépendance passe par cargo deny. Si la dépendance présente une vulnérabilité connue, une licence inacceptable ou provient d’une source non fiable, la sécurité échoue et vous indique pourquoi. C’est intentionnel. La bonne réponse est d’enquêter sur la dépendance, et non de supprimer la vérification.
Si une dépendance comporte un avis de sécurité qui ne peut pas être corrigé (une dépendance transitive sans mise à jour disponible), le processus de triage décrit dans la section 4.3 est la méthode pour documenter cette situation. Ouvrez un ticket de suivi, ajoutez l’entrée d’ignorance dans deny.toml avec votre justification, puis passez à la suite. La posture de sécurité est maintenue par la documentation, et non en espérant que l’avis de sécurité disparaisse.
Pour les contributeurs qui ajoutent des fichiers de workflow
Les nouveaux fichiers de workflow suivent trois règles sans exception :
- Toutes les références
uses:sont épinglées par SHA avec un commentaire de version. - De nouveaux jobs sont extraits en tant que workflows réutilisables s’ils dupliquent la logique d’un job existant.
- De nouveaux jobs liés à la version sont ajoutés à
release.yml, et non sous forme de nouveaux fichiers de workflow.
En cas de doute, demandez avant d’ajouter. Les fichiers de workflow sont des modifications à haut risque : ils s’exécutent avec des permissions élevées sur l’infrastructure CI et peuvent affecter la sécurité de la chaîne d’approvisionnement. Ils méritent le même niveau de revue que src/security/.
Pour les mainteneurs
Le scan quotidien des avis de sécurité fait de la sécurité une tâche de maintenance régulière, et non une situation de crise. Lorsqu’un nouvel avis est déclenché, le processus de tri est bien défini et le résultat est documenté dans deny.toml et un ticket de suivi. Les réviseurs peuvent auditer l’historique complet des décisions relatives aux avis dans l’historique git.
La PR de version issue de release-plz constitue l’étape de validation de la version. Avant toute publication, l’équipe examine la version, le journal des modifications et la liste des crates modifiées. Les versions ne sont pas publiées par hasard.
Annexe A : Glossaire
SLSA (Supply-chain Levels for Software Artifacts) : Un cadre de sécurité qui définit des niveaux d’intégrité de build, de la provenance de base aux builds entièrement hermétiques. Développé par Google et adopté par l’OpenSSF. Le niveau 2 est l’objectif pratique pour la plupart des projets open source : plateforme de build hébergée, scripts de build sous contrôle de version, provenance signée jointe aux artefacts.
Provenance : Un enregistrement signé cryptographiquement indiquant l’origine d’un artefact de build : quel commit source, quel workflow, quelle plateforme. Permet aux utilisateurs et aux gestionnaires de paquets de vérifier qu’un binaire a bien été produit à partir de la source revendiquée par le processus revendiqué.
cargo deny : Un plugin Cargo qui applique une politique de dépendances selon trois dimensions : les avis de sécurité (provenant de la base de données RustSec), les licences logicielles (par rapport à une liste d’autorisation définie) et les registres sources (garantissant que les dépendances proviennent uniquement d’emplacements approuvés). Plus configurable que cargo audit et mieux adapté à la gestion de politiques à grande échelle.
release-plz : Un outil d’automatisation de releases pour l’écosystème Rust qui crée des « Release PRs » lors d’un push sur la branche par défaut, en incrémentant les versions et en générant les changelogs à partir de l’historique des conventional commits. Compatible avec les workspaces ; détecte quels crates ont été modifiés et lesquels nécessitent de nouvelles versions.
Workflow réutilisable : Un workflow GitHub Actions qui peut être appelé comme un job depuis un autre workflow, avec des paramètres. Permet de définir une seule fois la logique de build, de test et de sécurité, puis de l’appeler à la fois depuis le pipeline de PR et le pipeline de release.
Conventional commits : une convention de messages de commit (feat:, fix:, chore:, etc.) qui permet la génération automatisée de changelogs et la détermination des versions. C’est l’entrée utilisée par des outils comme release-plz pour décider si une release correspond à une montée de version patch, mineure ou majeure.
Strangler Fig (dans le contexte des pipelines) : La même stratégie de migration appliquée aux workflows : construire la nouvelle structure de pipeline en parallèle de l’existante, migrer les jobs un par un, retirer les anciens fichiers seulement lorsque la nouvelle structure est complète et vérifiée.
Annexe B : Lectures complémentaires
-
SLSA Framework : La spécification complète et les guides d’implémentation pour les niveaux de sécurité de la chaîne d’approvisionnement.
-
Documentation de
cargo deny: référence de configuration pour le fichier de politiquedeny.toml, incluant toutes les options d’avis de sécurité, de licences et de sources. -
Documentation
release-plz: Configuration de l’espace de travail, personnalisation du format du changelog et guide d’intégration de GitHub Actions. -
Renforcement de la sécurité de GitHub Actions : conseils officiels sur l’épinglage par SHA, les permissions des jetons et les risques liés à la chaîne d’approvisionnement dans les workflows Actions.
-
Spécification Conventional Commits : La spécification complète du format des messages de commit et de sa relation avec le versionnage sémantique.
-
OpenSSF Scorecard : un outil automatisé qui évalue les projets open source sur leurs pratiques de sécurité, notamment l’épinglage des dépendances, la protection des branches, les exigences de revue de code, et plus encore. Utile comme évaluation de référence et comme indicateur de santé continu.