feat: Phase 2 tenant isolation — RLS on 11 session tables #134

Merged
chihlasm merged 16 commits from feat/tenant-isolation-phase-2 into main 2026-04-11 07:02:25 +00:00
chihlasm commented 2026-04-10 14:26:36 +00:00 (Migrated from github.com)

Summary

  • P2-A: Fixed account_id NOT NULL write-path bugs on session_supporting_data, session_resolution_outputs, maintenance_schedules, and psa_post_log (3 write paths across psa_documentation_service.py and sessions.py)
  • P2-B: access_share endpoint switched to get_admin_db (BYPASSRLS) to handle cross-tenant session reads for public share links without leaking data to app-role queries
  • P2-C: Migration 70a5dd746e83 — enables FORCE ROW LEVEL SECURITY on 11 tables; 10 with standard tenant-only policy, step_library with visibility-aware policy (OR visibility = 'public') to preserve cross-tenant public step access
  • P2-D: 15 RLS isolation tests covering all 11 tables; seeded Account B data ensures tests are non-vacuous; includes step_library public-visibility regression test

Tables covered

sessions, ai_sessions, session_branches, session_supporting_data, session_resolution_outputs, session_handoffs, maintenance_schedules, psa_post_log, script_templates, script_generations, script_categories, step_library

What's next (Phase 3)

  • Backfill account_id on audit_logs, step_ratings, step_usage_logs, target_list_items
  • Add account_id column to tree_nodes, session_notes, session_node_states, user_invites — then enable RLS
  • Enable RLS on users / subscriptions (requires embedding account_id in JWT)

Test plan

  • Migrate DB: alembic upgrade head — verify Phase 2 migration applies cleanly on top of Phase 1
  • Run RLS isolation tests: pytest tests/test_rls_isolation.py -v (requires running PostgreSQL with RLS-configured roles)
  • Smoke test share links — public share access still works after access_shareget_admin_db change
  • Smoke test Solutions Library — public steps visible cross-tenant

🤖 Generated with Claude Code

## Summary - **P2-A:** Fixed `account_id NOT NULL` write-path bugs on `session_supporting_data`, `session_resolution_outputs`, `maintenance_schedules`, and `psa_post_log` (3 write paths across `psa_documentation_service.py` and `sessions.py`) - **P2-B:** `access_share` endpoint switched to `get_admin_db` (BYPASSRLS) to handle cross-tenant session reads for public share links without leaking data to app-role queries - **P2-C:** Migration `70a5dd746e83` — enables `FORCE ROW LEVEL SECURITY` on 11 tables; 10 with standard tenant-only policy, `step_library` with visibility-aware policy (`OR visibility = 'public'`) to preserve cross-tenant public step access - **P2-D:** 15 RLS isolation tests covering all 11 tables; seeded Account B data ensures tests are non-vacuous; includes `step_library` public-visibility regression test ## Tables covered `sessions`, `ai_sessions`, `session_branches`, `session_supporting_data`, `session_resolution_outputs`, `session_handoffs`, `maintenance_schedules`, `psa_post_log`, `script_templates`, `script_generations`, `script_categories`, `step_library` ## What's next (Phase 3) - Backfill `account_id` on `audit_logs`, `step_ratings`, `step_usage_logs`, `target_list_items` - Add `account_id` column to `tree_nodes`, `session_notes`, `session_node_states`, `user_invites` — then enable RLS - Enable RLS on `users` / `subscriptions` (requires embedding `account_id` in JWT) ## Test plan - [ ] Migrate DB: `alembic upgrade head` — verify Phase 2 migration applies cleanly on top of Phase 1 - [ ] Run RLS isolation tests: `pytest tests/test_rls_isolation.py -v` (requires running PostgreSQL with RLS-configured roles) - [ ] Smoke test share links — public share access still works after `access_share` → `get_admin_db` change - [ ] Smoke test Solutions Library — public steps visible cross-tenant 🤖 Generated with [Claude Code](https://claude.com/claude-code)
railway-app[bot] commented 2026-04-10 14:26:51 +00:00 (Migrated from github.com)

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

Service Status Web Updated (UTC)
patherly Success (View Logs) Apr 11, 2026 at 5:29 am
hopeful-liberation Success (View Logs) Apr 11, 2026 at 5:29 am
<!-- railway-bot-comment-version=2 --> <!-- railway-project-id="22b9b58c-271b-42e5-a10e-6fdec8d00134" railway-project-name="selfless-grace" --> 🚅 Deployed to the [resolutionflow-pr-134](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134?environmentId=d23524d4-ee2d-4c83-a7ac-38d9ca3163fb) environment in **[selfless-grace](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134)** | **Service** | **Status** | **Web** | **Updated** (UTC) | | :--- | :--- | :--- | :--- | | patherly | ✅ Success ([View Logs](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134/service/95f556ff-5264-4116-a0c2-618a2fc53ba4?id=e85c1811-cf56-47ae-921e-6bf7db6421e4&environmentId=d23524d4-ee2d-4c83-a7ac-38d9ca3163fb)) | | Apr 11, 2026 at 5:29 am | | hopeful-liberation | ✅ Success ([View Logs](https://railway.com/project/22b9b58c-271b-42e5-a10e-6fdec8d00134/service/e1db2ee3-d241-4f45-abe4-c9c5fdf483d5?id=0f9adb3c-6e92-4192-9b00-12b828b96703&environmentId=d23524d4-ee2d-4c83-a7ac-38d9ca3163fb)) | | Apr 11, 2026 at 5:29 am |
Sign in to join this conversation.