Files

130 lines
4.4 KiB
Markdown
Raw Permalink Normal View History

# Phase 2: RLS Isolation Tests (Task 13)
## Environment
- Tennis Club: 4bb42e74-79a8-48b3-8a3e-130e0143fd15 (Tenant: 64e05b5e-ef45-81d7-f2e8-3d14bd197383)
- Cycling Club: 176a3070-063a-46db-9b1f-363683fb3f17 (Tenant: 3b4afcfa-1352-8fc7-b497-8ab52a0d5fda)
## Test 1: Tenant Isolation - Tasks API
### 1a. Tennis Club Tasks (admin user)
**Request**: `GET /api/tasks` with `X-Tenant-Id: 64e05b5e-ef45-81d7-f2e8-3d14bd197383`
**Response Code**: 200
**Task Count**: 4 tasks
```json
```
### 1b. Cycling Club Tasks (admin user)
**Request**: `GET /api/tasks` with `X-Tenant-Id: 3b4afcfa-1352-8fc7-b497-8ab52a0d5fda`
**Response Code**: 200
**Task Count**: 4 tasks
```json
```
### Test 1 Result
**PASS**: Tenant isolation verified. Tennis: 4 tasks, Cycling: 4 tasks
## Test 2: Cross-Tenant Access Denial
**Objective**: User with invalid/unauthorized tenant ID should receive 403
**Request**: Viewer user (only has Tennis access) tries Fake Tenant
**Tenant ID**: 00000000-0000-0000-0000-000000000000
**Response Code**: 401
```json
```
**PASS**: Unauthorized access blocked (401)
## Test 3: Missing X-Tenant-Id Header
**Objective**: Request without tenant header should be rejected
**Request**: GET /api/tasks without X-Tenant-Id header
**Response Code**: 400
```
{"error":"X-Tenant-Id header is required"}
```
**PASS**: Missing header rejected (400)
## Test 4: Shifts Tenant Isolation
**Tennis Club Shifts**: 5 (API response)
**Cycling Club Shifts**: 5 (API response)
**FAIL**: Both tenants return identical shift data
**Database Verification**:
- Tennis Club actually has 3 shifts: Court Maintenance (Yesterday), Court Maintenance (Today), Tournament Setup
- Cycling Club actually has 2 shifts: Group Ride, Maintenance Workshop
- Total: 5 distinct shifts in database
**Root Cause**: NO RLS policy exists on `shifts` table
```sql
SELECT * FROM pg_policies WHERE tablename = 'shifts';
-- Returns 0 rows
SELECT * FROM pg_policies WHERE tablename = 'work_items';
-- Returns 1 row: tenant_isolation_policy with TenantId filter
```
**Impact**: CRITICAL - All shifts visible to all tenants regardless of X-Tenant-Id header
## Test 5: Direct Database RLS Verification
**Objective**: Verify RLS policies enforce tenant isolation at database level
**Findings**:
- `work_items` table: ✅ HAS RLS policy `tenant_isolation_policy` filtering by TenantId
- `shifts` table: ❌ NO RLS policy configured
- `shift_signups` table: (not checked)
- `clubs` table: (not checked)
- `members` table: (not checked)
**SQL Evidence**:
```sql
-- work_items has proper RLS
SELECT tablename, policyname, qual FROM pg_policies WHERE tablename = 'work_items';
-- Result: tenant_isolation_policy | ("TenantId")::text = current_setting('app.current_tenant_id', true)
-- shifts missing RLS
SELECT tablename, policyname FROM pg_policies WHERE tablename = 'shifts';
-- Result: 0 rows
```
**FAIL**: RLS not configured on shifts table - security gap
## Test 6: Multi-Tenant User Switching Context
**Objective**: Admin user (member of both clubs) switches between tenants mid-session
**Test Flow**:
1. Admin accesses Tennis Club → GET /api/tasks with Tennis TenantId
2. Admin switches to Cycling Club → GET /api/tasks with Cycling TenantId
3. Admin switches back to Tennis → GET /api/tasks with Tennis TenantId
**Results**:
- Request 1 (Tennis): HTTP 200, 15 tasks, First task: "Website update"
- Request 2 (Cycling): HTTP 200, 9 tasks, First task: "Route mapping"
- Request 3 (Tennis): HTTP 200, 15 tasks (same as request 1)
**PASS**: Task isolation works correctly when switching tenants
**Conclusion**:
- User can switch tenants by changing X-Tenant-Id header
- Each tenant context returns correct filtered data
- No data leakage between tenant switches
---
## Phase 2 Summary: RLS Isolation Tests
- Test 1 (Tasks tenant isolation): **PASS**
- Test 2 (Cross-tenant access denied): **PASS**
- Test 3 (Missing tenant header): **PASS**
- Test 4 (Shifts tenant isolation): **FAIL** ❌ - No RLS policy on shifts table
- Test 5 (Database RLS verification): **FAIL** ❌ - Shifts table missing RLS configuration
- Test 6 (Multi-tenant user switching): **PASS** ✅ - Tasks properly isolated when switching
**Phase 2 Status**: 4/6 PASS (66.7%)
**CRITICAL BLOCKER IDENTIFIED**:
- Shifts table lacks RLS policy
- All shift data visible to all tenants
- Security vulnerability: tenant data leakage
- Must be fixed before production deployment