Aller au contenu

Vue filtrée pour Administrateur Planificateur Gestionnaire de patrimoine Enseignant Étudiant Tout afficher

Isolation multi-établissements

Vérifié contre le produit le .

Ce scénario est autonome. Il monte ses deux établissements lui-même et se joue sans avoir déroulé les seize autres. C’est celui qu’on rejoue devant un client qui demande à voir.

Domaine Isolation entre établissements — aucune donnée ne franchit la frontière
Durée ~10 min
Niveau critique
Étiquette manuel — il exige deux sessions simultanées dans deux établissements distincts, et son intérêt est précisément d’être joué sous les yeux de quelqu’un

Chaque établissement est étanche. Un utilisateur d’un établissement ne peut voir, ni chercher, ni atteindre aucune donnée d’un autre — même en connaissant l’adresse exacte de la ressource, même avec les droits les plus élevés de son propre établissement.

La séparation ne repose pas sur un filtre appliqué par l’interface, qu’on pourrait contourner en tapant une adresse : elle est appliquée au niveau de la base de données, sous chaque requête.

Aucun jeu de données préexistant. Le scénario part d’un environnement démarré :

Fenêtre de terminal
docker compose up -d postgres redis
cd packages/db && bun run db:migrate
cd ../.. && bun run dev

L’application répond sur http://localhost:3000.

Deux navigateurs, ou un navigateur et une fenêtre privée — jamais deux onglets du même profil, qui partageraient la session.

# Action Résultat attendu
1.1 Navigateur 1« Créer un compte » : alice, avec le nom d’établissement « École A » le compte est créé, l’accueil s’affiche
1.2 alice → Référentiel & parc → créer un campus « Campus Nord », un bâtiment « BAT-A », une salle A-101 de 40 places les trois éléments apparaissent dans l’arborescence
1.3 alice → Réservation → réserver A-101 demain 09:00–10:00, motif « Réunion A » « Réservation confirmée. »
1.4 Navigateur 2« Créer un compte » : carol, avec le nom d’établissement « École B » le compte est créé, l’accueil s’affiche
1.5 carol → Référentiel & parc → créer un campus « Campus Sud », un bâtiment « BAT-B », une salle B-201 de 30 places les trois éléments apparaissent

À ce stade, deux établissements existent, chacun avec sa salle, et l’un d’eux avec une réservation.

Tout ce bloc se joue dans le navigateur 2, avec carol — qui est administratrice de son propre établissement, donc au maximum de ses droits.

# Action Résultat attendu
2.1 Réservation → rechercher demain, plage large, aucun filtre seule B-201 apparaît. A-101 est absente, alors qu’elle est libre à cette heure-là
2.2 Référentiel & parc → parcourir l’arborescence « Campus Sud » seul. Ni « Campus Nord », ni « BAT-A », ni A-101
2.3 Administration → Utilisateurs carol seule. alice n’y figure pas
2.4 Administration → Journal d’audit, filtres à « Tous » aucune entrée concernant l’École A — ni la création du campus Nord, ni la réservation d’alice
2.5 Pilotage les indicateurs ne portent que sur B-201

3. Ce que carol ne peut pas atteindre, même en connaissant l’adresse

Section intitulée « 3. Ce que carol ne peut pas atteindre, même en connaissant l’adresse »

C’est le bloc qui distingue une véritable étanchéité d’un simple filtrage d’affichage.

# Action Résultat attendu
3.1 Dans le navigateur 1, ouvrir la fiche de A-101 et copier l’adresse complète de la page l’adresse contient l’identifiant de la salle
3.2 Coller cette adresse dans le navigateur 2, connecté en carol « Salle introuvable. » — pas un refus d’accès : la salle n’existe pas de son point de vue
3.3 Recommencer avec l’adresse d’un plan d’étage, d’une fiche d’enseignant ou d’un import de l’École A même comportement : introuvable

La nuance vaut d’être dite à voix haute : le produit ne répond pas « vous n’avez pas le droit », ce qui confirmerait l’existence de la ressource. Il répond qu’elle n’existe pas.

Il ne suffit pas que B ne voie pas A ; il faut aussi que A ne voie pas B, et que rien n’ait bougé pendant les manipulations.

# Action Résultat attendu
4.1 Navigateur 1, alice → Référentiel & parc « Campus Nord » seul ; ni « Campus Sud », ni B-201
4.2 alice → Réservation, recherche large seule A-101 apparaît
4.3 alice → « Mes réservations » sa réservation de l’étape 1.3 est intacte, statut « Confirmée »
4.4 alice → Administration → Journal d’audit ses propres gestes y figurent, et aucun de ceux de carol

5. L’étanchéité côté interface de programmation

Section intitulée « 5. L’étanchéité côté interface de programmation »

Le même contrôle, en dehors de l’application web — c’est la question que pose un responsable informatique.

Dans le navigateur 2, connecté en carol, ouvrir http://localhost:3001/docs : la session est transmise automatiquement.

# Action Résultat attendu
5.1 Lister les salles B-201 seule
5.2 Demander la salle A-101 par son identifiant, relevé à l’étape 3.1 404 — la ressource n’existe pas pour cette session
5.3 Lister les réservations aucune — celle d’alice n’apparaît pas

Le résultat est le même que dans l’interface, et c’est le point : la séparation n’est pas faite par l’écran, elle est faite en dessous.

  • Créer deux comptes coup sur coup peut déclencher le limiteur d’authentification. Le message affiché est « Une erreur est survenue. Veuillez réessayer. », générique. Attendre une minute de silence complet, puis reprendre.
  • Le nom d’établissement est demandé à l’inscription. Un compte créé sans nom d’établissement rejoint une invitation, il n’en crée pas — le scénario a besoin de deux créations, pas d’une création et d’une invitation.
  • L’étape 3.1 exige de relever une adresse réelle. Un identifiant inventé donnerait le même résultat pour une raison différente, et ne prouverait rien.

Les pièges transverses — environnement, authentification, fraîcheur des données — sont rassemblés sur Les pièges connus.

Ce qui est couvert Story
Isolation par établissement, appliquée sous chaque requête STORY-002
Occupation unifiée et recherche de disponibilité STORY-013, STORY-015
Journal d’audit cloisonné STORY-010
Rôles et permissions par établissement STORY-004

Couvert par les tests automatisés : apps/api/src/auth/auth-tenant.e2e.spec.ts et apps/api/src/rbac/rbac.e2e.spec.ts éprouvent l’isolation côté serveur, y compris sur des identifiants croisés. Le parcours complet côté interface ne l’est pas — et c’est précisément celui qu’un client demande à voir.

  • Deux navigateurs distincts, deux comptes, deux établissements créés
  • École A : un campus, un bâtiment, une salle A-101, et une réservation confirmée
  • École B : un campus, un bâtiment, une salle B-201
  • carol cherche une salle → seule B-201, A-101 absente bien que libre
  • carol ouvre le référentiel → son campus seul
  • carol ouvre les utilisateurs → elle seule
  • carol ouvre le journal d’audit, filtres à « Tous »aucune entrée de l’École A
  • carol ouvre l’adresse directe de la fiche A-101 → « Salle introuvable. »
  • alice ne voit ni le campus, ni la salle de l’École B
  • La réservation d’alice est intacte après toutes les manipulations
  • Depuis l’interface de programmation, en carol : A-101 par identifiant → 404
Documentation technique source (2)