Skip to content

fix: resolve cross-tenant data leakage, timezone revenue calculation, and db connection pool - #214

Open
AARUSH-SING wants to merge 2 commits into
Base360-AI:mainfrom
AARUSH-SING:main
Open

AARUSH-SING wants to merge 2 commits into
Base360-AI:mainfrom
AARUSH-SING:main

Conversation

@AARUSH-SING

Copy link
Copy Markdown

📌 Summary

Resolves reported dashboard revenue discrepancies, cross-tenant data leakage, and precision bugs across Client A, Client B, and Finance:

  1. Client B Data Leakage (Cache Collision): Fixed cross-tenant leakage by prefixing Redis cache keys with tenant_id (revenue:{tenant_id}:{property_id}) in cache.py.
  2. Client A March Revenue (Timezone Bug): Evaluated check-in dates in property local timezone (AT TIME ZONE p.timezone) in reservations.py. Booking res-tz-1 (2024-02-29 23:30 UTC = 2024-03-01 00:30 Paris time) is now accurately included in March revenue ($2,250.00 / 4 bookings).
  3. Finance Team Precision: Replaced float operations with Decimal and ROUND_HALF_UP to two decimal places to fix cent-level rounding errors.
  4. Database Connection Pool: Fixed asyncpg pool connection string parsing in database_pool.py, stopping silent fallbacks to static mock data.
  5. Frontend Multi-Tenancy: Updated secureApi.ts, jwtUtils.ts, and Dashboard.tsx to validate tenant slugs (tenant-a, tenant-b) and dynamically display each client's properties.

🧪 Verification Results

Verified live via docker-compose with client credentials:

Client Property Expected Result Verified Result
Sunset Properties (tenant-a) Beach House Alpha (prop-001) $2,250.00 (4 bookings) $2,250.00 (4 bookings) ✅
Ocean Rentals (tenant-b) Mountain Lodge Beta (prop-001) $0.00 (0 bookings) $0.00 (0 bookings) ✅ (No leakage)
Ocean Rentals (tenant-b) Lakeside Cottage (prop-004) $1,776.50 (4 bookings) $1,776.50 (4 bookings) ✅ (Exact cents)

📂 Key Files Modified

  • Backend: database_pool.py, cache.py, reservations.py, dashboard.py, login.py
  • Frontend: secureApi.ts, jwtUtils.ts, Dashboard.tsx, RevenueSummary.tsx
  • Infra: docker-compose.yml, frontend/Dockerfile, .gitignore

AARUSH-SING and others added 2 commits September 29, 2026 21:05
…connection pool

- Scope Redis cache keys by tenant_id to prevent cross-tenant data collisions
- Calculate reservation revenue in property local timezone using AT TIME ZONE
- Fix DatabasePool asyncpg connection string parsing from settings.database_url
- Enforce Decimal ROUND_HALF_UP precision to resolve sub-cent discrepancies
- Support slug tenant IDs and dynamic property dropdowns in frontend
- Add local redis:7-alpine container in docker-compose.yml
Comment on lines +43 to +44
session_ctx = db_pool.get_session()
session = await session_ctx.__aenter__()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The call to db_pool.get_session() within an async with block is missing an await. This will always raise a TypeError when the database is available.
Severity: CRITICAL

Suggested Fix

The coroutine returned by db_pool.get_session() must be awaited before it can be used as an async context manager. Change the line async with db_pool.get_session() as session: to async with await db_pool.get_session() as session:. This ensures the session is correctly acquired before use.

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/services/reservations.py#L43-L44

Potential issue: In `calculate_total_revenue`, the database session is acquired using
`async with db_pool.get_session()`. However, `get_session` is a coroutine and must be
awaited. The current code will raise a `TypeError` whenever the database connection is
successful. This error is caught, causing the function to silently fall back to
returning static mock data instead of querying the database. As a result, the
application will always serve incorrect, hardcoded data for total revenue.

Also affects:

  • backend/app/services/reservations.py:97~97

Did we get this right? 👍 / 👎 to inform future reviews.

Comment on lines +248 to +249
const slugRegex = /^[a-z0-9_-]+$/i;
return uuidRegex.test(tenantId) || slugRegex.test(tenantId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The backend accepts an x-simulated-tenant header without validating it against the authenticated user's tenant, creating a potential cross-tenant access vulnerability.
Severity: HIGH

Suggested Fix

In dashboard.py, remove the fallback logic that reads the tenant ID from the x-simulated-tenant header. The tenant ID should be derived exclusively from the authenticated user's session (current_user.tenant_id) to ensure data is always scoped correctly.

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/lib/secureApi.ts#L248-L249

Potential issue: The backend endpoint for the dashboard allows a tenant ID to be
specified via the `x-simulated-tenant` header. This value is used if a `tenant_id` is
not present on the authenticated user object. However, the backend does not validate
that this header-provided ID matches the user's actual tenant, creating a potential
cross-tenant data access vulnerability. An authenticated user without a tenant ID in
their session could potentially access another tenant's data by setting this header.

Also affects:

  • backend/app/api/v1/dashboard.py:23~25

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant