···11+---
22+marp: true
33+paginate: true
44+backgroundColor: "#fff"
55+theme: gaia
66+lang: fr-FR
77+style: |
88+ section { font-size: 25px; }
99+ h1 { color: #1a5fb4; }
1010+ h2 { color: #1a5fb4; }
1111+ h3 { color: #555; font-size: 24px; margin-bottom: 0.2em; }
1212+ table { font-size: 21px; }
1313+ code { font-size: 18px; }
1414+ section.wide table { font-size: 18px; }
1515+ section.part { background-color: #1a5fb4 !important; }
1616+ section.part h1, section.part h2, section.part p { color: #fff !important; }
1717+---
1818+1919+<!-- _class: lead -->
2020+2121+# Forges & web décentralisé
2222+2323+État des lieux au 10 septembre 2026
2424+2525+---
2626+2727+<!-- _class: lead part -->
2828+<!-- _backgroundColor: #1a5fb4 -->
2929+<!-- _color: #ffffff -->
3030+3131+# 1. Cadrage
3232+3333+## code et collaboration
3434+3535+---
3636+3737+## Automatisation de la mise en miroir
3838+3939+**Le transport** du code est résolu depuis 2005 : git est distribué par construction, un dépôt peut exister à plusieurs endroits.
4040+4141+**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.
4242+4343+---
4444+4545+## Éléments non couverts par git
4646+4747+Le véritable obstacle, c'est tout ce qui entoure un dépôt : tickets,
4848+propositions de modification, relectures, identité, droits.
4949+5050+Ces éléments sont stockés dans la base de données d'un serveur Forgejo, en dehors de git.
5151+5252+[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.
5353+5454+---
5555+5656+<!-- _class: lead part -->
5757+<!-- _backgroundColor: #1a5fb4 -->
5858+<!-- _color: #ffffff -->
5959+6060+# 2. État de la fédération dans Forgejo
6161+6262+## Fonctionnalités livrées et fonctionnalités manquantes
6363+6464+---
6565+6666+
6767+6868+## Périmètre fonctionnel de la fédération [Forgejo](https://forgejo.org)
6969+7070+### Fonctionne
7171+7272+- Le favori fédéré : un fork mis en favori transmet ce favori au dépôt
7373+ d'origine.
7474+- Le suivi de comptes distants, avec un flux de leur activité.
7575+- Les fondations techniques : pages d'acteur, découverte, requêtes signées.
7676+7777+### Pas implémenté
7878+7979+Tickets, commentaires et propositions de modification fédérés. Modération et
8080+contrôle d'accès entre serveurs.
8181+8282+---
8383+8484+## Fonctionnement du favori fédéré
8585+8686+```
8787+@alice@forgeA --(c'est quoi, ce dépôt ?)--> acteur du dépôt sur forgeB
8888+ --(« aimé », signé)---------> boîte de réception sur forgeB
8989+forgeB vérifie la signature --> compteur de favoris +1, favori ajouté au profil d'alice
9090+```
9191+9292+Le message part à sens unique, il est signé, il ne contient aucun texte :
9393+rien à modérer.
9494+9595+C'est le test le plus simple pour vérifier que l'échange entre deux serveurs
9696+fonctionne.
9797+9898+---
9999+100100+## Suivi de comptes entre Forgejo et la fédiverse
101101+102102+Un compte Forgejo peut suivre un compte [Mastodon](https://joinmastodon.org) ou [GoToSocial](https://gotosocial.org), et l'inverse.
103103+Les commits et les versions apparaissent alors dans un fil social.
104104+105105+C'est la première fonction de fédération visible pour quelqu'un qui ne
106106+développe pas.
107107+108108+Seuls Forgejo, [Mastodon](https://joinmastodon.org) et [GoToSocial](https://gotosocial.org) sont acceptés pour l'instant.
109109+110110+---
111111+112112+## Risque associé à l'activation de la fédération
113113+114114+Le projet se réserve le droit de casser la fédération sans préavis.
115115+116116+Les 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
117117+inutilisable pour tout usage ActivityPub.
118118+119119+---
120120+121121+
122122+123123+## Adoption en production
124124+125125+La fédération est désactivée par défaut, et les grandes instances publiques ne
126126+l'activent pas.
127127+128128+Les points d'entrée de la fédération répondent 404 sur
129129+[codeberg.org](https://codeberg.org), [disroot](https://disroot.org) et
130130+[verdigado](https://verdigado.com).
131131+132132+---
133133+134134+<!-- _class: lead part -->
135135+<!-- _backgroundColor: #1a5fb4 -->
136136+<!-- _color: #ffffff -->
137137+138138+# 3. Autres solutions
139139+140140+## Des solutions indépendantes d'ActivityPub
141141+142142+---
143143+144144+## Mise en relation de deux forges par miroir
145145+146146+Forgejo push ou pull déjà un dépôt vers une autre instance. Le code passe,
147147+les tickets non.
148148+149149+Deux projets comblent une partie du manque :
150150+151151+- **[forgesync](https://github.com/lukaswrz/forgesync)** copie tous les dépôts d'une Forgejo vers une autre, tickets et propositions compris.
152152+- **[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.
153153+-
154154+---
155155+156156+## [F3](https://code.forgejo.org/f3/f3-documentation) : migrer un projet, pas le fédérer
157157+158158+F3 est un format d'export qui contient tout un projet : dépôt, tickets,
159159+propositions, commentaires, comptes.
160160+161161+Le code de migration de Forgejo s'en sert déjà.
162162+163163+---
164164+165165+
166166+167167+## [Authorized Integrations](https://forgejo.org/docs/latest/user/api/authorized-integrations/) : authentification entre serveurs
168168+169169+Forgejo v16, juillet 2026 : **Authorized Integrations**. La CI d'une instance
170170+peut désormais s'authentifier sur les dépôts d'une autre, sans secret partagé
171171+ni jeton à renouveler.
172172+173173+Un lien automatisable, arrivé cette année, sans ActivityPub. Nous l'avons
174174+testée en conditions réelles entre deux instances, f1 et f2.cyberwild.org.
175175+176176+---
177177+178178+## Mise en place : exécuteur et confiance
179179+180180+Un runner Forgejo (`forgejo-runner`), en mode host et sans Docker, est
181181+enregistré sur f1. Côté f2, une intégration autorisée fait confiance aux JWT
182182+émis par l'émetteur de f1, filtrés par une revendication.
183183+184184+```
185185+forgejo admin user create-authorized-integration \
186186+ --username forgeadmin \
187187+ --issuer https://f1.cyberwild.org/api/actions \
188188+ --claim-eq repository=forgeadmin/testrepo \
189189+ --scope write:repository \
190190+ --repo forgeadmin/testrepo
191191+```
192192+193193+---
194194+195195+## Le CI de f1 demande un jeton OIDC à sa propre instance
196196+197197+```
198198+jobs:
199199+ inspect:
200200+ runs-on: linux-host
201201+ enable-openid-connect: true
202202+ steps:
203203+ - run: |
204204+ AUD="u:1:11412bf9-...-f06c"
205205+ curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
206206+ "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=$AUD"
207207+```
208208+209209+Revendications du JWT reçu : `iss`, `repository`, `ref`, `workflow`, `sub`. Le
210210+jeton est signé par f1 et vérifiable par f2 sans contact préalable.
211211+212212+---
213213+214214+## Le jeton sert directement à s'authentifier sur f2
215215+216216+```
217217+curl -X POST \
218218+ -H "Authorization: Bearer $JWT" \
219219+ -H "Content-Type: application/json" \
220220+ --data '{"title":"Proposition de test depuis le CI de f1","head":"f1-ci-run-6","base":"main"}' \
221221+ https://f2.cyberwild.org/api/v1/repos/forgeadmin/testrepo/pulls
222222+```
223223+224224+Aucun jeton n'est stocké côté f2 pour f1 : la confiance repose sur la
225225+signature du JWT et les règles de revendications, pas sur un secret échangé à
226226+l'avance.
227227+228228+---
229229+230230+## Résultat : trois actions inter-instances réussies
231231+232232+| Action déclenchée depuis f1 | Résultat sur f2 |
233233+|---|---|
234234+| Créer un fichier | HTTP 201 |
235235+| Créer une branche | HTTP 201 |
236236+| Ouvrir une proposition de modification | HTTP 201 |
237237+238238+239239+---
240240+241241+<!-- _class: lead part -->
242242+<!-- _backgroundColor: #1a5fb4 -->
243243+<!-- _color: #ffffff -->
244244+245245+# 4. Comparaison avec d"autres systèmes décentralisés
246246+247247+## Panorama des systèmes comparés
248248+249249+---
250250+251251+
252252+253253+## [ForgeFed](https://forgefed.org) : une spécification distincte de Forgejo
254254+255255+**ForgeFed** est une extension d'ActivityPub pensée pour les forges : dépôts,
256256+tickets, propositions, versions.
257257+258258+**[Vervis](https://hackage.haskell.org/package/vervis)** en est l'implémentation de référence : une forge complète et
259259+séparée, pas un module à brancher sur Forgejo.
260260+261261+Forgejo construit sa propre fédération. Le blog ForgeFed n'a rien publié depuis janvier 2025.
262262+263263+---
264264+265265+<!-- _class: wide -->
266266+267267+## Comparaison des modèles techniques
268268+269269+| | [ActivityPub](https://www.w3.org/TR/activitypub/) | [ATProto](https://atproto.com) | [IPFS](https://ipfs.tech) | [Radicle](https://radicle.dev) |
270270+|---|---|---|---|---|
271271+| Organisé autour de | le serveur | l'utilisateur | le contenu | le dépôt |
272272+| Identité | une adresse sur un serveur | un identifiant portable | une clé | une clé, sans compte |
273273+| Données stockées | sur le serveur | pointées par l'identifiant | partout où copiées | sur les nœuds relais |
274274+| Droits | signatures, plus l'admin | des clés, on peut déménager | aucun | une liste de clés signée |
275275+| 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 |
276276+277277+Radicle range tickets et propositions **dans le dépôt git lui-même** .
278278+279279+---
280280+281281+<!-- _class: wide -->
282282+283283+
284284+285285+## Comparaison des modèles de gouvernance
286286+287287+| | Code | Gouvernance |
288288+|---|---|---|
289289+| ActivityPub | Mastodon, PeerTube, GoToSocial : AGPL | spécification W3C figée en 2018. Threads est propriétaire et fédère quand même |
290290+| ATProto | référence ouverte, auto-hébergeable | une société écrit le protocole, tient l'infrastructure |
291291+| 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 |
292292+| 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) |
293293+294294+Ni ActivityPub ni Radicle ne dépendent d'une société..
295295+296296+---
297297+298298+
299299+300300+## Ponts entre réseaux sociaux décentralisés
301301+302302+**[Bridgy Fed](https://fed.brid.gy)** relie la fédiverse, Bluesky et le web
303303+ouvert dans les deux sens. **[granary](https://github.com/snarfed/granary)**, en dessous traduit entre les formats.
304304+305305+Ce sont des projets personnels.
306306+307307+---
308308+309309+## Tentatives d'hébergement de git sur IPFS
310310+311311+| Projet | État |
312312+|---|---|
313313+| [Gitlawb/node](https://github.com/Gitlawb/node), [ipgit](https://github.com/meyer1994/ipgit) | actifs en 2026, une centaine de favoris chacun |
314314+| git-remote-ipfs, pando, brig | génération précédente, abandonnée |
315315+316316+Rien n'est utilisable en production.
317317+318318+ATProto s'inspire du même principe : chaque contenu est identifié par une
319319+empreinte plutôt que par une adresse, comme sur IPFS. Mais contrairement à
320320+IPFS, ATProto associe ce contenu à des comptes utilisateurs identifiables.
321321+322322+---
323323+324324+
325325+326326+## Portabilité de l'identité
327327+328328+**[Keyoxide](https://keyoxide.org)** produit des preuves d'identité
329329+décentralisées, déjà utilisées par Forgejo pour ses propres contacts.
330330+**[did:web](https://w3c-ccg.github.io/did-method-web/)** permet à un domaine de publier une identité portable dès aujourd'hui.
331331+332332+Mais quitter une instance reste synonyme d'abandonner son identité, ses
333333+contributions et ses relations. Radicle évite ce défaut en fondant l'identité
334334+sur des clés plutôt que sur un compte.
335335+336336+---
337337+338338+<!-- _class: lead part -->
339339+<!-- _backgroundColor: #1a5fb4 -->
340340+<!-- _color: #ffffff -->
341341+342342+# 5. Démonstration pratique
343343+344344+## Radicle testé entre r1 et r2.cyberwild.org
345345+346346+---
347347+348348+## Mise en place : identités et connexion directe entre pairs
349349+350350+Radicle 1.10.3 est installé sur les deux nœuds. Pas de serveur central :
351351+chaque nœud a sa propre identité (clé Ed25519) et écoute en pair-à-pair.
352352+Comme r1 et r2 sont sur le même réseau local, la connexion est directe, sans
353353+tunnel.
354354+355355+```
356356+rad auth --alias radicle1
357357+radicle-node --listen 0.0.0.0:8776
358358+359359+# depuis r1, connexion directe au nœud r2
360360+rad node connect z6Mkfqb...2nbFDJg@192.168.1.108:8776
361361+```
362362+363363+---
364364+365365+## Un dépôt partagé, sans serveur
366366+367367+```
368368+# sur r1 : publier un dépôt existant sur le réseau
369369+rad init --name testrepo --default-branch master --public
370370+# -> rad:z2YWuPL53okTkr5mgb7WCKsfxG7h8
371371+372372+# sur r2 : récupérer le même dépôt directement depuis r1
373373+rad clone rad:z2YWuPL53okTkr5mgb7WCKsfxG7h8
374374+```
375375+376376+Le dépôt, avec ses fichiers, est répliqué intégralement entre les deux nœuds
377377+via le protocole pair-à-pair, sans jamais passer par un serveur HTTP.
378378+379379+---
380380+381381+## Un patch (l'équivalent Radicle d'une proposition de modification)
382382+383383+```
384384+# sur r2 : proposer un changement
385385+git checkout -b feature-dummy4
386386+git commit -am "add dummy4.txt"
387387+git push rad HEAD:refs/patches
388388+# -> Patch 922387e... ouvert
389389+390390+# sur r1 (mainteneur) : relire et fusionner
391391+rad patch checkout 922387e
392392+git merge --no-ff feature-dummy4-review
393393+git push rad master
394394+```
395395+396396+---
397397+398398+## Résultat : fédération pair-à-pair, sans passerelle HTTP obligatoire
399399+400400+| Étape | Résultat |
401401+|---|---|
402402+| Connexion directe r1 et r2 | établie |
403403+| Réplication du dépôt sur r2 | fichiers identiques |
404404+| Patch ouvert sur r2, visible sur r1 | propagé automatiquement |
405405+| Fusion du patch sur r1 | master mis à jour |
406406+407407+Contrairement à 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.
408408+409409+---
410410+411411+<!-- _class: lead part -->
412412+<!-- _backgroundColor: #1a5fb4 -->
413413+<!-- _color: #ffffff -->
414414+415415+# 6. Faire dialoguer Forgejo et Radicle
416416+417417+## graft : un miroir entre les deux mondes déjà testés
418418+419419+---
420420+421421+## Ce que fait [graft](https://github.com/jeanbaptiste/graft)
422422+423423+Un 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.
424424+425425+Il tourne à intervalle régulier, garde son état dans une base SQLite locale, et
426426+ne force jamais un push. Les vraies divergences sont signalées et laissées à
427427+l'arbitrage humain plutôt que résolues automatiquement.
428428+429429+Projet récent (GPLv3, quatre commits, aucune version publiée) : une
430430+démonstration de faisabilité, pas un outil éprouvé.
431431+432432+---
433433+434434+## Relier f1 et r1
435435+436436+```yaml
437437+sync_interval: 5m
438438+state_db: /var/lib/graft/state.db
439439+440440+repos:
441441+ - name: testrepo
442442+ forgejo:
443443+ base_url: https://f1.cyberwild.org
444444+ owner: forgeadmin
445445+ repo: testrepo
446446+ token_file: /etc/graft/testrepo.token
447447+ radicle:
448448+ rid: rad:z2YWuPL53okTkr5mgb7WCKsfxG7h8
449449+ http_base_url: https://r1.cyberwild.org
450450+ rad_home: /home/graft/.radicle
451451+ sync:
452452+ git: true
453453+ issues: true
454454+ patches: true
455455+```
456456+457457+Le même dépôt que dans la démonstration Radicle, maintenant relié à f1 plutôt
458458+qu'à r2 seul.
459459+460460+---
461461+462462+## Ce qui se synchronise et limites actuelles
463463+464464+- **Code** : la branche par défaut, uniquement en avance rapide.
465465+- **Tickets** : un ticket Forgejo devient un ticket Radicle et inversement,
466466+ mais seulement à la création.
467467+- **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.
468468+469469+Aucun force-push.
470470+---
471471+472472+## Complémentarité
473473+474474+graft ne tranche pas entre Radicle et Forgejo, il les traite comme
475475+complémentaires : le même projet existe sur les deux à la fois.
476476+477477+Ce que ça ne résout pas : l'identité reste double, un compte Forgejo d'un
478478+côté, une clé Radicle de l'autre.
479479+480480+---
481481+482482+
483483+484484+## Synthèse et questions
485485+486486+**Discussion :**
487487+488488+- Qui modère une proposition de modification abusive venue d'un autre
489489+ serveur ?
490490+- Les miroirs et F3 marchent déjà. ActivityPub résout-il le vrai problème ?
491491+- Radicle et Forgejo : rivaux, ou deux moitiés de la même réponse ?