""" tests/test_tenancy_isolation.py Verifies that tenant data isolation rules are enforced — one tenant's data must never be accessible from another tenant's session. """ import pytest from app.extensions import db, bcrypt as _bcrypt from app.models.platform import Tenant, Plan from app.models.salon import User, Customer, Location def _create_tenant_with_user(app, slug, email, customer_name): with app.app_context(): plan = Plan.query.first() tenant = Tenant( slug=slug, name=slug, owner_email=email, plan_id=plan.id, status="active", ) db.session.add(tenant) db.session.flush() loc = Location( tenant_id=tenant.id, name="Main", is_primary=True, is_active=True ) db.session.add(loc) user = User( tenant_id=tenant.id, email=email, password_hash=_bcrypt.generate_password_hash("IsolationPass1").decode("utf-8"), role="tenant_admin", is_active=True, ) db.session.add(user) db.session.flush() customer = Customer( tenant_id=tenant.id, name=customer_name, phone=f"555-{tenant.id:04d}", ) db.session.add(customer) db.session.commit() return tenant.id, customer.id class TestTenancyIsolation: def test_customer_belongs_to_own_tenant(self, tenant_app): """Querying customers filtered by tenant_id returns only that tenant's data.""" t1_id, c1_id = _create_tenant_with_user( tenant_app, "iso-tenant-1", "owner1@iso.com", "Alice" ) t2_id, c2_id = _create_tenant_with_user( tenant_app, "iso-tenant-2", "owner2@iso.com", "Bob" ) with tenant_app.app_context(): t1_customers = Customer.query.filter_by(tenant_id=t1_id).all() t2_customers = Customer.query.filter_by(tenant_id=t2_id).all() t1_ids = {c.id for c in t1_customers} t2_ids = {c.id for c in t2_customers} assert c1_id in t1_ids assert c2_id not in t1_ids assert c2_id in t2_ids assert c1_id not in t2_ids def test_no_cross_tenant_customer_names(self, tenant_app): """Alice should not appear in tenant 2's query results.""" with tenant_app.app_context(): t1 = Tenant.query.filter_by(slug="iso-tenant-1").first() t2 = Tenant.query.filter_by(slug="iso-tenant-2").first() if t1 and t2: t1_names = {c.name for c in Customer.query.filter_by(tenant_id=t1.id).all()} t2_names = {c.name for c in Customer.query.filter_by(tenant_id=t2.id).all()} assert "Alice" not in t2_names assert "Bob" not in t1_names