Set-OPS-Public/docs/depots-prives-conception.md
Daniel Allaire 9af39b1b60 forge : chaque locataire publie la cle qui lira son depot, le site sait l'enregistrer
Debut du chantier des depots prives (docs/depots-prives-conception.md). La face reseau
publie genome: {depot, cle_lecture} ; P95 exige que la cle soit connue de la flotte, et
l'armement refuse une voute qui en remettrait une autre. make forge-cles enregistre
chaque cle en lecture seule sur le seul depot que la face nomme, retire une cle
perimee, ne touche jamais celle du runner du site. Flux SSH vers la forge du site
depuis les seuls runners des locataires (paire runners_locataires).

Rien n'est encore applique sur le terrain ; les depots restent publics.

95 preuves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 19:59:07 -04:00

7.8 KiB

Dépôts privés sur la forge du site — conception du chantier

Pour qui : le mainteneur qui décide de ce chantier puis le conduit, et quiconque se demande pourquoi un runner ne lit que ses propres dépôts.

Préparé le 2026-10-11. Rien n'est changé tant que les décisions D1 à D3 ne sont pas prises.

1. Le constat

Sur la forge du site, l'organisation genome porte cinq dépôts, tous publics :

Dépôt Contenu Qui en a besoin
set-ops-public le moteur tous les runners
set-ops-modeles les modèles génériques le runner du site
site-chezlepro la carte de la fabric, le plan du site le runner du site
ops-chezlepro le plan, l'inventaire et la face de Chezlepro son runner, le runner du site
ops-technolibre le plan, l'inventaire et la face de Technolibre son runner, le runner du site

Mesuré le 2026-10-11 : depuis le runner de Technolibre, git ls-remote sans identifiant lit la tête de ops-chezlepro (b4fbd85) et de site-chezlepro (51dae24). Chaque locataire peut donc lire le plan de l'autre, et la carte du site. Aucun n'en a besoin : chaque runner de locataire ne clone que le moteur et son propre dépôt ; ce que le site lui donne arrive par la fiche déposée dans son dépôt.

D'où ça vient : le 2026-09-12, à la première reconstruction du site, les dépôts créés privés ont cassé le clonage anonyme des runners. Ils sont passés publics, avec l'argument que seuls ceux qui ont franchi la frontière joignent la forge (scripts/forge_amorcer.py). Les autres locataires en font partie.

2. La cible

  • Publics : set-ops-public et set-ops-modeles. Ils sont génériques, identiques pour tous.
  • Privés : site-chezlepro et chaque ops-<locataire>.
  • Le runner du site lit et pousse tous les dépôts avec sa clé, déjà enregistrée comme clé de déploiement en écriture par genome_pousser.yml. Mesuré le 2026-10-11 : il lit les cinq dépôts en SSH, avec une vérification stricte de la clé d'hôte. Rien à créer pour lui.
  • Le runner d'un locataire lit son seul dépôt, avec une clé de déploiement en lecture seule : la clé publique de son runner, déjà déclarée au plan (ssh_baseline_cles_admin) et dont la privée lui est remise à l'armement depuis sa voûte (vault_runner_cle_ssh).
  • Aucun secret ne change de main. Le locataire publie la clé publique de son runner dans sa face réseau ; le site l'enregistre sur le dépôt de ce locataire, avec ses propres identifiants d'administration de la forge (vault_forgejo_admin, déjà dans sa voûte).

3. Le nœud : l'insémination

Le site amorce le runner d'un locataire avant que celui-ci ait reçu sa clé stable (elle arrive à l'armement, geste humain, après). Pendant l'insémination, le rôle serveur_ops clone pourtant le dépôt du locataire : avec un dépôt privé, ce clonage échoue. Même chose au premier déploiement du runner du site, dont la clé est neuve.

