L’assistant propose une requête qui commence par SELECT. Elle paraît inoffensive et le compte SQL est en lecture seule. Pourtant, elle peut demander une table étrangère au dossier, révéler une colonne sensible ou monopoliser une connexion. Le problème commence lorsque le service traite une proposition de requête comme une capacité autorisée, sans vérifier ce qu’elle peut lire et consommer dans le moteur.
En pratique, la protection repose sur plusieurs frontières contrôlées : les données exposées, les constructions SQL admises, le rôle connecté et le budget d’exécution. Une interrogation IA des données métier doit définir ces frontières avant d’accepter une proposition. La validité syntaxique ne remplace ni les permissions ni la vérification du résultat métier.
Nous exécutons quatorze requêtes manuscrites contre un contrat syntaxique étroit et sept sondes séparées sur PostgreSQL 18.6. Trois commandes fictives rendent visibles les lignes et colonnes accessibles ; aucun modèle ou environnement client n’intervient. La première lecture confiée à une IA sur mesure pour vos données doit être décrite par une vue et un rôle réellement limités. Le contrat SQL complète cette frontière en refusant les formes de requête que le parcours ne veut pas exposer.
Pour qui borner une lecture SQL proposée par une IA
Identifier la lecture utile au lieu d’ouvrir toute la base
Le sujet concerne une équipe qui souhaite répondre à des questions métier à partir de données structurées. La demande peut porter sur quelques commandes, un état de dossier ou un indicateur. Le premier périmètre doit préciser les objets utiles, la population consultable et les attributs réellement nécessaires. Donner accès à tout un schéma pour faciliter une démonstration transforme un besoin limité en capacité de lecture beaucoup plus large.
Un responsable métier nomme la décision préparée et le sens des données ; le propriétaire de la base choisit les objets exposés ; l’équipe applicative définit les formes admises et la restitution. Ces responsabilités se rejoignent dans un contrat. Le prompt peut expliquer ce contrat au modèle, mais l’exécuteur doit le vérifier sans lui faire confiance. Une consigne « ne consulte pas les contacts » ne retire aucun privilège SQL.
Choisir une interface plus simple lorsqu’elle suffit
Si les utilisateurs posent quelques questions connues, des requêtes paramétrées ou des outils métier nommés peuvent offrir une frontière plus facile à vérifier. Le modèle choisit une question et ses paramètres ; le serveur conserve la requête. Ce choix évite de déléguer inutilement la composition SQL. Il ne dispense pas du contrôle des droits ou des limites sur les paramètres et les résultats.
Le SQL proposé devient pertinent lorsque la variété des lectures justifie son coût de validation. Même dans ce cas, toutes les constructions ne doivent pas être ouvertes dès le début. Notre banc accepte seulement une petite projection ordonnée d’une vue. Il ne couvre pas les jointures, agrégats ou filtres arbitraires. Cette restriction rend les garanties lisibles, mais elle impose de refuser certaines demandes légitimes et d’organiser une autre voie.
Séparer données, forme SQL et consommation
Écrire ce que chaque protection décide réellement
Une vue peut retirer des colonnes et limiter une population. Un rôle peut interdire la table privée. Un contrôleur syntaxique peut refuser une commande d’export ou une fonction. Un délai peut interrompre une requête trop longue. Ces décisions portent sur des risques différents. Les additionner dans une formule « SQL sécurisé » sans préciser leur portée rend difficile l’analyse d’un refus ou d’une fuite.
| Frontière | Contrôle du banc | Limite à conserver |
|---|---|---|
| Données | Vue A, order_id et total | Population fixe, pas de délégation utilisateur |
| Privilèges | Connexion ia_reader_3029, SELECT sur la vue | Les capacités publiques du moteur restent à examiner |
| Syntaxe | Une projection et un LIMIT entier 1–10 | Sous-ensemble étroit, pas de SQL général |
| Temps | statement_timeout 80 ms | Délai illustratif, pas de capacité garantie |
| Attente | lock_timeout 40 ms configuré | Aucun scénario de verrou concurrent exécuté ici |
Le banc conserve explicitement cette dernière limite : configurer un délai de verrou ne démontre pas son comportement sous contention. De même, deux lignes retournées ne mesurent pas la performance d’un entrepôt volumineux. La recette de production doit distinguer contrôles configurés, contrôles provoqués et garanties encore à éprouver sur ses volumes et ses interfaces réelles.
Garder l’exactitude de la réponse comme une autre obligation
Une requête peut respecter toutes ces frontières et calculer le mauvais indicateur. La vue peut être admissible mais son grain mal compris ; une période ou un état peuvent être interprétés à tort. La sécurité d’exécution décide si la capacité est autorisée. L’évaluation métier décide si le résultat répond à la question. Confondre ces deux recettes laisse passer des nombres faux parce qu’ils ont été obtenus sans incident de permission.
Le banc de requêtes valides qui faussent un résultat examine cette seconde frontière avec des montants et des jointures exécutés. Ici, nous conservons volontairement une lecture simple. Le résultat attendu est la liste A01 et A02 avec leurs totaux, ce qui permet de concentrer la preuve sur l’accès, la forme et les refus sans inventer une qualité de raisonnement du modèle.
Exposer une vue bornée sans donner la table privée
Retirer les données qui ne servent pas à la mission
La table fictive contient A01, société A, total 120 ; A02, société A, total 80 ; B01, société B, total 900. Chaque ligne possède également un contact fictif. La vue ai_3029.orders_view expose seulement order_id et total pour A. Le lecteur reçoit deux lignes et deux colonnes ; la table privée conserve trois lignes et les contacts. Le total de contrôle de la table est 1 100.
CREATE OR REPLACE VIEW ai_3029.orders_view
WITH (security_barrier=true) AS
SELECT order_id,total
FROM private_3029.orders
WHERE company='A';
La documentation PostgreSQL CREATE VIEW décrit les options et les vérifications de privilèges des vues. Notre vue utilise son propriétaire pour l’accès aux objets sous-jacents et conserve une barrière de sécurité. Le rôle reçoit SELECT sur la vue, sans USAGE sur le schéma privé. Ce montage doit être relu avec les propriétaires et fonctions réellement présents dans une installation.
Ne pas transformer un filtre fixe en preuve de droits individuels
Le filtre A est constant dans le laboratoire. Il démontre que cette vue ne retourne pas B01 ; il ne démontre pas que chaque utilisateur d’une application voit automatiquement sa propre société. Un service multi-entités doit porter une identité vérifiée jusqu’au contrôle d’accès approprié. Ajouter un identifiant de société libre dans le SQL proposé ne suffit pas à établir que cette société est autorisée.
Une évolution de vue constitue également une évolution de capacité. Ajouter un contact ou supprimer un filtre peut rendre admissible une lecture qui était auparavant impossible. Le propriétaire de données doit revoir la projection, les permissions et les cas négatifs avant publication. Le contrat applicatif et les objets réellement installés doivent rester rapprochables ; un nom de vue inchangé ne prouve pas que son contenu autorisé est resté identique.
Vérifier le rôle réellement connecté
Tester une connexion lecteur et pas une simulation de privilèges
Les sondes lecteur ouvrent réellement une connexion avec ia_reader_3029. Ce rôle n’est ni superutilisateur ni créateur de rôles et ne contourne pas les politiques RLS. Le laboratoire retire aussi CREATE et TEMPORARY de PUBLIC sur sa base dédiée. Le rôle peut utiliser le schéma de la vue et la lire. Il ne possède aucune permission directe sur la table privée.
Cette méthode évite une confusion fréquente : ouvrir une session superutilisateur, faire SET ROLE lecteur, puis considérer toutes les tentatives d’élévation comme représentatives d’un compte applicatif. L’identité de session initiale peut modifier ce qu’une session peut ensuite faire. Le banc se connecte donc directement comme lecteur pour ses six sondes ; une septième connexion propriétaire est nommée séparément et sert seulement à isoler la règle read-only.
Conserver les limites de la lecture seule
La référence PostgreSQL SET TRANSACTION décrit les opérations interdites dans une transaction read-only et les limites de cette notion. Ce mode ne transforme pas toutes les lectures possibles en lectures souhaitables. Il ne décide pas des populations à exposer et ne constitue pas une limite générale de consommation. Le rôle et la transaction doivent être contrôlés par l’exécuteur.
Dans notre banc, l’UPDATE demandé par le lecteur échoue d’abord avec une erreur de permission sur la vue, SQLSTATE 42501. Le contrôle propriétaire en transaction read-only échoue avec 25006. Les deux refus sont utiles, mais ils prouvent des mécanismes différents. Attribuer le premier au seul read-only aurait donné une explication incorrecte de la protection effectivement observée.
Admettre une forme étroite avec un arbre syntaxique
Décrire les constructions permises au lieu de rechercher des mots
Le contrôleur utilise pglast, version v8.5 dans la recette, pour obtenir un arbre syntaxique PostgreSQL. Il exige une instruction SELECT, une seule source qualifiée correspondant exactement à la vue, des colonnes explicitement admises, un ordre par order_id et un LIMIT entier compris entre 1 et 10. Les autres formes sont refusées avant connexion d’exécution.
Le contrat n’admet ni fonction ni étoile, ni alias libre, filtre, jointure, CTE, sous-requête, union, clause de verrouillage ou instruction supplémentaire. Ces exclusions sont des choix de périmètre, pas des affirmations selon lesquelles ces constructions seraient toujours dangereuses. Le parseur établit la structure ; notre contrôleur décide quelles structures le service accepte. Il ne résout pas les droits du moteur ni le sens métier d’une colonne.
Refuser une forme inconnue sans tenter de la réparer
Une instruction classée SELECT dans l’arbre syntaxique peut contenir un CTE modifiant des données ; une projection peut appeler une fonction coûteuse. Le contrôle doit examiner les structures présentes, pas seulement le premier mot ou une liste de chaînes interdites. Une forme non comprise doit produire un refus. Retirer une clause gênante puis exécuter le reste change la proposition et peut également changer le sens de la réponse attendue.
Le coût de cette stratégie est visible : une question nécessitant SUM ou une période filtrée ne passe pas notre contrat. Le service doit proposer une question déjà prise en charge, un outil paramétré ou une revue technique. L’élargissement demande une nouvelle spécification et ses essais adverses. Un parseur installé ne constitue pas, à lui seul, une garantie de sécurité pour toutes les requêtes que sa grammaire reconnaît.
Limiter temps et sortie sans confondre leurs effets
Faire porter les paramètres d’exécution par le serveur
Le serveur du banc ouvre BEGIN READ ONLY, fixe localement search_path à pg_catalog et configure statement_timeout à 80 ms et lock_timeout à 40 ms. La vue reste référencée avec son schéma explicite. La proposition cliente ne fournit aucune instruction de session. La documentation des paramètres de connexion PostgreSQL permet de vérifier leur portée avant adaptation.
BEGIN READ ONLY;
SET LOCAL search_path=pg_catalog;
SET LOCAL statement_timeout='80ms';
SET LOCAL lock_timeout='40ms';
Ces délais sont choisis pour une sonde locale courte ; ils ne représentent aucun SLA conseillé. Le budget réel dépend de la lecture, de sa charge et du parcours utilisateur. Il faut aussi borner connexions concurrentes, taille de réponse et usage de ressources selon l’environnement. Une connexion libérée proprement après annulation compte autant que le délai configuré ; la recette locale ne mesure pas un pool de production.
Ne pas prendre LIMIT pour une limite générale de travail
Exemple concret : la sonde moteur appelle pg_sleep(0.2) depuis la vue avec LIMIT 1. Une seule ligne de sortie est demandée, mais l’attente dépasse 80 ms et le moteur annule la requête avec 57014. Le contrat AST refuse déjà cette fonction dans le parcours normal. La sonde la contourne volontairement dans la base de laboratoire pour observer la protection de temps séparément.
Limiter les lignes retournées reste utile pour l’interface et le transfert, mais ne prouve pas qu’un tri ou un calcul coûte peu. Un budget d’exécution doit être éprouvé sur les lectures pertinentes, avec des données représentatives et une mesure de charge adaptée. Notre table de trois lignes ne permet aucune conclusion de capacité pour un ERP réel ou un corpus analytique volumineux.
Quatorze requêtes confrontées au contrat
Montrer quels refus surviennent avant le moteur
Les quatorze propositions sont manuscrites et connues à l’avance. Le banc vérifie leur verdict et n’exécute que les deux admises. La première retourne A01|120 et A02|80 ; la seconde, limitée à une ligne, retourne A01|120. Les douze autres n’obtiennent aucune exécution dans ce parcours. Ce résultat mesure le contrôleur défini, pas un taux de sécurité ou de précision d’un modèle.
| Cas | Proposition | Verdict |
|---|---|---|
| S29-01 | Deux colonnes de la vue, ordre, LIMIT 10 | admitted |
| S29-02 | Même lecture, LIMIT 1 | admitted |
| S29-03 | Table privée comme source | source_denied |
| S29-04 | UPDATE sur la table privée | statement_type_denied |
| S29-05 | SELECT avec CTE DELETE | select_shape_denied |
| S29-06 | Deux instructions SELECT | statement_count_denied |
| S29-07 | UNION de lectures | select_shape_denied |
| S29-08 | Appel pg_sleep dans la projection | projection_denied |
| S29-09 | Colonne contact non admise | projection_denied |
| S29-10 | Vue sans schéma explicite | source_denied |
| S29-11 | LIMIT absent | limit_denied |
| S29-12 | LIMIT 1000 | limit_denied |
| S29-13 | COPY d’un SELECT vers STDOUT | statement_type_denied |
| S29-14 | SET ROLE postgres | statement_type_denied |
Relier chaque verdict à sa responsabilité
Le refus source_denied signifie que la relation ne correspond pas au contrat, sans tester ses permissions dans la base. Projection_denied porte sur la forme ou la colonne proposée. Limit_denied indique un plafond absent ou incompatible. Ces codes permettent au service de choisir la suite sans exposer les détails internes de la base. Un message utilisateur doit traduire le périmètre pris en charge plutôt que reproduire aveuglément le SQL brut.
La recette doit conserver les entrées et leurs attentes, mais éviter de donner un accès d’administration à l’assistant pour expliquer un refus. Une nouvelle construction peut être légitime et rester non prise en charge. Le responsable du service arbitre son ajout avec le propriétaire de données et les budgets disponibles ; le modèle ne transforme pas spontanément un refus en exception au contrat.
Sept sondes pour observer les protections du moteur
Contourner le contrôleur seulement dans la recette isolée
Les sondes suivantes sont distinctes des propositions précédentes. Elles contournent volontairement le contrôleur dans la base fictive pour vérifier ce que refuse ou permet le moteur. Six utilisent la connexion lecteur ; une utilise le propriétaire en read-only. Toutes gardent le préfixe serveur et une fin de transaction. Le total privé reste 1 100 après les essais, sans modification des trois commandes.
| Cas | Sonde | Résultat observé |
|---|---|---|
| P29-01 | Lecture nominale de la vue | A01 120, A02 80 |
| P29-02 | Lecture de la table privée | 42501 : permission refusée sur le schéma |
| P29-03 | UPDATE sur la vue | 42501 : permission refusée sur la vue |
| P29-04 | pg_sleep(0.2), LIMIT 1 | 57014 : délai d’exécution dépassé |
| P29-05 | COPY (SELECT …) TO STDOUT | Export des deux lignes autorisées |
| P29-06 | SET ROLE postgres | 42501 : changement de rôle refusé |
| P29-07 | UPDATE privé, connexion propriétaire | 25006 : transaction read-only |
Comprendre pourquoi un export reste une lecture possible
Deuxième cas concret : P29-05 exécute COPY d’un SELECT sur la vue vers STDOUT. Le moteur retourne les deux lignes autorisées, même dans la transaction read-only. Il ne révèle pas B01 ou les contacts ; il montre qu’une forme d’export reste possible pour ces données. Le contrat applicatif refuse cette instruction parce que la capacité offerte est une lecture structurée contrôlée, sans mode d’export SQL libre.
Ce résultat n’est pas une fuite démontrée. L’utilisateur peut déjà recevoir les deux lignes via SELECT. Il distingue l’autorisation de données des modalités de sortie que le produit accepte. La recette doit tester ces modalités, la quantité exposée et les usages aval. Read-only ne signifie pas qu’un résultat sera automatiquement agrégé, minimisé ou présenté avec les explications métier nécessaires.
Faire du refus une décision compréhensible
Séparer demande non prise en charge et incident technique
Une fonction non admise ou un LIMIT trop grand relève du contrat. Une permission retirée au moteur indique un changement à examiner. Une annulation par délai signifie que la lecture n’a pas produit un résultat dans le budget. Le service doit conserver ces catégories au lieu d’afficher un même « aucun résultat » qui ferait passer un échec d’exécution pour une réponse métier vide.
L’abstention peut proposer une question connue, réduire le périmètre avec confirmation ou orienter vers un analyste. Elle ne doit pas déclencher une nouvelle requête avec davantage de privilèges pour obtenir une réponse coûte que coûte. Les agents qui utilisent un outil SQL ont besoin d’une sortie typée : refus, annulation ou résultat, avec un motif exploitable et sans divulgation inutile de la structure privée.
Tracer la capacité utilisée sans recopier toutes les données
La journalisation relie identité applicative, version de contrat, vue admise, décision du contrôleur, rôle moteur et état final. Cette instrumentation peut conserver une empreinte de proposition et le nombre de lignes, selon les besoins d’audit. Elle ne doit pas devenir un second corpus contenant systématiquement contacts, résultats bruts ou secrets. Les droits de consultation et la durée de conservation de cette trace doivent être définis.
Cette instrumentation permet de comparer une régression après changement de modèle ou de prompt sans confondre proposition et exécution. Le workflow doit savoir si l’outil a été appelé, si le moteur a annulé et si un résultat a été livré. Notre banc ne teste pas une supervision distribuée ; il conserve simplement les requêtes manuscrites, verdicts et SQLSTATE qui soutiennent les observations présentées.
Erreurs fréquentes dans les garde-fous SQL
Croire qu’une interdiction dans le prompt retire un privilège
Une consigne peut réduire les propositions indésirables lors de l’inférence, mais elle ne remplace pas une permission moteur. Si le compte peut lire une table privée, une erreur ou un contenu adversarial peut encore la proposer. La frontière doit subsister lorsque la proposition viole la consigne. Le contexte fourni au modèle doit également éviter d’exposer des objets qu’il n’a aucune raison légitime d’interroger.
Paradoxalement, rendre le modèle plus obéissant peut masquer un compte trop large pendant la démonstration : les essais favorables ne tentent jamais les lectures interdites. La recette négative doit provoquer ces propositions et vérifier les refus réels. L’évaluation d’un modèle, la validation d’un contrôleur et l’audit des droits de la base sont trois travaux liés, avec des preuves distinctes.
Élargir le contrat après un refus sans ajouter sa recette
Autoriser des fonctions, jointures ou sous-requêtes pour débloquer une question peut ouvrir de nouvelles formes de consommation et de lecture. Chaque extension doit préciser arguments, sources, combinaisons et budgets admis. Une exception ajoutée en urgence dans une liste de mots ne rend pas le reste du langage maîtrisé. Les cas précédemment refusés doivent rester documentés, y compris lorsqu’ils deviennent admissibles sous conditions.
La validation syntaxique doit correspondre à la version du moteur et au contrat installé. Il faut suivre les évolutions de parseur et conserver des tests de structure, de privilèges et de résultat. Les sources et citations d’un RAG peuvent aider à expliquer un indicateur, mais elles n’autorisent aucune requête. Une réponse avec citations ne prouve pas que les données SQL consultées étaient dans le périmètre permis.
Plan d’action pour ouvrir un périmètre de lecture
Commencer par une capacité dont chaque frontière est visible
Choisissez une lecture utile avec son propriétaire métier et ses données nécessaires. Décrivez la population, les colonnes, la sortie et les usages interdits. Le propriétaire de base vérifie rôle, objets et capacités publiques pertinentes ; l’équipe technique définit le contrat d’exécution. Cette préparation permet de décider si un outil paramétré suffit ou si une composition SQL limitée apporte réellement de la valeur.
- Exposer une vue ou un outil borné, avec grain et attributs documentés. Vérifier les lignes et colonnes exclues, puis faire relire les droits qui permettent la consultation des objets sous-jacents.
- Connecter le rôle applicatif réel dans un environnement isolé. Tester lecture privée, écriture et élévation ; distinguer permission refusée et mode read-only dans les résultats du moteur.
- Définir les structures SQL admissibles. Refuser les formes inconnues avant exécution, conserver leurs motifs et prévoir une voie pour les questions métier légitimes hors périmètre.
- Borner temps, attente, sortie et concurrence selon la charge réelle. Provoquer annulation et nettoyage des connexions ; mesurer les coûts sans déduire une capacité de production d’une table fictive.
- Rejouer les cas à chaque évolution de vue, rôle, contrat ou modèle. Conserver résultat attendu, verdict et état d’exécution ; ouvrir une extension seulement avec sa responsabilité et ses essais défavorables.
Le livrable ne se limite pas à une requête nominale. Il comprend les entrées refusées, les sondes moteur et les limites non éprouvées. La latence de génération et le coût d’inférence peuvent être suivis séparément du budget SQL. Le plan doit rendre le repli praticable pour l’utilisateur, afin que le service ne contourne pas ses propres frontières lorsqu’une lecture demandée n’est pas disponible.
Organiser l’exploitation des changements de capacité
Le runbook distingue entrée mal formée, sortie refusée, délai dépassé et permissions modifiées. La responsabilité de chaque reprise doit être explicite : métier pour une définition d’indicateur, propriétaire de données pour la vue, équipe technique pour le contrat et l’annulation. Une alerte doit permettre de retirer une capacité ou de rétablir un outil connu sans ouvrir temporairement un compte d’administration.
La recette en environnement représentatif vérifie volumes, pool de connexions, supervision et restitution. Elle examine aussi révocation des droits utilisateurs et accès aux traces. Le banc présenté fournit un point de départ contrôlé avec trois lignes et des propositions manuscrites. Son intérêt est de rendre les frontières observables ; son étroitesse interdit d’y voir une validation générale de tout assistant SQL.
Guides pour relier sécurité et exactitude métier
Construire la question et vérifier le nombre obtenu
La démarche NL-to-SQL sur les indicateurs et les requêtes replace cette frontière dans le dispositif complet : question admise, dictionnaire métier, proposition et vérification du résultat. Une exécution autorisée est une étape de ce parcours. Elle n’efface pas l’obligation d’expliciter période, grain et population avant restitution.
Le contrat de lecture s’insère ainsi entre la proposition et le résultat livré. Il indique quels objets ont pu être consultés et quelles structures ont été refusées. Le dictionnaire explique ensuite ce que signifient les colonnes réellement utilisées. Une modification du périmètre de données peut rendre une question indisponible sans rendre son indicateur faux : le produit doit annoncer cette capacité manquante plutôt que fabriquer une réponse de remplacement.
Clarifier la définition puis éprouver le calcul
Le traitement d’un indicateur SQL ambigu montre pourquoi une demande doit parfois être clarifiée avant génération. Le contrôle des résultats faux malgré une requête valide éprouve ensuite la sémantique du calcul. Ces recettes complètent les protections de lecture sans prétendre les remplacer.
La chaîne de preuve conserve donc trois décisions : définition de la question, autorisation de la lecture et vérification du résultat. Une demande clarifiée peut encore produire une requête hors contrat ; une requête admise peut encore perdre des commandes dans une jointure. Pour qualifier un incident, l’équipe doit retrouver chacune de ces décisions et son attente, plutôt que déduire toute la qualité du service de son absence d’erreur SQL.
Conclusion : autoriser une capacité de lecture vérifiée
Une requête proposée par une IA doit franchir des frontières explicites avant d’atteindre la base : population et colonnes exposées, forme SQL admise, rôle réellement connecté et budget d’exécution. Le mode read-only contribue à cette protection. Il ne décide pas seul de tout ce que le service peut lire, exporter ou consommer, et ne prouve pas que son résultat répond à la question métier.
Le banc admet deux requêtes sur quatorze et vérifie séparément sept comportements PostgreSQL. Les refus de permission, l’annulation par délai et le refus read-only du contrôle propriétaire sont distingués. L’export des lignes déjà autorisées reste possible au moteur et refusé par le contrat. Aucun modèle n’est évalué ; aucun volume ou délai de production n’est déduit des trois commandes fictives.
Une lecture IA des données métier gagne à commencer par un périmètre dont chaque protection peut être provoquée et expliquée. L’extension vers de nouvelles questions doit emporter définition métier, permissions, formes de requête et recette, avec une abstention utilisable lorsque la capacité manque.
Dawap accompagne l’ouverture d’une lecture SQL par votre IA sur mesure en partant de la vue utile au responsable métier et du rôle qui l’interroge. Avec la DSI, nous testons une colonne privée, une écriture et une requête trop longue avec ce compte, puis vérifions les restrictions syntaxiques séparément. Le périmètre peut s’élargir après ces preuves ; une simple déclaration « lecture seule » ne tient pas lieu de recette des droits et des ressources.