Mesure sur le terrain : chaque runner lit son depot en SSH avec sa cle de deploiement, et la forge lui refuse les autres, alors meme que les depots sont publics. Le role ne clone plus en HTTPS que les depots publics ; les depots instance, tenant et hebergeur passent en SSH, cle d'hote epinglee, commande SSH posee dans leur config git. Avant l'armement, le controleur les apporte en git bundle. La cle d'hote de la forge est declaree au plan du site et offerte par la fiche. genome_etat et genome_pousser lisent l'API authentifies ; la sonde genome-servi compte les publics ; forge_amorcer cree prives les depots des ecosystemes et du site. make forge-etancheite mesure le tout. Les depots restent publics. 95 preuves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
122 lines
5.1 KiB
YAML
122 lines
5.1 KiB
YAML
---
|
|
# CE QUE LA FORGE DU SITE PORTE, FACE A CE QUE LE POSTE PORTE.
|
|
#
|
|
# La forge du SITE fait autorite pour le genome (D-81). Toute autre copie est un miroir.
|
|
# Encore faut-il que cette autorite soit A JOUR — et la derive ne se voit pas toute seule.
|
|
#
|
|
# Mesure du 2026-08-26 : la forge etait restee quatre commits derriere le poste sans que
|
|
# rien ne le signale. Le runner clonait donc un moteur perime, dont le correctif qui
|
|
# desarme le pare-feu Proxmox. Un ecosysteme qui se reproduit depuis une forge en retard
|
|
# reproduit ses defauts.
|
|
#
|
|
# Cette cible ne corrige rien : elle REGARDE. `make genome-pousser` corrige.
|
|
#
|
|
# make genome-etat
|
|
|
|
- name: Ce que la forge du site porte, face au poste
|
|
hosts: serveur_ops_site
|
|
gather_facts: false
|
|
|
|
vars:
|
|
genome_racine: "{{ serveur_ops_racine | default('/opt/setops') }}"
|
|
genome_freres: "{{ playbook_dir | dirname | dirname | dirname }}"
|
|
genome_moteur: "{{ (serveur_ops_depots | selectattr('role', 'eq', 'moteur') | first).dest }}"
|
|
|
|
tasks:
|
|
- name: Voir lesquels de ces dépôts existent sur le contrôleur
|
|
ansible.builtin.stat:
|
|
path: "{{ genome_freres }}/{{ item.dest }}/.git"
|
|
delegate_to: localhost
|
|
become: false
|
|
loop: "{{ serveur_ops_depots | default([]) }}"
|
|
loop_control:
|
|
label: "{{ item.dest }}"
|
|
register: genome_locaux
|
|
|
|
- name: Retenir ceux qu'on peut comparer
|
|
ansible.builtin.set_fact:
|
|
genome_compares: >-
|
|
{{ genome_locaux.results | selectattr('stat.exists')
|
|
| map(attribute='item') | list }}
|
|
|
|
- name: Ce que le poste porte
|
|
ansible.builtin.command:
|
|
argv:
|
|
- python3
|
|
- "{{ genome_freres }}/{{ genome_moteur }}/scripts/genome_colis.py"
|
|
- etat
|
|
- "{{ genome_freres }}/{{ item.dest }}"
|
|
- --branche
|
|
- "{{ item.branche | default('main') }}"
|
|
delegate_to: localhost
|
|
become: false
|
|
loop: "{{ genome_compares }}"
|
|
loop_control:
|
|
label: "{{ item.dest }}"
|
|
register: genome_ici
|
|
changed_when: false
|
|
|
|
- name: Ce que la forge porte
|
|
ansible.builtin.uri:
|
|
url: >-
|
|
https://forge.{{ domaine_interne }}/api/v1/repos/{{ serveur_ops_forge_organisation
|
|
| default('genome') }}/{{ item.depot }}/branches/{{ item.branche | default('main') }}
|
|
# AUTHENTIFIE (2026-10-11) : les depots des locataires et du site deviennent prives, et
|
|
# l'API anonyme y repondrait 404 — un « absent » qui n'en serait pas un.
|
|
url_username: forgejo-admin
|
|
url_password: "{{ vault_forgejo_admin }}"
|
|
force_basic_auth: true
|
|
validate_certs: false
|
|
status_code: [200, 404]
|
|
loop: "{{ genome_compares }}"
|
|
loop_control:
|
|
label: "{{ item.depot }}"
|
|
register: genome_la_bas
|
|
# LE PREMIER CONTACT AVEC LA FORGE RATE PARFOIS (mesure du 2026-08-26 : une fois sur
|
|
# six, poignee TLS expiree, puis cinq reponses de suite). Ce n'est pas le chemin —
|
|
# il est prouve — c'est l'acceptation TLS apres un temps d'inactivite. On reessaie
|
|
# plutot que de rendre un verdict sur un alea.
|
|
retries: 4
|
|
delay: 3
|
|
until: genome_la_bas is succeeded
|
|
changed_when: false
|
|
|
|
- name: L'état, dépôt par dépôt
|
|
ansible.builtin.debug:
|
|
msg: >-
|
|
{{ item.depot }} :
|
|
poste {{ (genome_ici.results[idx].stdout | from_json).courte }}
|
|
{{ '=' if genome_la_bas.results[idx].status == 200
|
|
and genome_la_bas.results[idx].json.commit.id
|
|
== (genome_ici.results[idx].stdout | from_json).tete
|
|
else '≠' }}
|
|
forge {{ genome_la_bas.results[idx].json.commit.id[:7]
|
|
if genome_la_bas.results[idx].status == 200 else '(absente)' }}
|
|
{{ '— copie locale NON PROPRE, des commits ne sont pas faits'
|
|
if not (genome_ici.results[idx].stdout | from_json).propre else '' }}
|
|
loop: "{{ genome_compares }}"
|
|
loop_control:
|
|
label: "{{ item.depot }}"
|
|
index_var: idx
|
|
|
|
# ON REFUSE PLUTOT QUE DE SIGNALER. Un ecart connu et tolere redevient un ecart oublie ;
|
|
# et la commande qui le corrige tient en trois mots.
|
|
- name: La forge fait-elle autorité sur une copie à jour ?
|
|
ansible.builtin.assert:
|
|
that:
|
|
- genome_la_bas.results[idx].status == 200
|
|
- genome_la_bas.results[idx].json.commit.id
|
|
== (genome_ici.results[idx].stdout | from_json).tete
|
|
fail_msg: >-
|
|
{{ item.depot }} : la forge du site porte
|
|
{{ genome_la_bas.results[idx].json.commit.id[:7]
|
|
if genome_la_bas.results[idx].status == 200 else '(rien — dépôt absent)' }},
|
|
le poste porte {{ (genome_ici.results[idx].stdout | from_json).courte }}.
|
|
La forge du site FAIT AUTORITÉ (D-81) : tant qu'elle est en retard, tout
|
|
écosystème qui s'y reproduit reproduit un moteur périmé.
|
|
Corriger avec `make genome-pousser`.
|
|
success_msg: "{{ item.depot }} : la forge est à jour."
|
|
loop: "{{ genome_compares }}"
|
|
loop_control:
|
|
label: "{{ item.depot }}"
|
|
index_var: idx
|