Skip to main content

ADR 0002: RLS-Based Tenancy + Org-Unit Data Silos

Date: 2025-02-20
Status: Accepted

Context

Evalium must support:

  • strict tenant-level isolation
  • customer internal subdivision (org units / “silos”)
  • future hierarchy (sub-org units)
  • high-level admin visibility
  • small-team UX where org units shouldn't appear

Initial attempts were middleware filtering or SQL WHERE-based scoping. These proved fragile.

Decision

Evalium adopts PostgreSQL Row Level Security (RLS) as the primary enforcer of all data isolation.

Key rules:

  • All user, evaluation, session, submission, and versioned tables include tenant_id and org_unit_id.
  • RLS policies enforce:
    • tenant match
    • org match
    • global admin override
  • All DB access goes through TxManager which injects the correct GUCs using SET LOCAL.
  • Pool-level GUCs removed.
  • Scoped access now verified via shell and Go tests.

Implementation Notes (Current)

  • Tenant + org checks are combined in each policy to avoid OR-based bypasses.
  • TxManager is the only approved DB entrypoint; direct pool Query/Exec is forbidden because it would skip scope.
  • Runtime should use a non-superuser app role (e.g., evalium_app) so RLS is enforced; superusers bypass RLS and invalidate silo tests.
  • Shell regression (org_silos.sh + org_silos_testdb.sh) is the guardrail and must be kept green.

Options Considered

1. App-level filtering (WHERE clauses)

Cons: error-prone; missing filters cause data leaks

2. Hybrid model (filters + partial RLS)

Cons: complicated; still risk of bypass

3. Full RLS + TxManager (chosen)

Pros:

  • Cannot accidentally leak data
  • Clean separation (auth → GUCs → DB)
  • Highly scalable for future staff
  • Works with org hierarchies
    Cons:
  • Requires precise testing
  • Requires strict DB access patterns (no direct pool use)

Consequences

Positive:

  • Secure isolation across tenants/org units
  • Future support for sub-orgs
  • Defence in depth

Negative:

  • Requires strict discipline around TxManager usage
  • Slight learning curve for new engineers

Notes

Supersedes older architecture-overview assumptions.
Matches industry best practices (Stripe, GitLab, Heap).