hawser — Extensions, plugins, authentification & CI/CD
Comment hawser reste ouvert à ses frontières : il orchestre git, les forges et les outils de build — il ne les réimplémente jamais. Tout ce qui est spécifique à une tâche (systèmes de build, forges, étapes personnalisées) s’enfiche depuis l’extérieur via des interfaces stables et sans surprise. Se combine avec ARCHITECTURE.md (internes) et COMPLIANCE.md (preuves).
Règles de conception, dans l’ordre :
- Natif git. Si c’est déjà un fichier texte que git comprend (lock, alternates, gitdir), utilisez-le. Jamais de base de données cachée.
- Orchestrer, ne pas réimplémenter. haw décide quoi et quand ; les outils de l’utilisateur font le comment. haw ne connaît rien de CMake, Bazel, Yocto, Jenkins — il délègue au shell.
- Tuyaux Unix. Vue humaine dans le TUI ; vue machine via
--format jsonsur stdout. Tout ce que haw affiche, un script peut le consommer. - Échec ouvert. Une forge inconnue, un jeton manquant, un plugin absent dégrade une seule fonctionnalité — cela ne bloque jamais
sync/tree/status.
1. Mécanismes d’extension
Quatre couches, de la moins coûteuse d’abord. Choisissez la plus basse qui résout le problème.
1.1 run — exécuter n’importe quelle commande sur tous les dépôts
La trappe de sortie universelle. Exécution parallèle de commandes sur chaque dépôt (filtrable par groupe).
haw run 'git fetch --tags'
haw run --group firmware 'cmake --build build'
Aucun plugin nécessaire pour les 80 % des cas : « faire X dans chaque dépôt ».
1.2 Hooks — exécuter des scripts à des points du cycle de vie
Hooks de style git déclenchés autour des opérations haw. Les scripts se trouvent dans .haw/hooks/ (ou sont déclarés dans le manifeste) et reçoivent le contexte via l’environnement + JSON sur stdin.
| Hook | Se déclenche |
|---|---|
pre-sync / post-sync | avant/après un haw sync |
pre-lock / post-lock | autour de la (re)génération du lockfile |
post-switch | après haw switch <stack> |
post-change-start | après la création d’une branche de changeset |
Exemple — installer un hook git qui rejette un commit lorsque haw.lock est périmé (la garantie d’intégrité « à la git ») :
haw hooks install # écrit un pre-commit qui exécute `haw verify --lock`
1.3 Commandes par dépôt dans le manifeste
Déclarez comment un dépôt est construit/testé afin que haw puisse le piloter sans coder en dur le moindre outil de build.
[repo.app-mqtt]
remote = "github"
repo = "app-mqtt.git"
rev = "release/2.x"
build = "cmake --build build --preset release" # haw délègue simplement au shell
test = "ctest --test-dir build"
haw reste agnostique quant au système de build : CMake, Bazel, Meson, Cargo, Make — tout n’est que des chaînes de caractères.
1.4 Plugins de sous-commande — haw-<name> sur le PATH
Le modèle git / cargo / kubectl. Un haw foo … qui n’est pas intégré exécute haw-foo depuis le PATH, en transmettant les arguments et le contexte de l’espace de travail (via l’environnement + HAW_JSON sur stdin). La communauté livre haw-jira, haw-bazel, haw-sbom-scan sans toucher au cœur.
- Découverte : tout exécutable nommé
haw-*sur lePATH. - Contrat : haw transmet la racine de l’espace de travail, le stack courant et les dépôts résolus au format JSON sur stdin ; le plugin affiche les résultats au format JSON sur stdout ; haw les rend ou les redirige.
- Isolation : les plugins sont des processus distincts — un plugin défectueux ne peut pas faire planter haw.
Le cœur reste petit. haw maintient le moteur de composition + orchestration ; les intégrations (chaque particularité de forge, chaque outil de build, chaque tracker) vivent dans les plugins et les hooks.
1.5 Interface machine — --format json
Chaque commande de lecture (status, tree, change status, verify, evidence) propose --format json avec un schéma stable et versionné, plus des codes de sortie stables. C’est ce que consomment la CI, les tableaux de bord et les plugins. Le TUI est pour les humains ; le JSON est pour les machines.
2. Authentification (fonctionne sur n’importe quel dépôt)
Le déclic d’adoption : l’authentification de transport est gratuite ; l’authentification de forge est sur adhésion. haw n’invente jamais son propre magasin d’identifiants.
2.1 Transport (clone / fetch / push) — zéro configuration
haw délègue au git de l’utilisateur, il hérite donc automatiquement de l’authentification git existante :
- Clés SSH via
ssh-agent(le défaut en entreprise/embarqué). - HTTPS via les assistants
git credential(Git Credential Manager,osxkeychain,cache).
Fonctionne avec n’importe quel hôte — GitHub, GitLab, Gitea, Bitbucket, auto-hébergé, SSH nu — sans intégration. Si git clone fonctionne, haw sync fonctionne. C’est exactement ainsi que repo et west s’authentifient : ils ne le font pas.
2.2 API de forge (ouvrir/lire PR-MR, statut CI) — jeton, uniquement à l’usage
Seules les fonctionnalités PR/MR nécessitent des identifiants d’API, résolus dans cet ordre :
- Environnement :
GITHUB_TOKEN/GH_TOKEN,GITLAB_TOKEN,HAW_FORGE_TOKEN. - Réutiliser le jeton stocké d’un CLI existant :
gh auth token,glab auth. git credentialpour les jetons HTTPS.- Flux d’appareil OAuth (
haw auth login) — affiche un code à saisir dans un navigateur, sans redirection localhost, fonctionne sans interface/via SSH ; le jeton est stocké dans le trousseau de l’OS. C’est le modèlegh/docker login/aws sso.
- Auto-hébergé : URL de base d’API configurable par forge (GitHub Enterprise, GitLab self-managed). Obligatoire pour le marché cible.
- Isolé (air-gapped) : jeton via env/fichier uniquement ; pas de flux navigateur, pas de sortie (voir COMPLIANCE §6).
- Ne jamais persister un jeton dans
haw.toml,haw.lock, les journaux ou l’état de l’espace de travail (COMPLIANCE §5.6). Masquez les chaînes ayant l’apparence d’un identifiant.
2.3 Détection de forge
haw met en correspondance l’URL distante de chaque dépôt → forge (GitHub/GitLab/…) via le trait Forge. Hôte inconnu → le transport fonctionne toujours ; seules les fonctionnalités PR/MR se désactivent pour ce dépôt. Échec ouvert.
3. Intégration CI/CD
haw est conçu pour être piloté par des pipelines, pas seulement par des humains.
3.1 Checkout reproductible
haw sync --locked # matérialise l'arbre exact de haw.lock ; échoue si le lock est manquant/périmé
haw verify # vérifie que arbre sur disque == lock (porte de dérive) ; non nul en cas de dérive
--locked est le contrat CI : pas de résolution de rev, pas de non-déterminisme réseau — le lock committé fait loi. Déterministe sur Linux/macOS/Windows (COMPLIANCE §8).
3.2 Portes via JSON + codes de sortie
haw status --format json | jq -e '.repos[] | select(.dirty or .drift)' && exit 1 || true
Codes de sortie stables : 0 ok, valeurs non nulles distinctes pour dérive / échec de vérification / échec de signature.
3.3 Jetons en CI
Injectez les jetons de forge comme secrets CI (GITHUB_TOKEN dans Actions, variables masquées dans GitLab). Pas de connexion interactive dans les pipelines. Le transport utilise la clé SSH du runner ou un jeton de déploiement.
3.4 Cache de partage d’objets (CI rapide)
haw sync --locked --shared # git alternates contre un cache miroir préchauffé ; fichier texte, pas de liens symboliques
Mettez le miroir en cache entre les exécutions pour éviter de re-cloner de grands arbres de dépôts.
3.5 Preuves dans le pipeline de version
haw evidence --out haw-evidence.tar.zst # baseline + SBOM + provenance + enregistrement de config de l'outil
Attachez à la version pour le paquet de données de certification (COMPLIANCE §3, §4).
3.6 GitHub Actions (ébauche)
- uses: actions/checkout@v4
- run: cargo install hawser
- run: haw sync --locked --shared
env: { GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} }
- run: haw verify
- run: haw run --group firmware 'cmake --build build --preset release'
3.7 GitLab CI (ébauche)
build:
script:
- haw sync --locked
- haw verify
- haw run 'make'
variables: { GITLAB_TOKEN: $CI_JOB_TOKEN }
4. Où cela s’inscrit dans le plan
Ajouts au plan par phases dans ARCHITECTURE.md §6 ; chaque élément est cadré pour garder le cœur petit et pousser les intégrations vers les frontières. État au 2026-07-15 : tout ce qui suit est livré, à l’exception de la connexion par flux d’appareil OAuth (reportée — ARCHITECTURE DR-14) et de la charge utile SBOM/provenance complète de haw evidence (bundle actuel : manifeste, lock, journal d’audit, JSON de statut, enregistrement de l’outil).
| Capacité | Couche | Phase |
|---|---|---|
run en parallèle sur les dépôts (alias forall) | cœur | 3 |
--format json + schémas/codes de sortie stables | cœur | 1→3 |
| Transport de forge (natif git, zéro configuration) | haw-git | 1 |
| Jetons d’API de forge (env / réutilisation gh-glab) | haw-forge | 1 (GH), 3 (GL) |
| Connexion par flux d’appareil OAuth + trousseau | haw-forge | reporté (DR-14) |
| URL de base de forge auto-hébergée | haw-forge | 3 |
Hooks de cycle de vie (pre/post-sync, …) | cœur + haw hooks | 4 |
haw hooks install (pre-commit lock périmé) | cœur | 4 |
Commandes build/test par dépôt dans le manifeste | modèle de manifeste | 4 |
Plugins de sous-commande (haw-<name> sur le PATH) | dispatch hawser | 5 |
| Contrat JSON stdin/stdout des plugins | cœur | 5 |
Porte de dérive haw verify (CI) | cœur | 1→2 |
Bundle haw evidence | cœur | 3 |
Cache de partage d’objets --shared | haw-git | 2 |
Contrainte directrice : le cœur ne développe jamais de dépendance forte envers un outil de build, un tracker ou un système de CI spécifique. Ceux-ci arrivent sous forme de hooks, de commandes par dépôt ou de plugins haw-*.