Voor developers2 min leestijd
Tenant-isolatie afdwingen in CI met Supabase
Alle salons in Stippa wonen in dezelfde database. Hoe ik zorg dat niemand bij de buren naar binnen kan kijken, en waarom de controle vandaag ook naar reads kijkt.
Alle salons in Stippa wonen in dezelfde database. Een beetje als een appartementencomplex: één gebouw, veel voordeuren. Dat heet multitenancy (opent een externe site), het is heel normaal voor dit soort software, en het houdt de app eenvoudig en betaalbaar.
Maar het betekent ook dat het belangrijkste werk onzichtbaar is. Elke voordeur moet op slot. De ene salon mag nooit de afspraken, klanten of betalingen van een andere zien, laat staan aanpassen.
Twee sloten op de deur
Het eerste slot zit in de database zelf. Stippa draait op Supabase, en dat is PostgreSQL (opent een externe site) met row level security (opent een externe site): bij elke vraag controleert de database van welke salon de gegevens zijn. Hoor je niet bij die salon, dan krijg je simpelweg niets terug.
Het tweede slot zit in de code. Sinds eind mei loopt er bij elke wijziging een automatische controle langs de repositories, de stukken code die met de database praten. Die controle draait mee in de CI (opent een externe site), en een wijziging die er niet doorheen komt, komt er niet in.
Waarom twee sloten? Omdat een regel in de database je beschermt tegen de fout die je vergeten bent, en een controle in de code je dwingt er vooraf over na te denken. Samen vangen ze meer dan elk apart.
Waar de controle op let
Het script leest de broncode van elke repository en kijkt naar drie dingen.
- Wijzigingen. Elke update, delete en upsert moet gefilterd zijn op de salon. Een afspraak aanpassen op alleen het nummer, zonder te checken bij welke salon hij hoort? Komt er niet door.
- Nieuwe rijen. Wie een rij toevoegt aan een tabel die bij een salon hoort, moet die salon ook meeschrijven.
- Reads. Die kwam er vandaag bij. Een read die via een verwijzing naar een andere tabel gegevens van een andere salon zou kunnen raken, wordt nu ook gemeld.
Soms is een uitzondering terecht, bijvoorbeeld voor code die bewust over alle salons heen werkt. Die komt dan op een lijstje, met per bestand de reden erbij. Zo is elke uitzondering bewust gekozen, en later terug te vinden.
Waarom reads er ook bij horen
Updates en inserts zijn het voor de hand liggende risico: daar verandert iets. Reads voelen onschuldig. Maar een klantenlijst die per ongeluk ook de klanten van de salon verderop laat zien, is net zo erg. Toen de controle die stap kreeg, kwamen er een paar plekken boven die strakker moesten. Die zijn met dezelfde wijziging dichtgezet.
Meer over hoe Stippa gebouwd is, lees je in de case study.