20260817_503_tenant_decimal_quota_gateway.py 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. """Permit bounded decimal quota reservations through a corrected closed gateway."""
  2. from alembic import op
  3. revision = "20260817_503"
  4. down_revision = "20260817_502"
  5. branch_labels = None
  6. depends_on = None
  7. def upgrade() -> None:
  8. op.execute(
  9. r"""
  10. CREATE FUNCTION public.tenant_quota_reserve(p_payload jsonb)
  11. RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path=pg_catalog,public AS $tenant_decimal$
  12. DECLARE v_tenant text; v_digest text; v_amount numeric(30,6); v_quota record; v_reservation record; v_fence bigint;
  13. BEGIN
  14. IF jsonb_typeof(p_payload)<>'object' OR NOT (p_payload ?& ARRAY['tenant_id','quota_name','amount','idempotency_key'])
  15. OR p_payload-ARRAY['tenant_id','quota_name','amount','idempotency_key']<>'{}'::jsonb THEN RAISE EXCEPTION 'tenant_payload_closed'; END IF;
  16. v_tenant:=p_payload->>'tenant_id';
  17. IF v_tenant !~ '^[a-z][a-z0-9-]{0,62}$' OR p_payload->>'quota_name' NOT IN ('records','storage_objects','background_tasks','events','models','plugins','connectors','api_concurrency')
  18. OR p_payload->>'idempotency_key' !~ '^[A-Za-z0-9._:-]{1,120}$' OR p_payload->>'amount' !~ '^[0-9]+([.][0-9]{1,6})?$' THEN RAISE EXCEPTION 'tenant_payload_invalid'; END IF;
  19. v_amount:=(p_payload->>'amount')::numeric;
  20. IF v_amount<=0 OR v_amount>1000000000000000000000000::numeric THEN RAISE EXCEPTION 'tenant_payload_invalid'; END IF;
  21. v_digest:=encode(sha256(convert_to(p_payload::text,'utf8')),'hex');
  22. PERFORM set_config('dataops.tenant_id',v_tenant,true);
  23. PERFORM pg_advisory_xact_lock(hashtext(v_tenant || '-quota-' || (p_payload->>'quota_name')));
  24. SELECT * INTO v_reservation FROM public.tenant_quota_reservations WHERE tenant_id=v_tenant AND quota_name=p_payload->>'quota_name' AND idempotency_key=p_payload->>'idempotency_key' FOR UPDATE;
  25. IF FOUND THEN
  26. IF v_reservation.request_digest<>v_digest THEN RAISE EXCEPTION 'tenant_replay_conflict'; END IF;
  27. RETURN jsonb_build_object('tenant_id',v_tenant,'lease_fence',v_reservation.lease_fence,'status',v_reservation.status);
  28. END IF;
  29. SELECT * INTO v_quota FROM public.tenant_quotas WHERE tenant_id=v_tenant AND quota_name=p_payload->>'quota_name' FOR UPDATE;
  30. IF NOT FOUND OR NOT EXISTS(SELECT 1 FROM public.tenants WHERE tenant_id=v_tenant AND state='active') THEN RAISE EXCEPTION 'tenant_not_active'; END IF;
  31. IF v_quota.limit_units-v_quota.reserved_units<v_amount THEN RAISE EXCEPTION 'tenant_quota_exhausted'; END IF;
  32. UPDATE public.tenant_quotas SET reserved_units=reserved_units+v_amount,lease_fence=lease_fence+1,updated_at=clock_timestamp()
  33. WHERE tenant_id=v_tenant AND quota_name=p_payload->>'quota_name' AND lease_fence=v_quota.lease_fence RETURNING lease_fence INTO v_fence;
  34. IF NOT FOUND THEN RAISE EXCEPTION 'tenant_fence_conflict'; END IF;
  35. INSERT INTO public.tenant_quota_reservations(tenant_id,quota_name,idempotency_key,request_digest,amount,lease_fence,status)
  36. VALUES(v_tenant,p_payload->>'quota_name',p_payload->>'idempotency_key',v_digest,v_amount,v_fence,'reserved');
  37. INSERT INTO public.tenant_audit_events(tenant_id,event_type,payload_digest,lease_fence) VALUES(v_tenant,'quota.reserve',v_digest,v_fence);
  38. RETURN jsonb_build_object('tenant_id',v_tenant,'lease_fence',v_fence,'status','reserved');
  39. END; $tenant_decimal$;
  40. ALTER FUNCTION public.tenant_quota_reserve(jsonb) OWNER TO dataops_tenant_foundation_owner;
  41. REVOKE ALL ON FUNCTION public.tenant_quota_reserve(jsonb) FROM PUBLIC;
  42. GRANT EXECUTE ON FUNCTION public.tenant_quota_reserve(jsonb) TO dataops_app_runtime;
  43. """
  44. )
  45. def downgrade() -> None:
  46. op.execute("REVOKE EXECUTE ON FUNCTION public.tenant_quota_reserve(jsonb) FROM dataops_app_runtime; DROP FUNCTION IF EXISTS public.tenant_quota_reserve(jsonb);")