Files
ObsiGate/docs/features/hub-reglages-obsigate-229.md
T
Spark b88191ffcb
CI / lint (pull_request) Successful in 1m16s
CI / security (pull_request) Successful in 19s
CI / test (pull_request) Successful in 3m41s
CI / build (pull_request) Successful in 13s
CI / e2e (pull_request) Failing after 14m58s
feat: HUB-21 — réglages généraux du Hub consommés par ObsiGate (bannière + drapeau recherche_partout) #229
2026-11-06 17:02:04 +00:00

4.2 KiB

#229 — HUB-21 : consommation des réglages généraux du Hub par ObsiGate

Carte : propagation de HUB-21 (fusion #135) — le pilote TikTak (0.61.22, en production) a posé le patron de client ; ObsiGate le consomme à son tour, comme les autres hôtes de la suite. Version cible : 2.85.2 (branche depuis le main 2.85.1).

Contrat consommé (liste fermée D6(a))

  • GET {hub}/api/reglages/effectifs — endpoint public (aucun cookie relayé), Accept: application/json, délai 2 s ;
  • réponse 200, forme figée : {"recherche_partout": bool, "banniere": str, "domaine_defaut": "pro"|"famille"|"perso"|null, "ttl_secondes": 60}, Cache-Control: public, max-age=60 ;
  • URL du Hub : draco_config.app_url("hub"), la résolution de la barre commune (#223) — variable explicite d'abord, dérivation par l'hôte sœur ensuite, défaut officiel enfin. Jamais d'URL dev figée.

Client — backend/hub_reglages.py

Sur le patron du pilote TikTak (app/hub_reglages.py, httpx → urllib comme backend/hub_roles.py) :

  • cache mémoire 60 s ; horodatage posé avant l'appel : un échec conserve l'ancien cache et ne déclenche pas de rafale vers un Hub en panne ;
  • forme validée strictement ; toute erreur (réseau, délai, statut ≠ 200, JSON illisible, forme hors contrat) → repli intégral sur les défauts actuels (recherche_partout: true, banniere: "", domaine_defaut: null) — le comportement d'ObsiGate avant HUB-21. Le module ne lève jamais ; aucun appel au démarrage.

Consommation

  1. banniere — backend/main.py::_fragment_banniere_hub() construit le fragment (texte échappé via html.escape, jamais de HTML injecté), injecté sous la barre commune par _index_html (page principale, juste avant le rappel de la barre) et par serve_recherche_page (page /recherche, après l'en-tête de la barre). Le script inline (nonce CSP ajouté par inject_csp_nonce) révèle le bandeau sauf si le même texte a été fermé dans la session du navigateur (sessionStorage, clé obsigate_banniere_masquee) : une nouvelle annonce réapparaît. Bannière vide = aucun fragment rendu, zéro changement visuel. Styles .banniere-hub* dans frontend/style.css, sur les variables du thème (var(--accent)).
  2. recherche_partout — serve_recherche_page remplace le jeton {{RECHERCHE_PARTOUT}} de frontend/recherche.html, rendu en attribut data-recherche-partout du <main id="recherche">. Le JS vendangé frontend/js/recherche.js (modification identique dans les 4 hôtes applicatifs : fonction pure federationAutorisee) n'interroge plus les applications sœurs ni la console quand la valeur est false — leurs sections affichent « Recherche fédérée désactivée… » — tandis que la recherche locale ObsiGate (même origine) continue. Attribut absent ou illisible = fédération active (repli).
  3. domaine_defaut — non consommé. ObsiGate n'a pas de notion de domaine (Pro/Famille/Perso) propre à ses vues : le sélecteur de domaine de la barre commune pilote le panneau Spark, pas ObsiGate. La valeur est lue et validée par le client, sans effet local. Seul l'hôte console (agent) applique ce réglage.

i18n

Aucun texte d'interface du SPA n'est ajouté : la bannière est un contenu d'annonce servi par le Hub (texte libre de l'administrateur), et le libellé « Fermer l'annonce » est l'attribut d'accessibilité du fragment injecté côté serveur, sur le même patron que les autres hôtes. Pas de clé frontend/locales/* ajoutée.

Tests

  • tests/test_hub_reglages.py (nouveau) : contrat exact de l'appel (URL, aucun cookie, délai 2 s), formes inattendues → repli, erreur HTTP / Hub injoignable / JSON illisible → repli, cache 60 s, ancien cache conservé sans rafale ; intégration TestClient : bannière présente et échappée sur / et /recherche, absente si vide ou Hub muet, data-recherche-partout selon la valeur du drapeau (faux / vrai / Hub muet).
  • tests/frontend/recherche.test.mjs : assertions ajoutées pour federationAutorisee (seules les valeurs explicitement négatives désactivent ; absent/illisible = actif).