| 1 |
Qdrant et port 8080 exposés sur le LAN (Docker bypass UFW) |
v2.4.0 |
2026-09-14 |
| 2 |
/query laisse passer sans filtre ACL si user_groups vide |
v2.5.0 |
2026-09-14 |
| 3 |
En-tête X-OpenWebUI-User-Email falsifiable |
v2.4.0 |
2026-09-14 (effet de bord point 1) |
| 4 |
Token et données personnelles en clair dans les logs Docker |
v2.5.0 |
2026-09-14 |
| 5 |
Extensions différentes entre indexer.py et acl_resolver.py |
v2.1.0 |
2026-09-11 |
| 6 |
lire_acl_fichier retourne [] au lieu de [], [] |
v2.1.0 |
2026-09-11 |
| 8 |
Extension de contexte : scroll aléatoire au lieu de fenêtre par chunk_index |
v2.3.0 |
2026-09-13 |
| 9 |
RRF biaisé contre la collection documentation |
v2.3.0 |
2026-09-13 |
| 11 |
Réindexation complète à chaque passage (pas de détection des fichiers inchangés) |
v2.3.0 |
2026-09-13 |
| 12 |
Suppression par content_hash pouvait effacer des copies légitimes |
v2.3.0 |
2026-09-13 |
| 13 |
interdits[] jamais vidé, ACL illisibles restaient actives |
v2.5.0 |
2026-09-14 |
| 15 |
Nettoyage des orphelins sans seuil : garde-fou 20% ajouté dans acl_resolver.py |
v2.7.0 |
2026-09-20 |
| 16 |
DOCUMENTATION_COLLECTION et DOCUMENTATION_PATHS absents du Compose |
v2.3.0 |
2026-09-13 |
| 17 |
EXCLUDE_PATTERNS n’excluait pas les répertoires |
v2.3.0 |
2026-09-13 |
| 18 |
Pas de séparation structurelle instructions/données dans le prompt |
v2.9.0 |
2026-09-21 |
| 19 |
svc-rag lisait le partage par les groupes métier : droits hérités au-delà du partage (droits d’étiquettes Purview, modification d’un site SharePoint), et perte de lecture silencieuse au retrait d’un groupe. Remplacé par le groupe dédié GRP-RAG-Indexation et Set-AccesIndexationRAG.ps1 |
v2.14.2 |
2026-09-27 |
| 20 |
Fenêtre de contexte non demandée à Ollama : valeur par défaut de 4 096 tokens, contexte du RAG et du juge tronqué sans erreur. Fenêtres explicites par requête (LLM_NUM_CTX, JUDGE_NUM_CTX) |
v2.15.0 |
2026-09-27 |
| 21 |
Index BM25 non reconstruit après une synchronisation partiellement en échec : décalage possible avec Qdrant. Reconstruit après chaque synchronisation |
v2.15.0 |
2026-09-27 |
| 22 |
Courriel de quarantaine trompeur : fichiers aux permissions illisibles présentés comme « non indexés », avec une action inefficace. Les deux causes sont distinguées |
v2.15.4 |
2026-09-29 |
| doc.2 |
GROUPS_CACHE_TTL, SYNC_PYTHON, SYNC_TIMEOUT_* absents du Compose |
v2.12.0 |
2026-09-24 |
| doc.4 |
deploy.sh générait un .env incomplet |
v2.12.0 |
2026-09-24 |
| 23 |
Qdrant sans clé d’API : tout conteneur du réseau Compose pouvait lire et écrire. Clé obligatoire, transmise aux quatre clients (§15.2) |
v2.16.0 |
2026-10-01 |
| 24 |
Aucun chiffrement au repos : disque de données LUKS2 dédié, déverrouillage par TPM, phrase secrète en clé de secours ; Qdrant, Open WebUI, n8n et journaux migrés (§15.3). Les sauvegardes restent au point 34 |
v2.16.0 |
2026-10-01 |
| 25 |
sp_indexer.py écrivait chaque document dans un fichier temporaire sur disque : extraction dans /dev/shm |
v2.16.0 |
2026-10-02 |
| 14 (masque) |
Toute entrée ALLOWED valait autorisation, quel que soit le masque : un fichier en écriture seule (boîte de dépôt) devenait interrogeable. Reproduit (FUITE), corrigé, prouvé sans régression (§16.5) |
v2.17.0 |
2026-10-03 |
| 26 |
Jeton d’administration en clair dans les workflows n8n : identifiant Header Auth partagé, domaine limité à rag-api (§16.7) |
v2.17.0 |
2026-10-04 |
| 37 |
Test de non-divulgation automatisé, en deux modes, et contrôle après chaque synchronisation avec alerte (§16.2 à §16.4) |
v2.17.0 |
2026-10-03 |
| 38 |
Mot de passe SMB hors de la ligne de commande : fichier d’identifiants en mémoire |
v2.17.0 |
2026-10-03 |
| 39 |
Juge en échec : réponse non vérifiée, plus jamais « ancrée » |
v2.17.0 |
2026-10-03 |
| 40 |
Citations : correspondance exacte ; deux documents de même nom signalés tous deux |
v2.17.0 |
2026-10-03 |
| 41 |
/stats réservé à l’administration, /health minimal, panne de Qdrant en erreur 503 |
v2.17.0 |
2026-10-03 |
| 42 |
Empreinte HMAC des questions (LOG_HMAC_KEY) |
v2.17.0 |
2026-10-03 |
| 43 |
Modèles Ollama bruts masqués dans Open WebUI, accès au moteur d’inférence à restreindre au pare-feu (§16.7) |
v2.17.0 |
2026-10-03 |
| 45 |
Aucun signal quand un secret garde une valeur d’exemple (changeme) : avertissement au démarrage. Constaté en lab : jeton d’administration et jeton d’API restés à leur valeur d’exemple ; le second a été signalé par l’avertissement dès son premier démarrage |
v2.17.0 |
2026-10-04 |
| 46 |
.env lisible par tous les comptes de la VM (644) en lab, .env et clés privées sur le disque système non chiffré : déplacés sur le disque chiffré (§15.3.6), préparation avant le déploiement (§1.5) |
v2.17.0 |
2026-10-04 |
| 47 |
/v1 ignorait la demande de réponse en flux : Open WebUI v0.11.3 n’affichait plus rien. Réponse en flux, en un seul fragment, contrôles inchangés (§16.8) |
v2.17.1 |
2026-10-04 |
| 48 |
Échec de la résolution Entra présenté comme une absence d’information : mention explicite dans la réponse (§16.9) |
v2.17.1 |
2026-10-04 |
| 49 |
Images en latest et main : versions figées et empreintes documentées (§3.4) ; contrôles automatiques du dépôt par GitHub Actions |
v2.17.1 |
2026-10-04 |
| 50 |
Contexte construit pour les seules questions précises : liste tronquée à 20 candidats, 3 extraits complémentaires quelconques, copies non écartées. Diversité des sources (§8.9) |
v2.17.2 |
2026-10-05 |
| 51 |
Prompt « tout ou rien » : refus dès qu’une réponse était incomplète. Réponse partielle explicite, protégée par deux tests de refus (§8.9) |
v2.17.2 |
2026-10-05 |
| 53 |
Juge et embedding sur CPU par défaut, sans graine de génération : réglages JUDGE_NUM_GPU, EMBED_NUM_GPU, LLM_SEED ; les trois modèles validés sur la carte (§10.2) |
v2.18.0 |
2026-10-07 |
| 54 |
Document principal tronqué quand son meilleur extrait est l’en-tête : document court envoyé en entier (DOC_COMPLET_MAX), fenêtre décalée pour les longs documents (§10.6) |
v2.18.0 |
2026-10-07 |
| 55 |
Documents complémentaires réduits à leurs en-têtes : extraits consécutifs autour du meilleur extrait, mêmes filtres d’accès que le document principal (§10.6) |
v2.18.0 |
2026-10-07 |
| 56 |
Fenêtre du juge plus petite que celle du modèle : sources coupées, affirmations justes déclarées non ancrées. Par défaut, la fenêtre du juge est celle du modèle (§10.6) |
v2.18.0 |
2026-10-07 |
| 57 |
Réponses : balises du contexte et extraits recopiés, citations sans crochets, liens recopiés depuis un document, fausses absences. Nettoyage, normalisation des citations, règles de prompt (§10.9) |
v2.18.0 |
2026-10-07 |
| 58 |
Réglages numériques transmis vides : la RAG API ne démarrait pas. Valeur vide traitée comme absente (19 lectures, RAG API, authentification, indexeur) ; réglages ajoutés au Compose avec leurs valeurs par défaut (§10.9) |
v2.18.0 |
2026-10-07 |
| 60 |
Test de cloisonnement : erreur de lecture de Qdrant traitée comme une collection absente ; correspondance partielle du document, un cas pouvant évaluer deux documents. Erreurs explicites (503), correspondance exacte par défaut, cas ambigus refusés (§16) |
v2.18.2 |
2026-10-07 |
| 63 |
deploy.sh et env.example : fenêtre du juge fixée à 8 192 tokens, plus petite que celle du modèle principal, contrairement à la règle du §10.6. Portée à 16 384 |
v2.20.0 |
2026-10-12 |
| 64 |
§0 : contrôles de Qdrant (curl) sans la clé d’API obligatoire depuis la v2.16 (§15) ; QDRANT_API_KEY, LOG_HMAC_KEY et MIP_TOKEN absents des secrets à générer dans la procédure manuelle ; contrôle LDAP : option -ZZ (StartTLS) retirée d’une connexion déjà chiffrée en ldaps://, certificat de l’autorité indiqué explicitement (LDAPTLS_CACERT). Corrigé dans le §0 réécrit |
v2.20.0 |
2026-10-12 |
| 68 |
Juge d’Ollama : l’étiquette qwen3:4b raisonne toujours. Trois juges mesurés (4B raisonnant, 14B, qwen3:4b-instruct) ; qwen3:4b-instruct retenu (26 sur 30, 4,8 min contre 5,4 et 6,8 min). Étiquette, env.example, deploy.sh, valeurs par défaut du code et §2, §3, §10 alignés |
v2.20.2 |
2026-10-12 |
| 69 |
OLLAMA_NUM_PARALLEL mesuré : 2 ne tient pas sur 16 Go avec trois modèles (contexte réservé deux fois, modèles évincés et rechargés) ; avec 1, deux séries simultanées en 8,1 à 8,2 min contre 4,8 min seule. Recommandation du §2.2 appuyée par ces chiffres (§10.12). Au-delà de deux utilisateurs : non mesuré |
v2.20.2 |
2026-10-12 |
| 70 |
deploy.sh : un serveur vLLM qui répondait sans clé (code autre que 401) n’arrêtait pas le déploiement, il émettait un simple avertissement. Test rendu bloquant |
v2.20.1 |
2026-10-12 |
| 71 |
§3 : extraits du .env et du Compose sans QDRANT_API_KEY ; contrôles de la §3.6 (Qdrant, /stats), commandes de snapshot et de restauration sans la clé ni le jeton obligatoires ; exemples avec changeme-api-token. Alignés sur les fichiers du dépôt, valeurs lues dans le .env |
v2.20.1 |
2026-10-12 |
| 77 |
deploy.sh : à la confirmation, une réponse autre que « o » (un « 0 » tapé par erreur, par exemple) annulait le déploiement sans l’expliquer. Réponses « o », « oui », « y », « yes » acceptées ; toute autre réponse non reconnue est signalée |
v2.20.3 |
2026-10-14 |
| 78 |
n8n redémarrait en boucle (EACCES) sur une VM neuve : n8n_data doit appartenir à l’utilisateur 1000, et sur le disque chiffré le dossier est un lien (chown doit viser le vrai dossier). Ajouté à deploy.sh, au §0 (étape 6, « En cas de problème »), au §1.5 et au §3 |
v2.20.3 |
2026-10-14 |
| 79 |
SP_EXCLUDE_DRIVES=Preservation Hold Library sans apostrophes dans env.example : source .env échouait (« Hold: command not found »). Valeur entre apostrophes dans env.example, deploy.sh et index.md ; mise en garde au §0 |
v2.20.3 |
2026-10-14 |
| 80 |
§0 : smbclient sans -W <DOMAINE> échoue en NT_STATUS_LOGON_FAILURE sur un domaine Active Directory, mot de passe correct. Option ajoutée, cause documentée |
v2.20.3 |
2026-10-14 |
| 81 |
deploy.sh : l’environnement Python n’installait pas tous les paquets de l’indexation (rank-bm25, smbprotocol et autres absents). Liste alignée sur l’étape 11 du §0 |
v2.20.3 |
2026-10-14 |
| 82 |
deploy.sh : dossier de documentation par défaut différent de celui de l’indexeur, d’où des documents de documentation technique non reconnus comme tels à l’indexation. Valeur par défaut DOIT4EVERYONE alignée, invite précisée |
v2.20.3 |
2026-10-14 |
| 83 |
deploy.sh : annonçait « Déploiement terminé » sans contrôler l’état réel. Désormais : santé de la RAG API contrôlée depuis le conteneur (le port 8080 n’est pas publié), quatre conteneurs en running avec zéro redémarrage, liste des problèmes et sortie en erreur sinon |
v2.20.3 |
2026-10-14 |
| 84 |
docker-compose.yml : l’adresse annoncée par n8n était écrite en dur (<IP-VM>). Variable N8N_WEBHOOK_URL dans env.example, docker-compose.yml, §0 et §3 |
v2.20.3 |
2026-10-14 |
| 85 |
api/anon_main.py : sur un index vide (avant la première indexation), le journal affichait « Impossible de construire l’index : division by zero ». Message clair, sans erreur |
v2.20.3 |
2026-10-14 |
| 86 |
§0 étapes 2 et 4 : PKI à deux niveaux. Certificats listés puis exportés par empreinte (un filtre sur le nom et « le premier » sont ambigus, la racine figurant à plusieurs endroits), fichier de chaîne racine plus autorité intermédiaire, contrôle openssl s_client |
v2.20.3 |
2026-10-14 |
| 87 |
§0 étape 7 et §1.5 : cp refuse d’écrire dans le lien .env sans cible, et sed -i sur le lien le remplace par un fichier en clair sur le disque système. Commandes sur le vrai chemin ; docker compose up -d et non restart pour relire le .env |
v2.20.3 |
2026-10-14 |
| 88 |
§0 étape 14, §14.8.2, §16.8 : connexion à placer dans la section « API compatibles OpenAI » ; attributs LDAP distingués (courriel userPrincipalName, nom d’utilisateur sAMAccountName) ; désactivation des titres, étiquettes et questions de suivi (quatre appels par question dans le lab) ; §15.3.3 : contrôle luksDump qui n’affichait qu’un emplacement de clé sur deux ; §1.4 : versions de Docker relevées sur une VM neuve |
v2.20.3 |
2026-10-14 |
| 89 |
Open WebUI v0.11.3 : appels supplémentaires à rag-api par conversation (titre, étiquettes, suggestions). Sur la VM neuve déployée avec le Compose du dépôt (variables d’état initial), une seule ligne au journal par question, y compris après des réglages de l’interface personnelle de l’utilisateur, qui sont sans effet sur ces appels |
v2.20.4 |
2026-10-16 |
| 93 |
deploy.sh : une coupure passagère vers pypi.org arrêtait le déploiement sur l’installation des paquets Python. --retries 10 --timeout 60, message d’erreur explicite ; le script est relançable |
v2.20.4 |
2026-10-17 |
| 94 |
DNS : un DNS public ajouté à côté de celui du domaine (contournement de la coupure du point 93) a fait échouer LDAP (invalid server address, refus 403 pour tous) et la lecture des droits (NT_STATUS_INVALID_PARAMETER) au deuxième redémarrage, systemd-resolved étant resté sur le serveur public. deploy.sh contrôle la résolution du contrôleur de domaine et du serveur de fichiers et signale un DNS public ; acl_resolver.py contrôle la résolution avant la première lecture ; §0 étape 4 réécrite (contrôler l’existant, ne rien modifier s’il convient, jamais de DNS public), §5.3.1, §15.3.5 et dépannage |
v2.20.4 |
2026-10-17 |
| 95 |
acl_resolver.py : un mot de passe refusé était réessayé sur chaque fichier. Le test du garde-fou avec un mot de passe faux a verrouillé svc-rag dans l’Active Directory au quatrième fichier, et avec lui la connexion de tous les utilisateurs. Arrêt au premier refus d’authentification (mot de passe, compte verrouillé, désactivé ou expiré), message [GARDE-FOU] aussi sur la sortie d’erreur (repris dans le courriel de synchronisation) ; test du garde-fou par un partage inexistant (§0 étape 16, §5.4.2b), déverrouillage documenté |
v2.20.4 |
2026-10-17 |
| 96 |
§3.7 : la procédure n’avait jamais pu fonctionner. Les snapshots étaient écrits dans le conteneur (/qdrant/snapshots), introuvables sur la VM et perdus à la recréation du conteneur ; la restauration était envoyée en POST (réponse 404 sans message) au lieu de PUT ; la suppression des données effaçait aussi les snapshots. QDRANT__STORAGE__SNAPSHOTS_PATH dans le Compose, copie hors de qdrant_data avant la suppression, remise en place, PUT. Restauration complète validée (76 et 1 616 extraits, droits et cloisonnement identiques) |
v2.20.4 |
2026-10-17 |
| 97 |
Avertissement « le contrôle automatique n’a pas pu rattacher toutes les affirmations » à tort sur une réponse correcte : le modèle avait recopié un nom de fichier sans son accent, et le contrôle exact des citations le jugeait inexistant. normaliser_citations remplace une citation par le nom réel quand, sans accents ni casse, elle correspond à un seul document fourni ; le contrôle exact (verifier_citations) est inchangé. Le journal indique le contrôle qui a conclu (controle_echoue) ; quatre tests unitaires (test_citations.py) |
v2.20.4 |
2026-10-16 |
| 98 |
n8n (§0 étape 15) : les identifiants des workflows importés ne correspondent à rien et doivent être sélectionnés à nouveau dans chaque nœud ; jeton d’administration dans un identifiant Header Auth restreint au domaine rag-api, et non à recopier dans le nœud ; expéditeur égal à la boîte authentifiée (SendAsDenied sinon) ; destinataire interne ; test du courriel par épingle sur le nœud amont. Fuseau Europe/Zurich (n8n comptait en America/New_York) ; WEBHOOK_URL, variable lue par n8n, à la place de N8N_WEBHOOK_URL dans le Compose (rectifié en v2.21.1, point 117 : c’est N8N_WEBHOOK_URL qui fait foi depuis n8n 2.35) ; mention publicitaire de n8n retirée du courriel de rappel |
v2.20.4 |
2026-10-17 |
| 99 |
DOCUMENTATION_PATHS : la valeur par défaut était le dossier du lab (DOIT4EVERYONE). Vide par défaut (tout le partage dans documents), finalité des deux collections expliquée par deploy.sh, env.example et §0 ; présence du dossier contrôlée après le montage ; chemin avec sous-dossier refusé. §5.9, règle 1 : la description d’un sous-dossier homonyme routé vers documentation ne correspondait pas au code (comparaison du début du chemin), corrigée |
v2.20.4 |
2026-10-17 |
| 100 |
Partage monté en écriture (rw) par le §0 et le §5, en lecture seule (ro) par deploy.sh. Lecture seule partout ; deploy.sh signale un montage existant en écriture |
v2.20.4 |
2026-10-17 |
| 101 |
Open WebUI (§0 étape 14) : libellés LDAP de l’interface en français relevés ; réglages d’administration et réglages personnels distingués |
v2.20.4 |
2026-10-16 |
| 102 |
deploy.sh : première indexation et synchronisation des droits proposées en fin de déploiement (facultatives, journalisées, un échec n’annule pas le déploiement) ; tests des citations lancés ; résumé final corrigé (étapes n8n, snapshot, coquilles) |
v2.20.4 |
2026-10-17 |
| 103 |
Rapports et journaux (/var/log/rag, rapports des scripts) créés lisibles par tous les comptes de la VM (644). Créés en 640 (umask 027). Les fichiers existants gardent leurs droits : chmod 640 /var/log/rag/*.json /var/log/rag/*.jsonl |
v2.20.4 |
2026-10-17 |
| 104 |
État de santé de rag-api absent de docker ps : contrôle de santé ajouté au Compose ; §0 étape 9 et §15.3.5 précisent que qdrant et n8n restent en Up sans mention |
v2.20.4 |
2026-10-17 |
| 105 |
Open WebUI (port 3001) et n8n (port 5678) publiés sur le réseau en HTTP : mots de passe LDAP, sessions et questions en clair. Frontal Nginx en HTTPS, seul service qui publie des ports (80, 443, 5678), sous un nom DNS propre à la stack ; certificat de l’autorité interne ou auto-signé ; WebSocket, réponses au fil de l’eau, délai de 600 s ; n8n configuré derrière un frontal (N8N_PROTOCOL, N8N_PROXY_HOPS, WEBHOOK_URL, cookie sécurisé). Procédures d’obtention et de renouvellement du certificat (§9.8) |
v2.21.0 |
2026-10-18 |
| 106 |
Requêtes par adresse IP ou par un autre nom servies comme les autres. Serveurs par défaut : connexion fermée sans réponse en HTTP (return 444), négociation TLS refusée en HTTPS (ssl_reject_handshake) ; /sante exposé pour la supervision, réponse minimale. Testé hors lab (Nginx 1.24), puis validé sur la VM au rejeu du 19 octobre 2026 (000, code 35, 301) |
v2.21.0 |
2026-10-18 |
| 107 |
Secrets d’exemple : un simple avertissement au démarrage depuis la 2.17.0 (point 45). La RAG API refuse de démarrer sur un secret vide, une valeur d’exemple (changeme…, gabarit <…>), un jeton de moins de 32 caractères ou deux jetons identiques ; deploy.sh refuse un jeton saisi trop court |
v2.21.0 |
2026-10-17 |
| 108 |
/query acceptait API_TOKEN et répondait au nom du compte déclaré dans la requête (user_id) : tout détenteur du jeton d’Open WebUI pouvait se faire passer pour un autre utilisateur. Réservé à ADMIN_TOKEN ; test_cloisonnement.py adapté |
v2.21.0 |
2026-10-18 |
| 109 |
Images désignées par leur seul numéro de version, dépendances Python sans version : une reconstruction pouvait installer un autre contenu. Images figées par empreinte (@sha256), image de base de la RAG API figée, requirements.txt relevé par pip freeze ; Nginx sur la branche stable 1.30. Deux constructions identiques, aucun téléchargement au pull |
v2.21.0 |
2026-10-17 |
| 110 |
Open WebUI invitait à installer une nouvelle version (bannière v0.12.3), contraire à la règle du §16.8. ENABLE_VERSION_UPDATE_CHECK=false ; revue des versions inscrite à l’audit périodique (§17.6) |
v2.21.0 |
2026-10-17 |
| 111 |
Aucune alerte si la stack s’arrête, si la synchronisation ne tourne plus ou si le certificat expire. Contrôles définis (§16.10) ; nœud n8n « Signal supervision (Push) », désactivé par défaut, qui ne bloque jamais le courriel d’erreur ; exemple avec Uptime Kuma validé (sonde /sante avec échéance du certificat, sonde Push, courriel d’alerte reçu) |
v2.21.0 |
2026-10-18 |
| 112 |
deploy.sh : nom de la stack demandé et contrôlé (DNS vers la VM) ; certificat fourni contrôlé (clé, nom, échéance) ou auto-signé généré, auto-signé existant signalé ; /etc/rag-tls sur le disque chiffré ; configuration de Nginx au nom de la stack ; OWUI_JWT_SECRET généré ; cinq conteneurs et /sante contrôlés à travers Nginx ; adresses finales en HTTPS |
v2.21.0 |
2026-10-18 |
| 113 |
tests-apres-modification.md : les questions de test transmettaient l’identité par un en-tête simple, refusé depuis l’identité signée (point 44). Les commandes signent un jeton avec OWUI_JWT_SECRET, comme Open WebUI |
v2.21.0 |
2026-10-18 |
| 117 |
WEBHOOK_URL dépréciée depuis n8n 2.35 (alias de N8N_WEBHOOK_URL, avertissement au démarrage) ; le point 98 avait fait le changement dans le mauvais sens. N8N_WEBHOOK_URL dans le Compose, disponible depuis n8n 2.30 (documentation de n8n) |
v2.21.1 |
2026-10-18 |
| 118 |
Ancien point doc.3. N8N_BASIC_AUTH_* dans le Compose et le .env, sans effet depuis n8n 1.0 : fausse impression de protection. Retirées ; compte propriétaire de n8n à créer dès la première ouverture (§7.1.1, §0 étape 15) |
v2.21.1 |
2026-10-18 |
| 119 |
Fin de deploy.sh : /sante contrôlé avec curl -k, qui prouve que Nginx répond mais pas que le certificat est de confiance. Avec un certificat de l’autorité interne, second contrôle avec la chaîne (--cacert) |
v2.21.1 |
2026-10-18 |
| 120 |
Portée du chiffrement non dite : le TLS s’arrête à Nginx. Tableau des liaisons au §9.8.1, liaison vers le serveur de modèles en clair rappelée (point 72). « Toutes les images figées » inexact : le reranker facultatif ne l’est pas ; formulation corrigée |
v2.21.1 |
2026-10-18 |
| 125 |
deploy.sh réécrivait /root/rag-stack/.env sans contrôle : relancé sur une installation en service, il remplaçait tous les jetons et effaçait les réglages Microsoft 365, alors que le §0 le disait « relançable sans dommage ». Avant toute modification, le script signale un .env existant, demande confirmation (refus par défaut, rien n’est modifié) et en garde une copie datée en 600. Une procédure de mise à jour d’une installation existante reste à écrire (passage de la VM Microsoft 365 en 2.21) |
v2.21.1 |
2026-10-18 |
| 126 |
s10/mesure_s10.py et s10/charge_s10.py transmettaient l’identité par l’en-tête simple, refusé depuis la 2.21.0 (403 à chaque question) : les campagnes du §10 et le test de charge ne pouvaient plus tourner. Les deux scripts signent un jeton avec OWUI_JWT_SECRET, comme Open WebUI |
v2.21.1 |
2026-10-18 |
| 127 |
§9.8.4 : la chaîne de Nginx se construit avec ad-subca.pem, que le §0 ne créait pas (il ne produit que ad-chain.pem). Constaté au rejeu du 19 octobre 2026. Le §0 (étape 4) garde l’intermédiaire en ad-subca.pem ; le §9.8.4 donne la commande d’extraction pour une installation antérieure et le cas d’une autorité à un seul niveau |
v2.21.2 |
2026-10-19 |
| 128 |
deploy.sh : le garde-fou du .env (point 125) intervenait après les seize questions, qu’il fallait remplir pour rien en cas de refus. Placé au début du script, avant toute question |
v2.21.2 |
2026-10-19 |
| 129 |
Résumé final de deploy.sh : le compte propriétaire de n8n, à créer tout de suite (sinon n’importe quel poste peut le créer), n’y figurait pas. Étape 0 ajoutée |
v2.21.2 |
2026-10-19 |
| 130 |
Rapports d’indexer.py et d’acl_resolver.py lancés à la main : sans --rapport, écrits dans /root/rag-pipeline, sur le disque système non chiffré (noms de fichiers et groupes autorisés). Le résumé de deploy.sh et la checklist du §0 donnent --rapport /var/log/rag/... |
v2.21.2 |
2026-10-19 |
| 131 |
n8n 2.36.9 annonce que les paquets communautaires non vérifiés seront refusés par défaut dans une version future. N8N_UNVERIFIED_PACKAGES_ENABLED=false fixé dès maintenant dans le Compose |
v2.21.2 |
2026-10-19 |
| 10 |
Recherche par mots-clés (BM25) : les candidats étaient autorisés sur les droits mémorisés dans l’index, construit au démarrage et en fin de synchronisation. Un droit retiré dans Qdrant restait valable par ce chemin jusqu’à la reconstruction (pendant la synchronisation, ou jusqu’à une heure après un acl_resolver.py lancé à la main) ; un document supprimé restait trouvable. Gravité sous-estimée jusqu’ici (« faible ») : la relecture des voisins, censée arrêter l’extrait, le remettait quand elle revenait vide (fenetre or extraits), c’est-à-dire précisément quand le droit avait été retiré ; sans extension du contexte, aucune relecture. Signalé par une revue externe du code. Chaque candidat est relu dans Qdrant par son identifiant et ses droits contrôlés sur cette lecture (revalider_bm25), refus par défaut ; repli supprimé. Fuite reproduite sur le code de la 2.21.2 et absente après correction : test_revalidation_bm25.py, 11 tests. Sur le vrai Qdrant de la VM de test (test_revocation_bm25.py, §16.5.1) : FUITE en 2.21.2 par les deux chemins, OK en 2.21.3 ; test de non-divulgation inchangé (70 OK, 2 INFO) |
v2.21.3 |
2026-10-20 |
| 133 |
deploy.sh : un échec des tests unitaires des droits sur la recherche par mots-clés (test_revalidation_bm25.py) n’affichait qu’un avertissement, et le déploiement se terminait normalement. Signalé par une seconde revue externe. L’échec arrête la RAG API et termine le script en erreur (« Déploiement incomplet ») ; vérifié en simulation |
v2.21.4 |
2026-10-20 |
| 134 |
search_qdrant, revalider_bm25, etendre_complements : sans groupes, les contrôles d’accès étaient sautés. Aucun chemin exposé (/query et /v1 refusent ce cas avant la recherche), mais une route future qui l’oublierait aurait servi une recherche sans filtre. Signalé par une seconde revue externe. Refus dans les fonctions elles-mêmes : 403 pour la recherche, aucun résultat pour les deux autres ; trois tests unitaires ajoutés (14 au total, tous OK sur la VM de test) |
v2.21.4 |
2026-10-20 |
| 135 |
acl_resolver.py : une erreur de Qdrant pendant l’écriture des droits renvoyait 0, lu comme « non indexé » ; code de sortie 0, synchronisation réussie, aucune alerte, anciens droits conservés dans Qdrant. Même défaut pour la fermeture d’un fichier aux ACL illisibles, la suppression des extraits d’un fichier effacé et la lecture des orphelins. Signalé par une troisième revue externe ; reproduit sur le code de la 2.21.4 (Qdrant simulé). Trois issues distinctes, seconde tentative, code 2 et rapport ; synchronisation en échec et alerte ; documents retirés de la recherche jusqu’au prochain passage sans échec, liste gardée sur disque ; même règle pour les fichiers SharePoint en erreur (§16.5.2). VM de test : 12 tests unitaires OK, synchronisation réelle réussie ; échec réel d’écriture non provoqué |
v2.21.5 |
2026-10-20 |
| 136 |
/admin/sync cherchait le statut non_indexé dans le rapport des droits, qui écrit non_indexe : les fichiers non indexés n’étaient jamais comptés en quarantaine. Les deux graphies sont acceptées |
v2.21.5 |
2026-10-20 |
| 137 |
deploy.sh : un fichier de test de sécurité absent sautait le contrôle sans le dire. test_revalidation_bm25.py et test_echec_droits.py sont obligatoires : absent ou en échec, RAG API arrêtée et déploiement en erreur ; vérifié en simulation |
v2.21.5 |
2026-10-20 |
| 138 |
sp_indexer.py : un fichier déjà indexé qui dépassait ensuite SP_MAX_FILE_MB sortait sans relecture des droits ni suppression : anciens extraits et anciens droits conservés, sans alerte. Extraits supprimés ; suppression refusée = fichier en erreur, retiré de la recherche. Signalé par une quatrième revue externe |
v2.21.6 |
2026-10-20 |
| 139 |
RAG API (2.21.5) : un passage avec le code 2 remplaçait la liste des documents retirés ; une lecture des orphelins en échec, seul incident, la vidait et rendait visibles des documents retirés. Seul un passage complet retire des documents de la liste ; un passage incomplet ajoute les orphelins probables, ou tout le partage si leur inventaire échoue ; site ou bibliothèque SharePoint illisible retiré par périmètre. Signalé par une quatrième revue externe |
v2.21.6 |
2026-10-20 |
| 140 |
Registre acl_bloques.json : écriture non atomique ; absent ou illisible au démarrage, la RAG API démarrait sans rien retirer. Écriture atomique avec incident signalé ; registre créé vide par deploy.sh ; absent ou illisible, questions refusées (503) jusqu’à une synchronisation complète. Option ACL_INCERTAIN_FERME pour suspendre une origine après un passage abandonné ou interrompu. Signalé par une quatrième revue externe. VM de test : refus au démarrage sans registre, levée par une synchronisation complète, registre relu après redémarrage |
v2.21.6 |
2026-10-20 |
| 141 |
RAG API (2.21.6) : un échec d’écriture du registre était signalé mais les questions restaient servies ; après un redémarrage, l’ancien registre était relu comme valide, sans les documents retirés depuis. Questions refusées tant que le registre n’est pas écrit ; marqueur « synchronisation des droits en cours » posé avant toute modification des droits et retiré après l’écriture du résultat ; présent au démarrage, questions refusées jusqu’à une synchronisation terminée ; marqueur impossible à écrire, droits non synchronisés. Dossier synchronisé après le renommage. Signalé par une cinquième revue externe. VM de test : synchronisation interrompue simulée, questions refusées puis servies après une synchronisation |
v2.21.7 |
2026-10-20 |
| 142 |
Registre lisible mais mal formé ({}, chaîne au lieu d’une liste, version inconnue) accepté sans contrôle. Validation stricte du schéma ; toute anomalie = état inconnu, questions refusées. Signalé par une cinquième revue externe |
v2.21.7 |
2026-10-20 |
| 143 |
ACL_INCERTAIN_FERME valait 0 par défaut : après un passage abandonné ou interrompu, les derniers droits connus restaient appliqués. Défaut à 1 : origine suspendue jusqu’à un passage complet ; 0 reste possible par choix documenté |
v2.21.7 |
2026-10-20 |
| 144 |
Synchronisations arrêtées (n8n arrêté, workflow désactivé) : les derniers droits connus restaient appliqués sans limite de durée, sans alerte. Âge maximal des droits (ACL_AGE_MAX_HEURES, 3 heures par défaut) : date de la dernière synchronisation complète enregistrée dans le registre (version 3), mise à jour seulement si toutes les origines ont abouti sans passage incertain et si le registre est écrit ; au-delà, date absente ou dans le futur, questions refusées. Questions servies pendant une synchronisation normale : choix documenté (§5.4). Signalé par une sixième revue externe |
v2.21.8 |
2026-10-21 |
| 145 |
Marqueur « synchronisation des droits en cours » posé après l’indexation : une indexation interrompue n’était pas couverte. Marqueur posé avant ; droits non garantis, indexation sautée. Signalé par une sixième revue externe |
v2.21.8 |
2026-10-21 |
| 146 |
deploy.sh recréait un registre vide si celui-ci manquait sur une installation existante, ce qui effaçait la liste des documents retirés. Registre créé seulement sur une installation neuve ; installation existante sans registre, arrêt en erreur. Signalé par une sixième revue externe |
v2.21.8 |
2026-10-21 |
| 147 |
deploy.sh : un test de sécurité absent du dossier source n’était pas copié, sans erreur ; une ancienne copie restée dans /root/rag-pipeline était alors lancée à sa place. Présence obligatoire dans le dossier source et copie contrôlée. Signalé par une sixième revue externe |
v2.21.8 |
2026-10-21 |
| 148 |
/health répondait « ok » même avec des droits périmés ou inconnus : la supervision ne voyait rien. État des droits dans la réponse, toujours en HTTP 200. Signalé par une sixième revue externe |
v2.21.8 |
2026-10-21 |
| 149 |
s10/charge_s10.py comparait les médianes de paliers qui ne posaient pas les mêmes questions (« ×14,8 » à 8 questions, sans rapport avec la charge). Mesure de référence de chaque question seule, gain de chaque série ; compte rendu au §10.12 |
v2.21.8 |
2026-10-21 |
| 150 |
Procédures de mise à jour des Releases 2.21.2 à 2.21.7 : seul main.py était remplacé, jamais le docker-compose.yml. Sur la VM de test, le Compose était resté en 2.21.1 : ACL_INCERTAIN_FERME n’était pas transmis (valeur par défaut du code, 1, appliquée) et une valeur d’ACL_AGE_MAX_HEURES passée à Compose était ignorée sans message. Remplacement du Compose dans la procédure de la 2.21.8, avec comparaison préalable |
v2.21.8 |
2026-10-21 |
| 151 |
Verdict du juge lu sur la seule clé ancree : un juge qui répond « ancrée » tout en citant une affirmation non sourcée laissait passer la réponse comme vérifiée. Mesuré le 22 octobre 2026 (s10/mesure_juge.py) : le juge 4B d’Ollama l’a fait 14 fois sur 72 jugements de versions falsifiées, soit un fait inventé sur trois accepté. Liste non vide = réponse non ancrée ; aucune des 210 réponses réelles jugées n’est bloquée par la règle |
v2.21.9 |
2026-10-22 |
| 152 |
Réponse de moins de 200 caractères contenant « ne figure pas dans les documents » acceptée sans juge : un fait inventé suivi de cette phrase échappait à la vérification. Seule la phrase de refus exacte est acceptée sans juge. Trouvé à la relecture du code après le point 151 |
v2.21.9 |
2026-10-22 |
| 153 |
Même relecture : verdict de Purview lu avec bool() (une chaîne « false » aurait autorisé ; mip-service renvoie un booléen, sans conséquence constatée) ; valeur par défaut « ancrée » dans la lecture du résultat du juge (sans conséquence, toutes les branches la fixent). Lecture stricte et défaut « non ancrée » |
v2.21.9 |
2026-10-22 |
| 154 |
Réponse du juge incomplète lue comme « ancrée » : {"ancree": true} sans liste, ou une liste null, chaîne vide, 0 ou objet, étaient normalisés en liste vide après le contrôle. « Ancrée » exige maintenant le booléen true et une liste vide ; sinon non ancrée. Signalé par une septième revue externe ; les nouveaux tests échouent sur le code de la 2.21.9 et passent sur la 2.21.10 |
v2.21.10 |
2026-10-22 |
| 155 |
test_citations.py, qui contrôle aussi la lecture du verdict du juge depuis la 2.21.9, restait facultatif dans deploy.sh (simple avertissement). Exigé dans le dépôt, copie contrôlée, obligatoire et bloquant comme les tests de sécurité des droits. Signalé par une septième revue externe |
v2.21.10 |
2026-10-22 |
| 156 |
ACL_AGE_MAX_HEURES converti par float() sans contrôle : nan rendait toute comparaison fausse (droits toujours frais), un négatif désactivait le contrôle, inf le rendait sans limite. 0 ou nombre fini positif ; sinon limite de 3 heures et alerte. Signalé par une septième revue externe |
v2.21.10 |
2026-10-22 |
| 157 |
Marqueur de synchronisation impossible à retirer en fin de passage : seulement journalisé, le rapport de /admin/sync annonçait un succès ; au redémarrage, questions refusées sans alerte préalable. Signalé comme erreur du rapport, l’alerte part ; questions toujours servies (droits à jour). Signalé par une septième revue externe |
v2.21.11 |
2026-10-22 |
| 158 |
Droits comparés par noms (points ouverts 14, auth.1, auth.2) : groupe principal ignoré (documents autorisés à « Utilisateurs du domaine » invisibles), noms CN et pré-Windows 2000 confondus (collision possible), identités intégrées sans correspondance. Droits en SID des deux côtés : smbcacls --numeric (ligne non reconnue = fichier illisible, type inconnu = refus) et tokenGroups (illisible = aucun groupe) ; groupes intégrés ignorés par défaut, ACL_SID_ETENDUS ; contrôle de migration (documents_non_migres_sid). Revue externe en appui. VM de test : 1 692 extraits migrés, non-divulgation 79 OK, 2 INFO, dont un compte réduit au groupe principal |
v2.22.0 |
2026-10-22 |
| 159 |
Refus ignoré sur une identité absente des SID de l’utilisateur (revue externe, huitième) : un refus à « Tout le monde » ou « Utilisateurs authentifiés » sur un document autorisé à un groupe laissait les membres du groupe le lire ; un refus aux Administrateurs intégrés était écarté par acl_resolver.py. Règle des refus asymétrique (refus_applicable) : appliqué pour toute identité dont l’appartenance ne se lit pas (identités bien connues, groupes intégrés, SID d’une autre machine ou d’un autre domaine), jamais aux identités de service ni aux autres comptes du domaine ; autorisations inchangées ; tous les refus conservés ; rapport documents_refus_pour_tous ; 12 tests de plus dans test_sid.py, dont 5 échouent sur la 2.22.0. Validé le 22 octobre 2026 sur la VM de test avec un vrai refus à « Tout le monde » (lecture de données seule) sur un contrat client : même ACL, même compte membre du groupe autorisé, accès True en 2.22.0, accès False en 2.22.1 |
v2.22.1 |
2026-10-22 |
| 160 |
Rapport documents_refus_pour_tous incomplet (revue externe, neuvième) : refus_pour_tous ignorait tout SID S-1-5-21-…, sans distinguer le domaine d’une autre machine ou d’un autre domaine ; un document fermé à tous par un refus à un groupe local du serveur de fichiers n’était pas listé. Défaut du rapport seulement, la décision d’accès (check_access) les appliquait. La RAG API lit le SID du domaine dans l’annuaire (sid_domaine) et le transmet à acl_resolver.py (SID_DOMAINE) ; inconnu, le journal le signale. 4 tests de plus dans test_sid.py. Validé le 22 octobre 2026 sur la VM de test avec un refus à un groupe local du serveur de fichiers (lecture de données seule), dont le compte d’indexation n’est pas membre : document resté indexé, sid_domaine lu dans l’annuaire, document listé dans documents_refus_pour_tous, accès False pour un compte membre du groupe autorisé ; test_sid.py 32, test_echec_droits.py 46, test_revalidation_bm25.py 14 et test_citations.py 20 tests OK ; refus et groupe retirés, rapport à 0, test de non-divulgation 79 OK, 2 INFO |
v2.22.2 |
2026-10-22 |
| 161 |
Courriel de synchronisation n8n (ancien point ouvert 34) : la commande de contrôle proposée cherchait le statut « non_indexé », alors que acl_resolver.py écrit « non_indexe » ; elle ne trouvait pas ces fichiers. main.py les comptait déjà (2.21.5). Commande corrigée dans n8n-sync-corpus.json |
v2.22.2 |
2026-10-22 |
| 162 |
Mot de passe de svc-rag en clair sur le disque système : /etc/smbcredentials/svc-rag créé par le §0 (étape 5), le §5.3.2 et deploy.sh, hors du volume chiffré qui protège le .env (constat du rejeu du 23 octobre 2026). Fichier réel dans /srv/rag-donnees/secrets/smb-svc-rag, lien à l’emplacement habituel ; deploy.sh crée le lien quand le volume est monté et remplace un ancien fichier en clair ; fstab : _netdev et x-systemd.after=/srv/rag-donnees (partage monté après le volume). Validé au redémarrage avec la stack en service ; deploy.sh vérifié par simulation (installation neuve, ancien fichier, sans volume chiffré) |
v2.22.3 |
2026-10-24 |
| 164 |
deploy.sh : le contrôle du disque chiffré ne vérifiait que le montage de /srv/rag-donnees et la présence du lien .env, puis annonçait « liens en place ». Un dossier qdrant_data, openwebui_data ou n8n_data ordinaire, ou des journaux sur le disque système, passaient inaperçus (onzième revue externe). Chaque chemin sensible (trois dossiers de données, .env, /var/log/rag, /etc/rag-certs, /etc/rag-tls) doit aboutir sur le volume, comparé par périphérique, ce qui accepte aussi le montage bind du §15.3.4 ; absent, il est créé comme lien ; sur le disque système, le déploiement s’arrête. Vérifié par simulation : installation neuve, liens en place, dossier en clair, .env en clair, montage bind |
v2.22.4 |
2026-10-24 |
| 165 |
Migration du §15.3.4 (journaux par montage bind) : la condition de démarrage de Docker ne portait que sur /srv/rag-donnees ; si le montage de /var/log/rag échouait, Docker démarrait et la RAG API écrivait journal nLPD, rapports et registre des droits dans le dossier du disque système (onzième revue externe). Seconde condition ConditionPathIsMountPoint=/var/log/rag, réservée au montage bind ; passage au lien du §1.5 décrit pour unifier |
v2.22.4 |
2026-10-24 |
| 44 |
Identité transmise par en-têtes simples entre Open WebUI et la RAG API : quiconque connaissait API_TOKEN pouvait écrire l’adresse d’un autre compte. Open WebUI signe l’identité (FORWARD_USER_INFO_HEADER_JWT_SECRET, jeton HS256 de cinq minutes), la RAG API vérifie signature, émetteur et échéance, et ignore les en-têtes simples (403). Validé : compte de test avec ses 17 groupes, en-tête simple refusé, cloisonnement 6/6 |
v2.21.0 |
2026-10-18 |