Security Improvements: Organization Filtering
Tenant isolation is enforced primarily by the ORM auto-filter and PostgreSQL
row-level security described in Multi-tenancy.
This page covers the tooling that guards those guarantees against regressions in
code paths that add explicit organization_id filters (or bypass the ORM).
CI scan for missing filters
scripts/check_organization_filtering.py scans the codebase for database
queries on organization-scoped models that may be missing an organization_id
filter. It classifies findings as HIGH (queries on organization-aware models) or
MEDIUM (potentially unsafe) severity and exits non-zero when HIGH-severity issues
are found, so it can gate a build.
Exit codes: 0 no issues, 1 issues to address, 2 script error.
Regression tests
Cross-tenant isolation is covered by the suite under tests/backend/security/,
marked with the security pytest marker:
Key files: test_organization_filtering.py, test_cross_tenant_isolation.py,
test_rls_coverage.py, and test_service_security.py.
Writing org-safe queries
When a query bypasses the ORM auto-filter (raw SQL, db.execute(select(...)),
bulk operations), add the tenant predicate explicitly. ID lookups on globally
unique UUIDs are safe without it; list and search queries on non-unique fields
are not: