reference/synchroniser-doc-vers-rag.md

Synchroniser une doc git vers un index RAG — webhook + wrapper

Référence de structure pour un pipeline qui maintient un index RAG à jour à partir d'un dépôt git de documentation. Le principe : le RAG indexe un clone git local de la doc, hébergé sur le serveur applicatif. Sans mécanisme de rafraîchissement, ce clone devient obsolète dès qu'un commit est poussé. Deux déclencheurs complémentaires alimentent un pipeline unique de checkout + ré-indexation.

Vue d'ensemble

Déclencheur Origine Ref ciblé
Webhook Nouveau tag poussé sur la branche de release Le tag poussé
Interface d'administration Action manuelle d'un admin Branche + ref au choix

Les deux passent par le mĂŞme pipeline :

Déclencheur (webhook / admin)
  → Lanceur (process CLI détaché)
      → Commande CLI : checkout --ref=<ref>
          → git fetch origin --tags --prune
          → git checkout <ref>
          → git pull --ff-only   (seulement si branche ; pas si tag/SHA détaché)
      → Service d'ingestion : drop + rebuild complet de l'index
      → Persistance d'état : running=false, last_at=now, current_ref=<ref>

Déclencheur 1 — Webhook

Endpoint

Un endpoint HTTP POST dédié, par exemple POST /api/webhook/<fournisseur>/docs.

Sécurité

  • Signature HMAC-SHA256 du corps de la requĂŞte, transmise dans un en-tĂŞte dĂ©diĂ© (les fournisseurs git le nomment typiquement X-Hub-Signature-256).
  • Le secret est stockĂ© dans une variable d'environnement cĂ´tĂ© serveur (jamais en dur dans le code, jamais dans le dĂ©pĂ´t).
  • Secret absent OU signature invalide → 401.

Filtre d'événements

  • Ne traiter que l'Ă©vĂ©nement de crĂ©ation de tag. Les push de branche, PRs et autres Ă©vĂ©nements → 200 « ignorĂ© ».
  • Ce filtre garantit qu'un simple push de dĂ©veloppement ne relance pas une rĂ©-indexation complète.

Anti-chevauchement

Si un checkout est déjà en cours (verrou d'état à true), le webhook répond 202 sans relancer.

Configuration côté dépôt

Champ Valeur
URL l'endpoint webhook exposé par l'application
Content-Type application/json
Événements création de branche/tag uniquement
Secret mĂŞme valeur que la variable d'environnement serveur

Le secret webhook doit être géré comme un secret d'infrastructure (coffre de configuration / gestionnaire de secrets), puis injecté dans l'environnement du serveur — jamais commité.

Déclencheur 2 — Interface d'administration

Une section d'administration dédiée offre un déclenchement manuel avec choix libre de la ref.

Flux d'utilisation

  1. L'admin choisit une branche (liste issue des branches remote-tracking locales).
  2. (Optionnel) L'admin déclenche un rafraîchissement : un git fetch distant, puis rechargement de la liste des refs.
  3. Le sélecteur de ref se peuple via AJAX à partir des refs locales (pas de fetch réseau) :
    • tags fusionnĂ©s dans la branche (le plus rĂ©cent mis en avant) ;
    • N derniers commits (SHA court — date — message).
  4. L'admin sélectionne la ref et soumet.
  5. Checkout + ré-indexation se lancent en arrière-plan (process CLI détaché).
  6. La section affiche un verrou « en cours » avec auto-refresh.

Endpoints AJAX

Méthode Rôle
GET refs?branch=<b> Liste des refs locales (tags + commits) — aucun accès réseau
POST fetch Déclenche un git fetch distant

Ségrégation d'identité côté serveur

C'est le cœur du modèle de sécurité. Deux utilisateurs système distincts :

  • L'utilisateur du serveur web (celui qui exĂ©cute PHP-FPM ou Ă©quivalent) n'a aucune clĂ© SSH ni identitĂ© externe. Il ne peut pas parler Ă  l'hĂ©bergeur du dĂ©pĂ´t.
  • Un utilisateur applicatif dĂ©diĂ© dĂ©tient la clĂ© SSH de dĂ©ploiement et donc l'accès au dĂ©pĂ´t distant.

Le serveur web n'agit jamais lui-même sur le dépôt : il délègue à l'utilisateur applicatif via des règles sudo étroitement cadrées. Aucune commande arbitraire n'est autorisée.

git safe.directory

Le clone appartient à l'utilisateur applicatif ; le serveur web ne fait que le lire. Sans configuration, git renvoie fatal: detected dubious ownership. Il faut déclarer le chemin du clone comme safe.directory (portée système) :

git config --system --add safe.directory <chemin-du-clone>

Wrapper de commande

Les noms de commandes de nombreux frameworks (Symfony, etc.) contiennent des :, caractère réservé dans la syntaxe sudoers. On contourne cela avec un wrapper shell minimal, à chemin fixe, qui encapsule la commande réelle :

#!/bin/bash
exec <interpréteur> <chemin-console> <commande:checkout> "$@"

Le wrapper ne fait que relayer ses arguments : aucune logique, aucune interpolation.

Règles sudoers étroitement cadrées

Deux règles seulement, correspondant exactement aux deux actions autorisées (le fetch du bouton de rafraîchissement, et le checkout en arrière-plan) :

<user-web> ALL=(<user-app>) NOPASSWD: /usr/bin/git -C <chemin-du-clone> fetch origin --tags --prune
<user-web> ALL=(<user-app>) NOPASSWD: <chemin-du-wrapper> *

Principe : on énumère précisément les commandes permises, chemins absolus compris. Rien d'autre n'est délégable.

État persisté

L'application conserve un petit état applicatif pour piloter le verrou et l'affichage :

Clé Type Rôle
checkout_running bool verrou anti-chevauchement
last_checkout_at datetime ISO horodatage du dernier checkout
current_ref string ref actuellement indexée

Périmètre d'indexation — mode default-allow

Le module de lecture du corpus (et le RAG) opèrent en default-allow : tout fichier de doc est indexé sauf exclusions permanentes codées dans le composant. Il n'y a pas d'allowlist à maintenir dans la configuration.

Exemples de segments exclus en dur (à adapter au dépôt) :

Exclusion Raison
dossier de données d'entrée données personnelles / sources brutes
dossier de scripts outillage, pas de la documentation
dossier legacy/ archivé, hors corpus courant
brouillons non publiés contenu non validé
dotfiles / dotdirs métadonnées de dépôt (.git, etc.)

Pour exclure un dossier : ajouter son segment Ă  la liste des segments toujours exclus. Pour rendre un dossier visible : il l'est d'office, sans intervention.

Opérations de référence

Provisionner le clone initial

git clone <url-ssh-du-depot> <chemin-du-clone>
git -C <chemin-du-clone> checkout <branche-de-release>

Le webhook prend ensuite le relais pour les mises Ă  jour automatiques.

Vérifier l'état courant

git -C <chemin-du-clone> log --oneline -3
git -C <chemin-du-clone> describe --tags

Forcer un refresh manuel

sudo -u <user-app> <chemin-du-wrapper> --ref=<sha-ou-tag>

Bonne pratique : la commande de checkout n'accepte que des SHA ou des tags (validés par une regex du type ^[0-9a-f]{7,40}$). Un nom de branche est rejeté — on passe un SHA explicite ou un tag, afin d'indexer une ref immuable.

Débloquer un verrou resté à true

Si le process a échoué en laissant checkout_running à true, remettre la clé d'état à false dans le stockage applicatif (base ou fichier de config selon l'implémentation).

Consulter les logs

tail -f <chemin-du-log-de-checkout>

Workflow de release recommandé

1. Pousser les commits sur la branche de développement
2. Merger vers la branche de release
3. Tagger la release, puis pousser le tag
→ Le webhook déclenche automatiquement le checkout du tag + la ré-indexation
→ Le RAG reflète la doc de release en quelques minutes

Garde-fous Ă  retenir

  • Le serveur web n'a jamais d'accès direct au dĂ©pĂ´t distant ni au disque du clone en Ă©criture.
  • Toute dĂ©lĂ©gation passe par sudoers Ă©numĂ©rĂ© commande par commande, chemins absolus.
  • Le webhook est authentifiĂ© par HMAC, filtrĂ© sur le seul Ă©vĂ©nement de crĂ©ation de tag.
  • On indexe des refs immuables (SHA/tag), pas des branches mouvantes.
  • Le secret webhook et la clĂ© de dĂ©ploiement vivent dans un coffre / l'environnement, jamais dans le dĂ©pĂ´t.

Note de rédaction : cette référence est adaptée d'une spec opérationnelle interne. Les valeurs concrètes (domaines, chemins serveur, ports, noms d'utilisateurs système, hébergeur, noms de bundles/commandes réels) ont été volontairement généralisées. Remplacer les <placeholders> par les valeurs de votre propre infrastructure.

Assistant documentaire

Posez une question sur la documentation. Les réponses citent leurs sources — un clic ouvre le document à gauche.