20260811_486_trusted_delivery_database_boundary.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. """Put WP06 state behind a dedicated database owner and write gateway.
  2. The runtime login is deliberately not a member of either role established
  3. here. Role creation is performed only by the one-shot role-init process;
  4. this migration therefore fails closed if a deployment skipped that step.
  5. """
  6. from alembic import op
  7. revision = "20260811_486"
  8. down_revision = "20260811_485"
  9. branch_labels = None
  10. depends_on = None
  11. _TABLES = (
  12. "trusted_delivery_policy_versions",
  13. "trusted_delivery_policy_transitions",
  14. "trusted_delivery_grants",
  15. "trusted_delivery_deliveries",
  16. "trusted_delivery_receipts",
  17. "trusted_delivery_legal_holds",
  18. "trusted_delivery_hold_releases",
  19. "trusted_delivery_evidence",
  20. "trusted_delivery_subscriptions",
  21. "trusted_delivery_subscription_deliveries",
  22. "trusted_delivery_control_profile_versions",
  23. "trusted_delivery_control_profile_transitions",
  24. "trusted_delivery_capability_approvals",
  25. "trusted_delivery_supply_chain_gates",
  26. "trusted_delivery_control_evidence",
  27. "trusted_delivery_destruction_approvals",
  28. )
  29. def upgrade() -> None:
  30. op.execute(
  31. """
  32. DO $$ BEGIN
  33. IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='dataops_trusted_delivery_owner')
  34. OR NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='dataops_trusted_delivery_writer') THEN
  35. RAISE EXCEPTION 'trusted-delivery role-init is required before migration 20260811_486';
  36. END IF;
  37. IF NOT pg_has_role(current_user, 'dataops_trusted_delivery_owner', 'MEMBER')
  38. OR NOT pg_has_role(current_user, 'dataops_trusted_delivery_writer', 'MEMBER') THEN
  39. RAISE EXCEPTION 'migrator must be pre-granted trusted-delivery owner and writer roles';
  40. END IF;
  41. IF (SELECT rolcreaterole OR rolsuper FROM pg_roles WHERE rolname=current_user) THEN
  42. RAISE EXCEPTION 'migration identity must not retain CREATEROLE or superuser';
  43. END IF;
  44. END $$;
  45. CREATE TABLE public.trusted_delivery_approval_facts (
  46. approval_ref VARCHAR(200) PRIMARY KEY,
  47. approval_digest CHAR(64) NOT NULL CHECK(approval_digest ~ '^[0-9a-f]{64}$'),
  48. actor_uid UUID NOT NULL REFERENCES public.users(id),
  49. operation VARCHAR(40) NOT NULL CHECK(operation IN ('activate_policy','rollback_policy','activate_control_profile','rollback_control_profile','grant','release_hold','destruction')),
  50. status VARCHAR(20) NOT NULL CHECK(status IN ('approved','revoked','expired')),
  51. expires_at TIMESTAMPTZ NOT NULL,
  52. signed_receipt_digest CHAR(64) NOT NULL CHECK(signed_receipt_digest ~ '^[0-9a-f]{64}$'),
  53. created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp()
  54. );
  55. CREATE OR REPLACE FUNCTION public.trusted_delivery_write(p_operation text, p_payload jsonb)
  56. RETURNS jsonb
  57. LANGUAGE plpgsql
  58. SECURITY DEFINER
  59. SET search_path = pg_catalog, public
  60. AS $trusted_delivery_write$
  61. DECLARE
  62. v_uid uuid;
  63. v_policy uuid;
  64. v_existing record;
  65. v_approval text;
  66. v_digest text;
  67. v_actor uuid;
  68. BEGIN
  69. IF p_operation NOT IN ('create_policy','transition_policy','create_grant','create_subscription')
  70. OR jsonb_typeof(p_payload) <> 'object' THEN
  71. RAISE EXCEPTION 'trusted-delivery write is not permitted';
  72. END IF;
  73. IF p_operation='create_policy' THEN
  74. IF NOT (p_payload ?& ARRAY['uid','code','version','selector','resource_rules','created_by'])
  75. OR p_payload - ARRAY['uid','code','version','selector','resource_rules','created_by','current_version'] <> '{}'::jsonb
  76. OR jsonb_typeof(p_payload->'selector')<>'object' OR jsonb_typeof(p_payload->'resource_rules')<>'object' THEN
  77. RAISE EXCEPTION 'trusted-delivery policy payload is closed';
  78. END IF;
  79. v_uid := (p_payload->>'uid')::uuid;
  80. v_actor := (p_payload->>'created_by')::uuid;
  81. IF NOT EXISTS (SELECT 1 FROM public.users WHERE id=v_actor AND status='active') THEN RAISE EXCEPTION 'trusted-delivery actor is unavailable'; END IF;
  82. INSERT INTO public.trusted_delivery_policy_versions(uid,code,version,status,selector,resource_rules,created_by,current_version)
  83. VALUES(v_uid,p_payload->>'code',p_payload->>'version','draft',p_payload->'selector',p_payload->'resource_rules',v_actor,COALESCE((p_payload->>'current_version')::int,1));
  84. RETURN jsonb_build_object('uid',v_uid::text,'code',p_payload->>'code','version',p_payload->>'version','status','draft','current_version',COALESCE((p_payload->>'current_version')::int,1));
  85. END IF;
  86. IF p_operation='transition_policy' THEN
  87. IF NOT (p_payload ?& ARRAY['code','version','operation','idempotency_key','request_digest','actor_uid','approval_ref','approval_digest'])
  88. OR p_payload - ARRAY['code','version','operation','idempotency_key','request_digest','actor_uid','approval_ref','approval_digest'] <> '{}'::jsonb THEN
  89. RAISE EXCEPTION 'trusted-delivery transition payload is closed';
  90. END IF;
  91. v_approval:=p_payload->>'approval_ref'; v_digest:=p_payload->>'approval_digest'; v_actor:=(p_payload->>'actor_uid')::uuid;
  92. IF NOT EXISTS (SELECT 1 FROM public.trusted_delivery_approval_facts WHERE approval_ref=v_approval AND approval_digest=v_digest AND actor_uid=v_actor AND operation=CASE WHEN p_payload->>'operation'='activate' THEN 'activate_policy' ELSE 'rollback_policy' END AND status='approved' AND expires_at>clock_timestamp()) THEN
  93. RAISE EXCEPTION 'trusted-delivery transition requires protected approval fact';
  94. END IF;
  95. SELECT policy_uid,request_digest INTO v_existing FROM public.trusted_delivery_policy_transitions WHERE idempotency_key=p_payload->>'idempotency_key';
  96. IF FOUND THEN
  97. IF v_existing.request_digest <> p_payload->>'request_digest' THEN RAISE EXCEPTION 'trusted delivery idempotency conflict'; END IF;
  98. RETURN (SELECT jsonb_build_object('uid',uid::text,'code',code,'version',version,'status',status,'current_version',current_version) FROM public.trusted_delivery_policy_versions WHERE uid=v_existing.policy_uid);
  99. END IF;
  100. SELECT uid INTO v_policy FROM public.trusted_delivery_policy_versions WHERE code=p_payload->>'code' AND version=p_payload->>'version' FOR UPDATE;
  101. IF NOT FOUND THEN RAISE EXCEPTION 'trusted delivery policy version was not found'; END IF;
  102. PERFORM 1 FROM public.trusted_delivery_policy_versions WHERE code=p_payload->>'code' AND status='active' FOR UPDATE;
  103. UPDATE public.trusted_delivery_policy_versions SET status='retired',current_version=current_version+1 WHERE code=p_payload->>'code' AND status='active' AND uid<>v_policy;
  104. UPDATE public.trusted_delivery_policy_versions SET status='active',current_version=current_version+CASE WHEN status='active' THEN 0 ELSE 1 END WHERE uid=v_policy;
  105. INSERT INTO public.trusted_delivery_policy_transitions(uid,policy_uid,operation,idempotency_key,request_digest,approval_ref,approval_digest,actor_uid)
  106. VALUES(gen_random_uuid(),v_policy,p_payload->>'operation',p_payload->>'idempotency_key',p_payload->>'request_digest',v_approval,v_digest,v_actor);
  107. RETURN (SELECT jsonb_build_object('uid',uid::text,'code',code,'version',version,'status',status,'current_version',current_version) FROM public.trusted_delivery_policy_versions WHERE uid=v_policy);
  108. END IF;
  109. IF p_operation='create_grant' THEN
  110. IF NOT (p_payload ?& ARRAY['uid','policy_uid','subject_uid','asset_uid','provider','idempotency_key','request_digest','expires_at','status','reason_code','created_by','approval_ref','approval_digest','purpose','environment','target_capability'])
  111. OR p_payload - ARRAY['uid','policy_uid','subject_uid','asset_uid','provider','idempotency_key','request_digest','expires_at','status','reason_code','current_version','created_by','approval_ref','approval_digest','purpose','environment','target_capability'] <> '{}'::jsonb THEN RAISE EXCEPTION 'trusted-delivery grant payload is closed'; END IF;
  112. v_approval:=p_payload->>'approval_ref'; v_digest:=p_payload->>'approval_digest'; v_actor:=(p_payload->>'created_by')::uuid;
  113. IF NOT EXISTS (SELECT 1 FROM public.trusted_delivery_approval_facts WHERE approval_ref=v_approval AND approval_digest=v_digest AND actor_uid=v_actor AND operation='grant' AND status='approved' AND expires_at>clock_timestamp()) THEN RAISE EXCEPTION 'trusted-delivery grant requires protected approval fact'; END IF;
  114. INSERT INTO public.trusted_delivery_grants(uid,policy_uid,subject_uid,asset_uid,provider,idempotency_key,request_digest,expires_at,status,reason_code,current_version,created_by,approval_ref,approval_digest,purpose,environment,target_capability)
  115. VALUES((p_payload->>'uid')::uuid,(p_payload->>'policy_uid')::uuid,(p_payload->>'subject_uid')::uuid,(p_payload->>'asset_uid')::uuid,p_payload->>'provider',p_payload->>'idempotency_key',p_payload->>'request_digest',(p_payload->>'expires_at')::timestamptz,p_payload->>'status',p_payload->>'reason_code',COALESCE((p_payload->>'current_version')::int,1),v_actor,v_approval,v_digest,p_payload->>'purpose',p_payload->>'environment',p_payload->'target_capability');
  116. RETURN jsonb_build_object('uid', p_payload->>'uid', 'status', p_payload->>'status');
  117. END IF;
  118. IF p_operation='create_subscription' THEN
  119. IF NOT (p_payload ?& ARRAY['uid','grant_uid','asset_uid','trigger','purpose','expires_at','idempotency_key','request_digest','status','created_by'])
  120. OR p_payload - ARRAY['uid','grant_uid','asset_uid','trigger','purpose','expires_at','idempotency_key','request_digest','status','current_version','created_by'] <> '{}'::jsonb
  121. OR jsonb_typeof(p_payload->'trigger')<>'object' THEN RAISE EXCEPTION 'trusted-delivery subscription payload is closed'; END IF;
  122. INSERT INTO public.trusted_delivery_subscriptions(uid,grant_uid,asset_uid,trigger,purpose,expires_at,idempotency_key,request_digest,status,current_version,created_by)
  123. VALUES((p_payload->>'uid')::uuid,(p_payload->>'grant_uid')::uuid,(p_payload->>'asset_uid')::uuid,p_payload->'trigger',p_payload->>'purpose',(p_payload->>'expires_at')::timestamptz,p_payload->>'idempotency_key',p_payload->>'request_digest',p_payload->>'status',COALESCE((p_payload->>'current_version')::int,1),(p_payload->>'created_by')::uuid);
  124. RETURN jsonb_build_object('uid',p_payload->>'uid','grant_uid',p_payload->>'grant_uid','asset_uid',p_payload->>'asset_uid','trigger',p_payload->'trigger','purpose',p_payload->>'purpose','expires_at',p_payload->>'expires_at','status',p_payload->>'status','current_version',COALESCE((p_payload->>'current_version')::int,1));
  125. END IF;
  126. RAISE EXCEPTION 'trusted-delivery write operation is not implemented';
  127. END $trusted_delivery_write$;
  128. REVOKE ALL ON FUNCTION public.trusted_delivery_write(text,jsonb) FROM PUBLIC;
  129. GRANT EXECUTE ON FUNCTION public.trusted_delivery_write(text,jsonb) TO dataops_app_runtime;
  130. """
  131. )
  132. for table in _TABLES:
  133. op.execute(f"ALTER TABLE public.{table} OWNER TO dataops_trusted_delivery_owner")
  134. op.execute(
  135. f"REVOKE INSERT, UPDATE, DELETE, TRUNCATE ON TABLE public.{table} FROM dataops_app_runtime"
  136. )
  137. op.execute(f"GRANT SELECT ON TABLE public.{table} TO dataops_app_runtime")
  138. op.execute(f"GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.{table} TO dataops_trusted_delivery_writer")
  139. op.execute("ALTER TABLE public.trusted_delivery_approval_facts OWNER TO dataops_trusted_delivery_owner")
  140. op.execute("REVOKE ALL ON TABLE public.trusted_delivery_approval_facts FROM PUBLIC, dataops_app_runtime")
  141. op.execute("GRANT SELECT ON TABLE public.trusted_delivery_approval_facts TO dataops_trusted_delivery_writer")
  142. op.execute("ALTER FUNCTION public.trusted_delivery_write(text,jsonb) OWNER TO dataops_trusted_delivery_writer")
  143. def downgrade() -> None:
  144. op.execute(
  145. """
  146. DO $$ BEGIN
  147. IF EXISTS (SELECT 1 FROM public.trusted_delivery_approval_facts) THEN
  148. RAISE EXCEPTION 'downgrade requires approved trusted-delivery approval-fact archival migration';
  149. END IF;
  150. END $$;
  151. REVOKE EXECUTE ON FUNCTION public.trusted_delivery_write(text,jsonb) FROM dataops_app_runtime;
  152. DROP FUNCTION public.trusted_delivery_write(text,jsonb);
  153. DROP TABLE public.trusted_delivery_approval_facts;
  154. """
  155. )