Repository navigation
Task/base360.ai - #238
Task/base360.ai#238eslam5464 wants to merge 14 commits into
Conversation
…or data isolation
… improved error management and clarity
…roved data granularity
…presentation and add rounding function for cents
…mmary API integration
…t for improved compatibility
…d testing support
| if user_email == "sunset@propertyflow.com": | ||
| return "tenant-a" | ||
| if user_email == "ocean@propertyflow.com": | ||
| return "tenant-b" | ||
| if user_email == "candidate@propertyflow.com": | ||
| return "tenant-a" | ||
|
|
||
| # Default fallback | ||
| return "tenant-a" | ||
|
|
||
| # No default: an unknown user must never be placed in a real tenant, | ||
| # or they would see that tenant's data. | ||
| logger.warning(f"No tenant found for user {user_email} ({user_id})") | ||
| return None |
There was a problem hiding this comment.
Bug: Removing default fallback in resolve_tenant_id causes callers omitting token to resolve tenant_id as None for standard users.
Severity: HIGH
Suggested Fix
Update callers (login.py, auth_info.py, city_access_fast.py) to pass token to resolve_tenant_id, or use user.tenant_id already populated by authenticate_request.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: backend/app/core/tenant_resolver.py#L86-L106
Potential issue: `resolve_tenant_id` no longer falls back to 'tenant-a' and returns
`None` for any user without a hardcoded email when called without a `token`. Multiple
existing callers (`login.py`, `auth_info.py`, and `city_access_fast.py`) invoke
`resolve_tenant_id` without passing `token`. Consequently, users not in the hardcoded
email map receive a JWT with `tenant_id: None` on login, `/auth/me` returns `tenant_id:
null` while missing permissions, and city access returns `tenant_resolution_failed`.
Did we get this right? 👍 / 👎 to inform future reviews.
| if token: | ||
| try: | ||
| tenant_id = TenantResolver.resolve_tenant_from_token(jwt.get_unverified_claims(token)) | ||
| if tenant_id: | ||
| return tenant_id | ||
| except JWTError: | ||
| logger.warning(f"Could not read tenant claim from token for {user_email}") |
There was a problem hiding this comment.
Bug: resolve_tenant_from_token trusts user-editable user_metadata.tenant_id over admin-controlled metadata or database assignments.
Severity: HIGH
Suggested Fix
Ignore user_metadata for tenant authorization. Retrieve tenant_id strictly from app_metadata or validate the claim against the user_tenants database table.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: backend/app/core/tenant_resolver.py#L87-L93
Potential issue: `resolve_tenant_from_token` resolves `tenant_id` by inspecting
`user_metadata.tenant_id` prior to `app_metadata` or authoritative database records. In
Supabase auth, users can modify their own `user_metadata`. If a token from a
Supabase-authenticated user contains a manipulated `user_metadata.tenant_id`, the system
trusts the claim, allowing unauthorized access to other tenants' cached dashboard data,
revenue, and property records.
Did we get this right? 👍 / 👎 to inform future reviews.
| setLoading(true); | ||
| setError(''); | ||
| try { | ||
| // Use SecureAPI to handle authentication automatically | ||
| // We pass the simulatedTenant option which SecureAPI will attach as a header | ||
| // SecureAPI attaches the auth token; the backend takes the | ||
| // tenant from that token only. | ||
| const response = await SecureAPI.getDashboardSummary(propertyId, { | ||
| simulatedTenant: activeTenant, | ||
| month, | ||
| year, | ||
| timestamp: Date.now() | ||
| }); | ||
| setData(response); |
There was a problem hiding this comment.
Bug: Missing cancellation in useEffect fetch causes race conditions and displays out-of-order revenue data.
Severity: LOW
Suggested Fix
Use an AbortController or an active cancellation flag within useEffect cleanup to ignore responses from superseded requests.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: frontend/src/components/RevenueSummary.tsx#L29-L41
Potential issue: In `RevenueSummary.tsx`, `useEffect` fetches revenue data on changes to
`propertyId`, `month`, or `year` without request cancellation, cleanup flags, or
response ordering guards. When filter settings change rapidly, an earlier asynchronous
request may settle after a later request, overwriting current revenue state with stale
data and clearing the loading state prematurely.
Did we get this right? 👍 / 👎 to inform future reviews.
No description provided.