454 lines
14 KiB
Markdown
454 lines
14 KiB
Markdown
# Complete System Audit Report
|
|
**Date:** December 8, 2025
|
|
**Scope:** Full stack audit - Backend models, permissions, middleware, frontend, documentation
|
|
**Status:** 🔴 CRITICAL ISSUES FOUND
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
### Overall System State: 🔴 BROKEN
|
|
|
|
Your multi-tenancy system has **5 CRITICAL ISSUES** that are causing widespread failures:
|
|
|
|
1. **Superuser Access Broken** - Session auth blocked on API, no bypass logic working
|
|
2. **Permission System Contradictions** - Multiple conflicting permission classes
|
|
3. **Missing Bypass Logic** - Superuser/developer checks removed from critical paths
|
|
4. **Account Validation Too Strict** - Blocks all users including system accounts
|
|
5. **Paid Plan Signup Missing** - No path for users to subscribe to paid plans
|
|
|
|
**Impact:** Neither regular tenants NOR superusers can access the application.
|
|
|
|
---
|
|
|
|
## Critical Issue #1: Superuser Access COMPLETELY BROKEN
|
|
|
|
### Problem
|
|
Superusers cannot access the application at all due to conflicting middleware logic.
|
|
|
|
### Root Cause
|
|
**File:** `backend/igny8_core/auth/middleware.py:35-41`
|
|
|
|
```python
|
|
# Block superuser access via session on non-admin routes (JWT required)
|
|
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
|
|
if request.user.is_superuser and not auth_header.startswith('Bearer '):
|
|
logout(request)
|
|
return JsonResponse(
|
|
{'success': False, 'error': 'Session authentication not allowed for API. Use JWT.'},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
```
|
|
|
|
**This blocks ALL superuser access** because:
|
|
- Superusers login via Django admin (session-based)
|
|
- Session cookies are sent to API automatically
|
|
- Middleware detects superuser + no JWT = LOGOUT + 403 error
|
|
- Even WITH JWT, there's no bypass logic downstream
|
|
|
|
### Evidence
|
|
1. Middleware forces JWT-only for superusers
|
|
2. No JWT generation on login (traditional Django session auth)
|
|
3. Permission classes have `is_superuser` checks BUT middleware blocks before reaching them
|
|
4. Admin panel uses session auth, but API rejects it
|
|
|
|
### Impact
|
|
- Superusers cannot access ANY page in the app
|
|
- Developer account cannot debug issues
|
|
- System administration impossible
|
|
|
|
---
|
|
|
|
## Critical Issue #2: Permission System Has CONTRADICTIONS
|
|
|
|
### Problem
|
|
Three different permission modules with conflicting logic:
|
|
|
|
#### Module A: `backend/igny8_core/auth/permissions.py`
|
|
```python
|
|
class IsOwnerOrAdmin(permissions.BasePermission):
|
|
def has_permission(self, request, view):
|
|
if getattr(user, "is_superuser", False):
|
|
return True # ✅ Superuser allowed
|
|
return user.role in ['owner', 'admin', 'developer']
|
|
```
|
|
|
|
#### Module B: `backend/igny8_core/api/permissions.py`
|
|
```python
|
|
class HasTenantAccess(permissions.BasePermission):
|
|
def has_permission(self, request, view):
|
|
# NO superuser bypass ❌
|
|
# Regular users must have account access
|
|
if account:
|
|
return user_account == account
|
|
return False # Denies superusers without account match
|
|
```
|
|
|
|
#### Module C: `backend/igny8_core/admin/base.py`
|
|
```python
|
|
class AccountAdminMixin:
|
|
def get_queryset(self, request):
|
|
if request.user.is_superuser or request.user.is_developer():
|
|
return qs # ✅ Bypass for superuser/developer
|
|
```
|
|
|
|
### The Contradiction
|
|
- **auth/permissions.py** - Allows superuser bypass
|
|
- **api/permissions.py** - NO superuser bypass (strict tenant-only)
|
|
- **admin/base.py** - Allows superuser/developer bypass
|
|
- **ViewSets** - Use MIXED permission classes from different modules
|
|
|
|
### Example of Broken ViewSet
|
|
**File:** `backend/igny8_core/auth/views.py:144`
|
|
|
|
```python
|
|
class UsersViewSet(AccountModelViewSet):
|
|
permission_classes = [
|
|
IsAuthenticatedAndActive, # From api/permissions - no bypass
|
|
HasTenantAccess, # From api/permissions - no bypass
|
|
IsOwnerOrAdmin # From auth/permissions - has bypass
|
|
]
|
|
```
|
|
|
|
**Result:** Permission denied because `HasTenantAccess` (2nd check) fails before `IsOwnerOrAdmin` (3rd check) runs.
|
|
|
|
### Impact
|
|
- Inconsistent behavior across endpoints
|
|
- Some endpoints work, some don't
|
|
- Debugging is impossible - which permission is denying?
|
|
|
|
---
|
|
|
|
## Critical Issue #3: Account Validation TOO STRICT
|
|
|
|
### Problem
|
|
Middleware validation blocks even system accounts and developers.
|
|
|
|
**File:** `backend/igny8_core/auth/middleware.py:148-170` + `auth/utils.py:133-195`
|
|
|
|
```python
|
|
def _validate_account_and_plan(self, request, user):
|
|
from .utils import validate_account_and_plan
|
|
is_valid, error_message, http_status = validate_account_and_plan(user)
|
|
if not is_valid:
|
|
return self._deny_request(request, error_message, http_status)
|
|
```
|
|
|
|
```python
|
|
def validate_account_and_plan(user_or_account):
|
|
account = getattr(user_or_account, 'account', None)
|
|
if not account:
|
|
return (False, 'Account not configured', 403)
|
|
|
|
if account.status in ['suspended', 'cancelled']:
|
|
return (False, f'Account is {account.status}', 403)
|
|
|
|
plan = getattr(account, 'plan', None)
|
|
if not plan:
|
|
return (False, 'No subscription plan', 402)
|
|
|
|
if not plan.is_active:
|
|
return (False, 'Active subscription required', 402)
|
|
|
|
return (True, None, None)
|
|
```
|
|
|
|
### The Problem
|
|
**NO bypass for:**
|
|
- Superusers (is_superuser=True)
|
|
- Developer role (role='developer')
|
|
- System accounts (aws-admin, default-account)
|
|
|
|
Even the developer account (dev@igny8.com) gets blocked if:
|
|
- Their account doesn't have a plan
|
|
- Their plan is inactive
|
|
- Their account status is suspended
|
|
|
|
### Impact
|
|
- Cannot fix issues even with superuser access
|
|
- System accounts get blocked
|
|
- No emergency access path
|
|
|
|
---
|
|
|
|
## Critical Issue #4: Missing Bypass Logic in Core Components
|
|
|
|
### AccountModelViewSet - NO Bypass
|
|
**File:** `backend/igny8_core/api/base.py:17-42`
|
|
|
|
```python
|
|
def get_queryset(self):
|
|
queryset = super().get_queryset()
|
|
if hasattr(queryset.model, 'account'):
|
|
# Filter by account
|
|
if account:
|
|
queryset = queryset.filter(account=account)
|
|
else:
|
|
return queryset.none() # ❌ Blocks everyone without account
|
|
```
|
|
|
|
**Missing:**
|
|
- No check for `is_superuser`
|
|
- No check for `role='developer'`
|
|
- No check for system accounts
|
|
|
|
### HasTenantAccess Permission - NO Bypass
|
|
**File:** `backend/igny8_core/api/permissions.py:23-52`
|
|
|
|
```python
|
|
class HasTenantAccess(permissions.BasePermission):
|
|
def has_permission(self, request, view):
|
|
# NO superuser bypass
|
|
if account:
|
|
return user_account == account
|
|
return False # ❌ Denies superusers
|
|
```
|
|
|
|
### Impact
|
|
Every API endpoint using these base classes is broken for superusers.
|
|
|
|
---
|
|
|
|
## Critical Issue #5: Paid Plan Signup Path MISSING
|
|
|
|
### Problem
|
|
Marketing page shows paid plans ($89, $139, $229) but all signup buttons go to free trial.
|
|
|
|
**File:** `tenancy-accounts-payments-still-have issues/PRICING-TO-PAID-SIGNUP-GAP.md`
|
|
|
|
### Gap Analysis
|
|
- ✅ Free trial signup works
|
|
- ❌ Paid plan signup does NOT exist
|
|
- ❌ No payment page
|
|
- ❌ No plan selection on signup
|
|
- ❌ No payment method collection
|
|
|
|
### Missing Components
|
|
1. Payment page UI (frontend)
|
|
2. Plan parameter routing (/signup?plan=starter)
|
|
3. Payment method selection
|
|
4. Pending payment account creation
|
|
5. Bank transfer confirmation flow
|
|
|
|
---
|
|
|
|
## Models & Database State
|
|
|
|
### ✅ What's Working
|
|
1. **Models are well-designed:**
|
|
- Account, User, Plan, Subscription, Site, Sector
|
|
- Credit system (CreditTransaction, CreditUsageLog)
|
|
- Payment/Invoice models exist
|
|
- Proper relationships (ForeignKey, OneToOne)
|
|
|
|
2. **Database has data:**
|
|
- 5 plans (free, starter, growth, scale, enterprise)
|
|
- 8 accounts actively using system
|
|
- 280+ credit transactions
|
|
- Credit tracking working
|
|
|
|
3. **Soft delete implemented:**
|
|
- SoftDeletableModel base class
|
|
- Retention policies
|
|
- Restore functionality
|
|
|
|
### ❌ What's Broken
|
|
1. **Missing field in Account model:**
|
|
- `payment_method` field defined in model but NOT in database (migration missing)
|
|
|
|
2. **Subscription table empty:**
|
|
- No subscriptions exist despite Subscription model
|
|
- Users operating on credits without subscription tracking
|
|
|
|
3. **Payment system incomplete:**
|
|
- Models exist but no data
|
|
- No payment gateway integration
|
|
- No invoice generation in use
|
|
|
|
---
|
|
|
|
## Documentation Issues
|
|
|
|
### Problem: Scattered & Contradictory
|
|
|
|
**Three separate doc folders:**
|
|
1. `master-docs/` - Structured, organized, but may be outdated
|
|
2. `old-docs/` - Legacy docs, unclear what's still valid
|
|
3. `tenancy-accounts-payments-still-have issues/` - Recent fixes, most accurate
|
|
|
|
### Contradictions Found
|
|
1. **Superuser bypass:** Docs say it exists, code shows it was removed
|
|
2. **Payment methods:** Docs describe manual payment flow, but frontend doesn't implement it
|
|
3. **Plan allocation:** Docs show complex fallback logic, implementation shows it was simplified
|
|
4. **Session auth:** Docs don't mention JWT requirement for API
|
|
|
|
### Missing from Docs
|
|
1. Current state of superuser access (broken)
|
|
2. Which permission module is canonical
|
|
3. Middleware validation rules
|
|
4. Account.payment_method migration status
|
|
|
|
---
|
|
|
|
## Frontend Analysis
|
|
|
|
### ✅ Frontend Code Quality: GOOD
|
|
- Well-structured React/TypeScript
|
|
- Proper state management (Zustand)
|
|
- Error handling hooks exist
|
|
- API service layer organized
|
|
|
|
### ❌ Frontend Issues
|
|
1. **No paid plan signup page** - Missing `/payment` route
|
|
2. **No error display for permission denied** - Silent failures
|
|
3. **No JWT token generation** - Still using session auth
|
|
4. **No superuser indicator** - Users don't know why access is denied
|
|
|
|
---
|
|
|
|
## ROOT CAUSE ANALYSIS
|
|
|
|
### Timeline of What Happened
|
|
|
|
1. **Initially:** Superuser had full bypass, everything worked
|
|
2. **Tenancy work started:** Added strict tenant isolation
|
|
3. **Security concern:** Removed some bypass logic to prevent session contamination
|
|
4. **Over-correction:** Removed TOO MUCH bypass logic
|
|
5. **Now:** Neither tenants nor superusers can access anything
|
|
|
|
### The Core Problem
|
|
|
|
**Attempted to fix security issue but broke fundamental access:**
|
|
- Session contamination IS a real issue
|
|
- JWT-only for API IS correct approach
|
|
- BUT: Removed all bypass logic instead of fixing authentication method
|
|
- AND: Middleware blocks before permission classes can allow bypass
|
|
|
|
---
|
|
|
|
## RECOMMENDATIONS
|
|
|
|
I have **TWO OPTIONS** for you:
|
|
|
|
### Option 1: QUICK FIX (2-4 hours) ⚡
|
|
**Restore superuser access immediately, patch critical flows**
|
|
|
|
**Pros:**
|
|
- Fastest path to working system
|
|
- Superuser can access app today
|
|
- Tenant system keeps working
|
|
|
|
**Cons:**
|
|
- Technical debt remains
|
|
- Documentation still messy
|
|
- Some inconsistencies persist
|
|
|
|
**What gets fixed:**
|
|
1. Add superuser bypass to middleware
|
|
2. Add developer role bypass to HasTenantAccess
|
|
3. Add system account bypass to AccountModelViewSet
|
|
4. Generate JWT tokens on login
|
|
5. Update frontend to use JWT
|
|
|
|
**Estimated time:** 2-4 hours
|
|
**Effort:** LOW
|
|
**Risk:** LOW
|
|
|
|
---
|
|
|
|
### Option 2: PROPER REBUILD (2-3 days) 🏗️
|
|
**Redesign tenancy system with clean architecture**
|
|
|
|
**Pros:**
|
|
- Clean, maintainable code
|
|
- Consistent permission logic
|
|
- Proper documentation
|
|
- All flows working correctly
|
|
- Future-proof architecture
|
|
|
|
**Cons:**
|
|
- Takes 2-3 days
|
|
- Requires careful testing
|
|
- Must migrate existing data
|
|
|
|
**What gets rebuilt:**
|
|
1. **Unified permission system** - One module, clear hierarchy
|
|
2. **Clean middleware** - Proper bypass logic for all roles
|
|
3. **JWT authentication** - Token generation + refresh
|
|
4. **Paid plan signup** - Complete payment flow
|
|
5. **Consolidated docs** - Single source of truth
|
|
6. **Account migration** - Add missing payment_method field
|
|
7. **Subscription system** - Link accounts to subscriptions
|
|
8. **Test suite** - Cover all permission scenarios
|
|
|
|
**Estimated time:** 2-3 days
|
|
**Effort:** MEDIUM
|
|
**Risk:** MEDIUM (with proper testing)
|
|
|
|
---
|
|
|
|
## MY RECOMMENDATION
|
|
|
|
### Start with Option 1 (Quick Fix), then Option 2
|
|
|
|
**Why:**
|
|
1. You need access NOW - can't wait 3 days
|
|
2. Quick fix restores functionality in hours
|
|
3. Then properly rebuild when system is accessible
|
|
4. Less risk - incremental improvement
|
|
|
|
**Action Plan:**
|
|
1. **NOW:** Quick fix (2-4 hours) - restore superuser access
|
|
2. **Tomorrow:** Test all flows, document issues
|
|
3. **Next 2-3 days:** Proper rebuild with clean architecture
|
|
4. **End result:** Production-ready multi-tenancy system
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
**Please confirm which option you want:**
|
|
|
|
**Option A:** Quick fix now (I'll start immediately)
|
|
**Option B:** Full rebuild (2-3 days, but cleaner)
|
|
**Option C:** Quick fix now + full rebuild after (RECOMMENDED)
|
|
|
|
Once you confirm, I'll begin implementation with detailed progress updates.
|
|
|
|
---
|
|
|
|
## File Inventory (Issues Found)
|
|
|
|
### Backend Files with Issues
|
|
1. ✅ `/backend/igny8_core/auth/middleware.py` - Blocks superusers
|
|
2. ✅ `/backend/igny8_core/auth/utils.py` - No bypass in validation
|
|
3. ✅ `/backend/igny8_core/api/permissions.py` - No superuser bypass
|
|
4. ✅ `/backend/igny8_core/api/base.py` - No bypass in queryset filter
|
|
5. ⚠️ `/backend/igny8_core/auth/models.py` - Missing payment_method migration
|
|
6. ✅ `/backend/igny8_core/auth/views.py` - Mixed permission classes
|
|
|
|
### Frontend Files with Issues
|
|
7. ⚠️ `/frontend/src/services/api.ts` - No JWT token handling
|
|
8. ❌ `/frontend/src/pages/Payment.tsx` - MISSING (paid signup)
|
|
9. ⚠️ `/frontend/src/components/auth/SignUpForm.tsx` - No plan parameter
|
|
|
|
### Documentation Issues
|
|
10. ⚠️ `master-docs/` - May be outdated
|
|
11. ⚠️ `old-docs/` - Unclear what's valid
|
|
12. ✅ `tenancy-accounts-payments-still-have issues/` - Most accurate
|
|
|
|
**Legend:**
|
|
- ✅ = Critical issue, must fix
|
|
- ⚠️ = Important but not blocking
|
|
- ❌ = Missing component
|
|
|
|
---
|
|
|
|
## Conclusion
|
|
|
|
Your system has **good architecture** but **broken implementation** due to over-correction during security fixes. The models are solid, the database is working, but the permission/access layer is preventing anyone (including you) from using the app.
|
|
|
|
**The good news:** This is fixable in a few hours with targeted changes.
|
|
|
|
**Waiting for your decision on which option to proceed with...**
|