Terminal
This commit is contained in:
@@ -4,28 +4,17 @@
|
|||||||
-- fact when it is really an absence. None of them widens what anyone may see.
|
-- fact when it is really an absence. None of them widens what anyone may see.
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
-- 1. A billing administrator could not read their own receivables report
|
-- 0. Recognising a caller that bypasses RLS
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
--
|
--
|
||||||
-- v_billing_detail joined public.students purely to build a display name, but
|
-- True for the service role used by server-side code, and for a direct
|
||||||
-- can_access_student() admits org admins, auditors, parents, a student's own
|
-- superuser psql session (where `role` is unset).
|
||||||
-- teacher and campus staff — and NOT billing admins, even though the invoices
|
|
||||||
-- policy grants them every invoice in the organisation. The inner join then
|
|
||||||
-- dropped every row, so the receivables report came back empty for exactly the
|
|
||||||
-- role that exists to run it, with no error to explain why.
|
|
||||||
--
|
|
||||||
-- The tempting fix is to add is_billing_admin() to can_access_student(). That
|
|
||||||
-- would also hand finance staff allergies, chronic_conditions, special_needs,
|
|
||||||
-- disciplinary_history, custody_agreement and primary_physician, which they
|
|
||||||
-- have no business reading. So the name is resolved on its own instead, and
|
|
||||||
-- student row access is left exactly as it was.
|
|
||||||
-- True for callers that bypass RLS outright: the service role used by
|
|
||||||
-- server-side code, and a direct superuser psql session (role unset).
|
|
||||||
--
|
--
|
||||||
-- This MUST read the `role` GUC rather than current_user. Inside a
|
-- This MUST read the `role` GUC rather than current_user. Inside a
|
||||||
-- SECURITY DEFINER function current_user is the function's owner, so
|
-- SECURITY DEFINER function current_user is the function's owner, so
|
||||||
-- pg_has_role(current_user, 'service_role', ...) is true for every caller and
|
-- pg_has_role(current_user, 'service_role', ...) is true for every caller and
|
||||||
-- silently turns an entitlement check into a no-op.
|
-- silently turns an entitlement check into a no-op — which is exactly the trap
|
||||||
|
-- the checks below would otherwise fall into.
|
||||||
CREATE OR REPLACE FUNCTION public.is_service_context()
|
CREATE OR REPLACE FUNCTION public.is_service_context()
|
||||||
RETURNS BOOLEAN
|
RETURNS BOOLEAN
|
||||||
LANGUAGE sql STABLE AS $$
|
LANGUAGE sql STABLE AS $$
|
||||||
|
|||||||
Reference in New Issue
Block a user