Federated via graft
18 kB
575 lines
1---
2marp: true
3paginate: true
4backgroundColor: "#fff"
5theme: gaia
6lang: fr-FR
7style: |
8 section { font-size: 25px; }
9 h1 { color: #1a5fb4; }
10 h2 { color: #1a5fb4; }
11 h3 { color: #555; font-size: 24px; margin-bottom: 0.2em; }
12 table { font-size: 21px; }
13 code { font-size: 18px; }
14 section.wide table { font-size: 18px; }
15 section.part { background-color: #1a5fb4 !important; }
16 section.part h1, section.part h2, section.part p { color: #fff !important; }
17---
18
19<!-- _class: lead -->
20
21# Forges & web décentralisé
22
23État des lieux au 10 septembre 2026
24
25---
26
27<!-- _class: lead part -->
28<!-- _backgroundColor: #1a5fb4 -->
29<!-- _color: #ffffff -->
30
31# 1. Cadrage
32
33## code et collaboration
34
35---
36
37## Automatisation de la mise en miroir
38
39**Le transport** du code est résolu depuis 2005 : git est distribué par construction, un dépôt peut exister à plusieurs endroits.
40
41**L'orchestration** n'existe pas. Chaque miroir se configure à la main, instance par instance. Chaque projet écrit elle-même l'intégration continue qui l'entretient.
42
43---
44
45## Éléments non couverts par git
46
47Le véritable obstacle, c'est tout ce qui entoure un dépôt : tickets,
48propositions de modification, relectures, identité, droits.
49
50Ces éléments sont stockés dans la base de données d'un serveur Forgejo, en dehors de git.
51
52[ActivityPub](https://www.w3.org/TR/activitypub/), le protocole de la fédiverse, les fait circuler : il transporte de petits messages (« créé », « aimé », « suivi »), pas des fichiers.
53
54---
55
56<!-- _class: lead part -->
57<!-- _backgroundColor: #1a5fb4 -->
58<!-- _color: #ffffff -->
59
60# 2. État de la fédération dans Forgejo
61
62## Fonctionnalités livrées et fonctionnalités manquantes
63
64---
65
66
67
68## Périmètre fonctionnel de la fédération [Forgejo](https://forgejo.org)
69
70### Fonctionne
71
72- Le favori fédéré : un fork mis en favori transmet ce favori au dépôt
73 d'origine.
74- Le suivi de comptes distants, avec un flux de leur activité.
75- Les fondations techniques : pages d'acteur, découverte, requêtes signées.
76
77### Pas implémenté
78
79Tickets, commentaires et propositions de modification fédérés. Modération et
80contrôle d'accès entre serveurs.
81
82---
83
84## Fonctionnement du favori fédéré
85
86```
87@alice@forgeA --(c'est quoi, ce dépôt ?)--> acteur du dépôt sur forgeB
88 --(« aimé », signé)---------> boîte de réception sur forgeB
89forgeB vérifie la signature --> compteur de favoris +1, favori ajouté au profil d'alice
90```
91
92Le message part à sens unique, il est signé, il ne contient aucun texte :
93rien à modérer.
94
95C'est le test le plus simple pour vérifier que l'échange entre deux serveurs
96fonctionne.
97
98---
99
100## Suivi de comptes entre Forgejo et la fédiverse
101
102Un compte Forgejo peut suivre un compte [Mastodon](https://joinmastodon.org) ou [GoToSocial](https://gotosocial.org), et l'inverse.
103Les commits et les versions apparaissent alors dans un fil social.
104
105C'est la première fonction de fédération visible pour quelqu'un qui ne
106développe pas.
107
108Seuls Forgejo, [Mastodon](https://joinmastodon.org) et [GoToSocial](https://gotosocial.org) sont acceptés pour l'instant.
109
110---
111
112## Risque associé à l'activation de la fédération
113
114Le projet se réserve le droit de casser la fédération sans préavis.
115
116Les autres serveurs mémorisent le domaine et les clés d'une instance dès que la fédération est active. Une rupture peut rendre ce domaine définitivement
117inutilisable pour tout usage ActivityPub.
118
119---
120
121
122
123## Adoption en production
124
125La fédération est désactivée par défaut, et les grandes instances publiques ne
126l'activent pas.
127
128Les points d'entrée de la fédération répondent 404 sur
129[codeberg.org](https://codeberg.org), [disroot](https://disroot.org) et
130[verdigado](https://verdigado.com).
131
132---
133
134<!-- _class: lead part -->
135<!-- _backgroundColor: #1a5fb4 -->
136<!-- _color: #ffffff -->
137
138# 3. Autres solutions
139
140## Des solutions indépendantes d'ActivityPub
141
142---
143
144## Mise en relation de deux forges par miroir
145
146Forgejo push ou pull déjà un dépôt vers une autre instance. Le code passe,
147les tickets non.
148
149Deux projets comblent une partie du manque :
150
151- **[forgesync](https://github.com/lukaswrz/forgesync)** copie tous les dépôts d'une Forgejo vers une autre, tickets et propositions compris.
152- **[gitea-mirror](https://github.com/RayLabsHQ/gitea-mirror)** fait la même chose avec une interface web, et transfère aussi étiquettes, jalons, versions et wikis.
153-
154---
155
156## [F3](https://code.forgejo.org/f3/f3-documentation) : migrer un projet, pas le fédérer
157
158F3 est un format d'export qui contient tout un projet : dépôt, tickets,
159propositions, commentaires, comptes.
160
161Le code de migration de Forgejo s'en sert déjà.
162
163---
164
165
166
167## [Authorized Integrations](https://forgejo.org/docs/latest/user/api/authorized-integrations/) : authentification entre serveurs
168
169Forgejo v16, juillet 2026 : **Authorized Integrations**. La CI d'une instance
170peut désormais s'authentifier sur les dépôts d'une autre, sans secret partagé
171ni jeton à renouveler.
172
173Un lien automatisable, arrivé cette année, sans ActivityPub. Nous l'avons
174testée en conditions réelles entre deux instances, f1 et f2.cyberwild.org.
175
176---
177
178## Mise en place : exécuteur et confiance
179
180Un runner Forgejo (`forgejo-runner`), en mode host et sans Docker, est
181enregistré sur f1. Côté f2, une intégration autorisée fait confiance aux JWT
182émis par l'émetteur de f1, filtrés par une revendication.
183
184```
185forgejo admin user create-authorized-integration \
186 --username forgeadmin \
187 --issuer https://f1.cyberwild.org/api/actions \
188 --claim-eq repository=forgeadmin/testrepo \
189 --scope write:repository \
190 --repo forgeadmin/testrepo
191```
192
193---
194
195## Le CI de f1 demande un jeton OIDC à sa propre instance
196
197```
198jobs:
199 inspect:
200 runs-on: linux-host
201 enable-openid-connect: true
202 steps:
203 - run: |
204 AUD="u:1:11412bf9-...-f06c"
205 curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
206 "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=$AUD"
207```
208
209Revendications du JWT reçu : `iss`, `repository`, `ref`, `workflow`, `sub`. Le
210jeton est signé par f1 et vérifiable par f2 sans contact préalable.
211
212---
213
214## Le jeton sert directement à s'authentifier sur f2
215
216```
217curl -X POST \
218 -H "Authorization: Bearer $JWT" \
219 -H "Content-Type: application/json" \
220 --data '{"title":"Proposition de test depuis le CI de f1","head":"f1-ci-run-6","base":"main"}' \
221 https://f2.cyberwild.org/api/v1/repos/forgeadmin/testrepo/pulls
222```
223
224Aucun jeton n'est stocké côté f2 pour f1 : la confiance repose sur la
225signature du JWT et les règles de revendications, pas sur un secret échangé à
226l'avance.
227
228---
229
230## Résultat : trois actions inter-instances réussies
231
232| Action déclenchée depuis f1 | Résultat sur f2 |
233|---|---|
234| Créer un fichier | HTTP 201 |
235| Créer une branche | HTTP 201 |
236| Ouvrir une proposition de modification | HTTP 201 |
237
238
239---
240
241<!-- _class: lead part -->
242<!-- _backgroundColor: #1a5fb4 -->
243<!-- _color: #ffffff -->
244
245# 4. Comparaison avec d"autres systèmes décentralisés
246
247## Panorama des systèmes comparés
248
249---
250
251
252
253## [ForgeFed](https://forgefed.org) : une spécification distincte de Forgejo
254
255**ForgeFed** est une extension d'ActivityPub pensée pour les forges : dépôts,
256tickets, propositions, versions.
257
258**[Vervis](https://hackage.haskell.org/package/vervis)** en est l'implémentation de référence : une forge complète et
259séparée, pas un module à brancher sur Forgejo.
260
261Forgejo construit sa propre fédération. Le blog ForgeFed n'a rien publié depuis janvier 2025.
262
263---
264
265<!-- _class: wide -->
266
267## Comparaison des modèles techniques
268
269| | [ActivityPub](https://www.w3.org/TR/activitypub/) | [ATProto](https://atproto.com) | [IPFS](https://ipfs.tech) | [Radicle](https://radicle.dev) |
270|---|---|---|---|---|
271| Organisé autour de | le serveur | l'utilisateur | le contenu | le dépôt |
272| Identité | une adresse sur un serveur | un identifiant portable | une clé | une clé, sans compte |
273| Données stockées | sur le serveur | pointées par l'identifiant | partout où copiées | sur les nœuds relais |
274| Droits | signatures, plus l'admin | des clés, on peut déménager | aucun | une liste de clés signée |
275| Point faible | changer de serveur = changer d'identité | une société écrit les règles | pas de contrôle d'accès | sans relais, le projet disparaît |
276
277Radicle range tickets et propositions **dans le dépôt git lui-même** .
278
279---
280
281<!-- _class: wide -->
282
283
284
285## Comparaison des modèles de gouvernance
286
287| | Code | Gouvernance |
288|---|---|---|
289| ActivityPub | Mastodon, PeerTube, GoToSocial : AGPL | spécification W3C figée en 2018. Threads est propriétaire et fédère quand même |
290| ATProto | référence ouverte, auto-hébergeable | une société écrit le protocole, tient l'infrastructure |
291| IPFS | [Kubo](https://github.com/ipfs/kubo) et [Helia](https://github.com/ipfs/helia), MIT | fondation, mais Protocol Labs possède les domaines et arrête son financement le 30 septembre 2026 |
292| Radicle | [Heartwood](https://github.com/radicle-dev/heartwood), MIT et Apache 2.0 | mené par ses mainteneurs, financé par le [DAO Radworks](https://radworks.org) |
293
294Ni ActivityPub ni Radicle ne dépendent d'une société..
295
296---
297
298
299
300## Ponts entre réseaux sociaux décentralisés
301
302**[Bridgy Fed](https://fed.brid.gy)** relie la fédiverse, Bluesky et le web
303ouvert dans les deux sens. **[granary](https://github.com/snarfed/granary)**, en dessous traduit entre les formats.
304
305Ce sont des projets personnels.
306
307---
308
309## Tentatives d'hébergement de git sur IPFS
310
311| Projet | État |
312|---|---|
313| [Gitlawb/node](https://github.com/Gitlawb/node), [ipgit](https://github.com/meyer1994/ipgit) | actifs en 2026, une centaine de favoris chacun |
314| git-remote-ipfs, pando, brig | génération précédente, abandonnée |
315
316Rien n'est utilisable en production.
317
318ATProto s'inspire du même principe : chaque contenu est identifié par une
319empreinte plutôt que par une adresse, comme sur IPFS. Mais contrairement à
320IPFS, ATProto associe ce contenu à des comptes utilisateurs identifiables.
321
322---
323
324
325
326## Portabilité de l'identité
327
328**[Keyoxide](https://keyoxide.org)** produit des preuves d'identité
329décentralisées, déjà utilisées par Forgejo pour ses propres contacts.
330**[did:web](https://w3c-ccg.github.io/did-method-web/)** permet à un domaine de publier une identité portable dès aujourd'hui.
331
332Mais quitter une instance reste synonyme d'abandonner son identité, ses
333contributions et ses relations. Radicle évite ce défaut en fondant l'identité
334sur des clés plutôt que sur un compte.
335
336---
337
338<!-- _class: lead part -->
339<!-- _backgroundColor: #1a5fb4 -->
340<!-- _color: #ffffff -->
341
342# 5. Démonstration pratique
343
344## Radicle testé entre r1 et r2.cyberwild.org
345
346---
347
348## Mise en place : identités et connexion directe entre pairs
349
350Radicle 1.10.3 est installé sur les deux nœuds. Pas de serveur central :
351chaque nœud a sa propre identité (clé Ed25519) et écoute en pair-à-pair.
352Comme r1 et r2 sont sur le même réseau local, la connexion est directe, sans
353tunnel.
354
355```
356rad auth --alias radicle1
357radicle-node --listen 0.0.0.0:8776
358
359# depuis r1, connexion directe au nœud r2
360rad node connect z6Mkfqb...2nbFDJg@192.168.1.108:8776
361```
362
363---
364
365## Un dépôt partagé, sans serveur
366
367```
368# sur r1 : publier un dépôt existant sur le réseau
369rad init --name testrepo --default-branch master --public
370# -> rad:z2YWuPL53okTkr5mgb7WCKsfxG7h8
371
372# sur r2 : récupérer le même dépôt directement depuis r1
373rad clone rad:z2YWuPL53okTkr5mgb7WCKsfxG7h8
374```
375
376Le dépôt, avec ses fichiers, est répliqué intégralement entre les deux nœuds
377via le protocole pair-à-pair, sans jamais passer par un serveur HTTP.
378
379---
380
381## Un patch (l'équivalent Radicle d'une proposition de modification)
382
383```
384# sur r2 : proposer un changement
385git checkout -b feature-dummy4
386git commit -am "add dummy4.txt"
387git push rad HEAD:refs/patches
388# -> Patch 922387e... ouvert
389
390# sur r1 (mainteneur) : relire et fusionner
391rad patch checkout 922387e
392git merge --no-ff feature-dummy4-review
393git push rad master
394```
395
396---
397
398## Résultat : fédération pair-à-pair, sans passerelle HTTP obligatoire
399
400| Étape | Résultat |
401|---|---|
402| Connexion directe r1 et r2 | établie |
403| Réplication du dépôt sur r2 | fichiers identiques |
404| Patch ouvert sur r2, visible sur r1 | propagé automatiquement |
405| Fusion du patch sur r1 | master mis à jour |
406
407Contrairement à Forgejo, aucune passerelle HTTP n'est nécessaire pour fédérer : l'identité et le partage reposent sur les clés des nœuds, pas sur un serveur public, cohérent avec le tableau de comparaison de la section précédente.
408
409---
410
411<!-- _class: lead part -->
412<!-- _backgroundColor: #1a5fb4 -->
413<!-- _color: #ffffff -->
414
415# 6. Faire dialoguer Forgejo et Radicle
416
417## graft : un miroir entre les deux mondes déjà testés
418
419---
420
421## Ce que fait [graft](https://github.com/jeanbaptiste/graft)
422
423Un démon qui synchronise, entre une instance Forgejo et un nœud Radicle : le code, les tickets, et les propositions de modification dans les deux sens.
424
425Il tourne à intervalle régulier, garde son état dans une base SQLite locale, et
426ne force jamais un push. Les vraies divergences sont signalées et laissées à
427l'arbitrage humain plutôt que résolues automatiquement.
428
429Projet récent (GPLv3, quatre commits, aucune version publiée) : une
430démonstration de faisabilité, pas un outil éprouvé.
431
432---
433
434## Relier f1 et r1
435
436```yaml
437sync_interval: 5m
438state_db: /var/lib/graft/state.db
439
440repos:
441 - name: testrepo
442 forgejo:
443 base_url: https://f1.cyberwild.org
444 owner: forgeadmin
445 repo: testrepo
446 token_file: /etc/graft/testrepo.token
447 radicle:
448 rid: rad:z2YWuPL53okTkr5mgb7WCKsfxG7h8
449 http_base_url: https://r1.cyberwild.org
450 rad_home: /home/graft/.radicle
451 sync:
452 git: true
453 issues: true
454 patches: true
455```
456
457Le même dépôt que dans la démonstration Radicle, maintenant relié à f1 plutôt
458qu'à r2 seul.
459
460---
461
462## Ce qui se synchronise et limites actuelles
463
464- **Code** : la branche par défaut, uniquement en avance rapide.
465- **Tickets** : un ticket Forgejo devient un ticket Radicle et inversement,
466 mais seulement à la création.
467- **Propositions de modification** : une PR Forgejo ouvre un patch Radicle en poussant son commit de tête vers `refs/patches`, et inversement un patch Radicle ouvre une PR Forgejo.
468
469Aucun force-push.
470---
471
472## Complémentarité
473
474graft ne tranche pas entre Radicle et Forgejo, il les traite comme
475complémentaires : le même projet existe sur les deux à la fois.
476
477Ce que ça ne résout pas : l'identité reste double, un compte Forgejo d'un
478côté, une clé Radicle de l'autre.
479
480---
481
482<!-- _class: lead part -->
483<!-- _backgroundColor: #1a5fb4 -->
484<!-- _color: #ffffff -->
485
486# 7. Fonctions sociales de graft
487
488## Un tableau de bord, et des ponts vers Discourse, Zulip, Tangled
489
490---
491
492
493
494## Le tableau de bord graft
495
496Une page HTML unique, régénérée à chaque cycle de synchronisation : la liste
497des dépôts, leur nombre de miroirs, et un flux d'activité récente (les 10
498derniers commits, tickets, patches et commentaires).
499
500Volontairement plat : pas de base de données à interroger, pas
501d'authentification, juste un fichier HTML servi par le démon lui-même.
502
503---
504
505
506
507## Une identité fédiverse par dépôt
508
509Chaque série synchronisée (`constitution`, `federation-x`, `graft-source`...)
510obtient sa propre identité ActivityPub : `@série@graft.cyberwild.org`, avec
511WebFinger, Actor et Outbox interrogeables.
512
513Une entrée AT Proto / Bluesky par série existe aussi dans le modèle, prête à
514être activée dès qu'une clé d'app y est associée — « not configured » pour
515l'instant.
516
517---
518
519<!-- _class: lead part -->
520<!-- _backgroundColor: #1a5fb4 -->
521<!-- _color: #ffffff -->
522
523# Ponts vers Discourse, Zulip et Tangled
524
525## Faire vivre l'activité de graft ailleurs que sur une forge
526
527---
528
529
530
531## Pont vers Discourse
532
533Un démon séparé (`graft-discourse`), branché sur le flux ActivityPub de
534graft : chaque série synchronisée devient une catégorie Discourse
535(« Federated Repos »), chaque ticket ou patch un sujet.
536
537Les réponses sur Discourse repartent en commentaire vers le ticket
538Forgejo/Radicle d'origine, marquées « via Fediverse ». Le pont ignore ses
539propres messages pour ne pas boucler.
540
541---
542
543
544
545## Pont vers Zulip
546
547Même principe, décliné pour Zulip (`graft-zulip`) : un canal par série
548(ici `constitution`), un fil (*topic*) par ticket. Zulip distingue le canal
549et le sujet là où Discourse n'a qu'une catégorie et un sujet — les deux
550démons partagent l'essentiel de leur code, seule la couche protocole change.
551
552---
553
554
555
556## Vers Tangled et AT Proto
557
558Tangled (une forge Git construite sur AT Proto/Bluesky) demande une identité
559signée par un PDS pour enregistrer un serveur Git (*knot*). Un PDS a été
560installé pour produire ce DID, `tangled.cyberwild.org` a été enregistré et
561vérifié : la prochaine étape naturelle est d'y raccrocher les mêmes séries
562que sur Forgejo et Radicle.
563
564---
565
566
567
568## Synthèse et questions
569
570**Discussion :**
571
572- Qui modère une proposition de modification abusive venue d'un autre
573 serveur ?
574- Les miroirs et F3 marchent déjà. ActivityPub résout-il le vrai problème ?
575- Radicle et Forgejo : rivaux, ou deux moitiés de la même réponse ?