Remède proposé : le colis. Quand un runner ne peut pas encore lire un dépôt privé, le contrôleur qui joue serveur_ops (le runner du site pendant l'insémination, le poste ailleurs) lui apporte ce dépôt en git bundle. Le mécanisme existe déjà : genome_colis.py porte le génome du poste au runner du site. Le runner clone le colis, puis pointe origin vers l'URL SSH de la forge. Ses tirages suivants passent par sa clé, une fois armé.

4. Les décisions à prendre

D1 — Comment le runner d'un locataire lit-il son dépôt ?

  • Clé de déploiement en SSH (recommandé). Le runner continue de tirer lui-même ; il garde son autonomie (émancipation, make lancé sur le runner, garde verifier_genome_a_jour). Coût : un flux nouveau, du runner de chaque locataire vers la forge du site, en SSH.
  • Colis seulement. Aucun flux nouveau, aucune clé de déploiement pour les locataires : le contrôleur apporte toujours le dépôt. Mais le runner ne tire plus son dépôt lui-même, et sa garde de génome n'a plus de forge à laquelle se comparer.

D2 — Sur quelle écoute SSH ?

  • Le sshd de la machine, port 22 (recommandé pour commencer). Le runner du site et le poste l'utilisent déjà pour pousser ; l'utilisateur git y est contraint par la forge. Le flux n'ouvre que les adresses des runners de locataires, pas leurs supernets.
  • Le serveur SSH intégré de Forgejo, sur un port dédié. Il n'expose pas le sshd de la machine, mais sa cohabitation avec le sshd existant reste à éprouver avant de s'y fier.

D3 — La preuve. Ce chantier touche l'insémination : je propose de le prouver par une reconstruction complète de Technolibre (raser, créer, inséminer, armer, monter), dépôts privés, avant de reprendre le lot 3b.

5. Ce qui change dans le code

Pièce Changement
serveur_ops_depots un drapeau prive: true sur les dépôts instance, tenant et hebergeur
roles/serveur_ops URL SSH et clé du runner pour les dépôts privés ; colis du contrôleur quand le runner ne peut pas encore les lire ; clé d'hôte de la forge épinglée
contexte.py (face) la face publie la clé publique de lecture du runner (genome.cle_lecture)
contexte.py (fiche) la fiche du site publie la clé d'hôte SSH de sa forge, que le runner du locataire épingle
nouvelle cible forge-cles le site enregistre, d'après les faces, la clé de lecture de chaque locataire sur son dépôt, et retire celles qui ne sont plus publiées
forge_amorcer.py crée les dépôts privés comme privés
flux serveur_forge_site : entrée SSH depuis les runners des locataires hébergés (paire nouvelle, résolue depuis les faces) ; serveur_ops : sortie correspondante
genome_etat.yml lit la forge par SSH ou authentifié : l'API anonyme répondrait 404 pour un dépôt privé
sonde-genome-servi compte les dépôts de l'organisation authentifié, sinon elle ne verrait plus que les deux publics

Inchangés : sonde-genome-a-jour (son repère ne compare que set-ops-public), le poste (il pousse déjà en SSH), la console (etat_forge lit origin, qui deviendra l'URL SSH).

6. Les preuves à écrire

  • Hors ligne (make prouver) : chaque dépôt instance, tenant ou hebergeur est déclaré privé ; chaque face publie une clé de lecture, et cette clé est dans ssh_baseline_cles_admin.
  • Sur le terrain (make forge-etancheite), avec témoins :
    • sans identifiant, un dépôt privé refuse et un dépôt public répond ;
    • le runner d'un locataire lit son dépôt et ne lit pas celui de l'autre ;
    • les clés de déploiement de chaque dépôt sont exactement : runner du site en écriture, runner du locataire en lecture.
  • Par reconstruction : D3.

7. L'ordre de bascule

Chaque étape se vérifie avant la suivante, et la bascule se défait d'un appel par dépôt (repasser public).

  1. Éprouver sur la forge du site, sans rien basculer : enregistrer la clé de lecture du runner de Technolibre sur ops-technolibre, ouvrir le flux pour ce seul runner, et mesurer qu'il lit son dépôt en SSH.
  2. Construire le code et les preuves (§5, §6) ; make verifier.
  3. Déployer sans basculer : flux et frontière (make frontiere-appliquer CONFIRMER=true, lancé par Daniel), clés de déploiement, remotes SSH sur les trois runners. Les dépôts sont encore publics : chaque runner doit déjà tirer en SSH.
  4. Basculer site-chezlepro, ops-chezlepro et ops-technolibre en privé. Mesurer avec make forge-etancheite, puis la veille des trois consoles.
  5. Prouver par la reconstruction de Technolibre (D3).
  6. Reprendre le lot 3b : les demandes vivent alors dans le dépôt de chaque locataire, lisibles par lui et par le site seulement.