20260818_552_metering_definer_owner_fence.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. """Transfer every WP12 SECURITY DEFINER function to the fixed NOLOGIN owner."""
  2. from alembic import op
  3. revision = "20260818_552"
  4. down_revision = "20260818_551"
  5. branch_labels = None
  6. depends_on = None
  7. def upgrade() -> None:
  8. # A real restricted migrator owns the functions it created at 551 and is a
  9. # member (not the login identity) of the fixed NOLOGIN role. Keep that
  10. # identity while transferring ownership: SET ROLE would lose ownership of
  11. # the temporary functions before they are fenced.
  12. op.execute(r'''
  13. DO $owner$
  14. DECLARE fn record;
  15. BEGIN
  16. -- Includes the 551 metering_showback_allocation_total_guard trigger
  17. -- function and every renamed legacy gateway still present in pg_proc.
  18. IF NOT EXISTS(SELECT 1 FROM pg_roles WHERE rolname='dataops_tenant_foundation_owner' AND rolcanlogin=false AND rolsuper=false AND rolcreaterole=false) THEN
  19. RAISE EXCEPTION 'WP12 fixed NOLOGIN definer owner must be provisioned by role-init';
  20. END IF;
  21. IF NOT has_schema_privilege('dataops_tenant_foundation_owner','public','CREATE') THEN
  22. RAISE EXCEPTION 'WP12 fixed NOLOGIN definer owner requires public CREATE from role-init';
  23. END IF;
  24. FOR fn IN
  25. SELECT p.proname,pg_get_function_identity_arguments(p.oid) AS args
  26. FROM pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace
  27. WHERE n.nspname='public' AND p.prosecdef AND p.proname LIKE 'metering_showback_%'
  28. LOOP
  29. EXECUTE format('ALTER FUNCTION public.%I(%s) OWNER TO dataops_tenant_foundation_owner',fn.proname,fn.args);
  30. EXECUTE format('REVOKE ALL ON FUNCTION public.%I(%s) FROM PUBLIC,dataops_app,dataops_app_runtime,dataops_bi_ai_catalog_control',fn.proname,fn.args);
  31. END LOOP;
  32. END; $owner$;
  33. GRANT EXECUTE ON FUNCTION public.metering_showback_issue_claim(text,text,jsonb),public.metering_showback_control_write(text,text,jsonb) TO dataops_bi_ai_catalog_control;
  34. GRANT EXECUTE ON FUNCTION public.metering_showback_runtime_write(text,jsonb),public.metering_showback_runtime_read(text,jsonb),public.metering_showback_rollup(jsonb),public.metering_showback_allocation_replay(jsonb) TO dataops_app_runtime;
  35. ''')
  36. def downgrade() -> None:
  37. # Ownership remains fixed on downgrade: restoring a transient migrator as a
  38. # SECURITY DEFINER owner would reintroduce the privilege-retention defect.
  39. return None