feat: tenant isolation Phase 0 — app-layer filters, UUID audit, CI gate #132

Merged
chihlasm merged 22 commits from feat/tenant-isolation-phase-0 into main 2026-04-09 04:42:19 +00:00
chihlasm commented 2026-04-09 04:23:10 +00:00 (Migrated from github.com)

Summary

Implements the application-layer half of tenant data isolation (Phase 0). No schema changes — all existing tables, all existing data. Establishes the patterns and CI gate that all future tenant-data work must comply with.

Depends on: #131 (copilot hotfix) must merge first.

What's in this PR

  • tenant_filter(model, account_id) — canonical app-layer scoping helper in filters.py. Every query on a tenant table must use it.
  • get_tenant_context dependency in deps.py — centralises the account_id null check
  • Analytics flow endpoint (GET /analytics/flows/{tree_id}) — scoped to requesting account
  • Category tree count (GET /categories/{id}) — tree_count no longer leaks cross-tenant row counts
  • AI session search — restricted to user_id only (was OR(user_id, account_id))
  • UUID endpoint audit — audited 19 endpoint files; fixed all gaps:
    • retry_psa_push (CRITICAL): no ownership check existed — any user could retry any session's PSA push
    • get_documentation: was returning 403 (confirming session existence) → now 404
    • 15 handlers across 9 files: 403 → 404 for cross-tenant UUID lookups
    • update_tree: restored 403 for intra-account permission failures (same-account users who can see a tree but can't edit it no longer get a confusing 404)
    • _get_tree_or_403 renamed to _get_tree_or_404 in maintenance_schedules.py
  • TargetList audit: active code in 12+ files — migrate to account_id in Phase 1 (not dead code)
  • CI tenant-filter check: backend/scripts/check_tenant_filters.py added to CI backend job (warn mode, 109 current warnings = Phase 1 backlog)

Spec

docs/superpowers/specs/2026-04-09-tenant-data-isolation-design.md

Phase 0 gate status

  • Copilot tree bypass fixed (PR #131)
  • Analytics flow endpoint scoped
  • Category tree count scoped
  • AI session search restricted to user_id
  • Full UUID endpoint audit completed
  • get_tenant_context dependency added
  • tenant_filter() helper added
  • TargetList audit documented in spec
  • CI grep check defined and active
  • Teams orphan count — must run from VPS SSH before Phase 1

Test plan

  • CI passes — all 15 tests in test_tenant_isolation_p0.py green
  • CI tenant-filter check step runs (warn mode, exits 0)
  • python scripts/check_tenant_filters.py shows 109 warnings (Phase 1 backlog, not regressions)
  • Verify happy paths: own-account resources still return 200

🤖 Generated with Claude Code

## Summary Implements the application-layer half of tenant data isolation (Phase 0). No schema changes — all existing tables, all existing data. Establishes the patterns and CI gate that all future tenant-data work must comply with. **Depends on:** #131 (copilot hotfix) must merge first. ### What's in this PR - **`tenant_filter(model, account_id)`** — canonical app-layer scoping helper in `filters.py`. Every query on a tenant table must use it. - **`get_tenant_context`** dependency in `deps.py` — centralises the `account_id` null check - **Analytics flow endpoint** (`GET /analytics/flows/{tree_id}`) — scoped to requesting account - **Category tree count** (`GET /categories/{id}`) — `tree_count` no longer leaks cross-tenant row counts - **AI session search** — restricted to `user_id` only (was `OR(user_id, account_id)`) - **UUID endpoint audit** — audited 19 endpoint files; fixed all gaps: - `retry_psa_push` (CRITICAL): no ownership check existed — any user could retry any session's PSA push - `get_documentation`: was returning 403 (confirming session existence) → now 404 - 15 handlers across 9 files: 403 → 404 for cross-tenant UUID lookups - `update_tree`: restored 403 for intra-account permission failures (same-account users who can *see* a tree but can't edit it no longer get a confusing 404) - `_get_tree_or_403` renamed to `_get_tree_or_404` in `maintenance_schedules.py` - **TargetList audit**: active code in 12+ files — migrate to `account_id` in Phase 1 (not dead code) - **CI tenant-filter check**: `backend/scripts/check_tenant_filters.py` added to CI backend job (warn mode, 109 current warnings = Phase 1 backlog) ### Spec `docs/superpowers/specs/2026-04-09-tenant-data-isolation-design.md` ### Phase 0 gate status - [x] Copilot tree bypass fixed (PR #131) - [x] Analytics flow endpoint scoped - [x] Category tree count scoped - [x] AI session search restricted to user_id - [x] Full UUID endpoint audit completed - [x] `get_tenant_context` dependency added - [x] `tenant_filter()` helper added - [x] TargetList audit documented in spec - [x] CI grep check defined and active - [ ] Teams orphan count — must run from VPS SSH before Phase 1 ## Test plan - [ ] CI passes — all 15 tests in `test_tenant_isolation_p0.py` green - [ ] CI tenant-filter check step runs (warn mode, exits 0) - [ ] `python scripts/check_tenant_filters.py` shows 109 warnings (Phase 1 backlog, not regressions) - [ ] Verify happy paths: own-account resources still return 200 🤖 Generated with [Claude Code](https://claude.com/claude-code)
railway-app[bot] commented 2026-04-09 04:23:25 +00:00 (Migrated from github.com)

🚅 Deployed to the resolutionflow-pr-132 environment in selfless-grace

Service Status Web Updated (UTC)
patherly 🕒 Building (View Logs) Apr 9, 2026 at 4:42 am
hopeful-liberation 🕒 Building (View Logs) Apr 9, 2026 at 4:42 am
<!-- railway-bot-comment-version=2 --> <!-- railway-project-id="22b9b58c-271b-42e5-a10e-6fdec8d00134" railway-project-name="selfless-grace" --> 🚅 Deployed to the [resolutionflow-pr-132](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134?environmentId=c0a1241e-c3df-4686-b005-b67e7125b87b) environment in **[selfless-grace](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134)** | **Service** | **Status** | **Web** | **Updated** (UTC) | | :--- | :--- | :--- | :--- | | patherly | 🕒 Building ([View Logs](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134/service/95f556ff-5264-4116-a0c2-618a2fc53ba4?id=abc0da79-b5c7-4212-be9a-dfd949baaeef&environmentId=c0a1241e-c3df-4686-b005-b67e7125b87b)) | | Apr 9, 2026 at 4:42 am | | hopeful-liberation | 🕒 Building ([View Logs](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134/service/e1db2ee3-d241-4f45-abe4-c9c5fdf483d5?id=2b7e51d2-8d80-4d12-961e-c34bd248a493&environmentId=c0a1241e-c3df-4686-b005-b67e7125b87b)) | | Apr 9, 2026 at 4:42 am |
Sign in to join this conversation.