20260811_485_trusted_delivery_hardening.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. """Close WP06 asset-state races and database-side trusted-delivery guards."""
  2. from alembic import op
  3. revision = "20260811_485"
  4. down_revision = "20260811_484"
  5. branch_labels = None
  6. depends_on = None
  7. def upgrade() -> None:
  8. op.execute(r"""
  9. CREATE OR REPLACE FUNCTION public.lock_trusted_delivery_asset(p_asset UUID)
  10. RETURNS void LANGUAGE plpgsql AS $$
  11. BEGIN
  12. PERFORM pg_advisory_xact_lock(hashtextextended(p_asset::text, 485));
  13. END $$;
  14. CREATE OR REPLACE FUNCTION public.guard_trusted_delivery_hold_asset()
  15. RETURNS trigger LANGUAGE plpgsql AS $$
  16. BEGIN
  17. PERFORM public.lock_trusted_delivery_asset(NEW.asset_uid);
  18. IF NEW.status='active' THEN UPDATE public.trusted_delivery_destruction_approvals SET status='blocked' WHERE asset_uid=NEW.asset_uid AND status='approved'; END IF;
  19. RETURN NEW;
  20. END $$;
  21. CREATE TRIGGER trg_trusted_delivery_hold_asset_lock BEFORE INSERT OR UPDATE OF status ON public.trusted_delivery_legal_holds FOR EACH ROW EXECUTE FUNCTION public.guard_trusted_delivery_hold_asset();
  22. CREATE OR REPLACE FUNCTION public.guard_trusted_delivery_destruction_asset()
  23. RETURNS trigger LANGUAGE plpgsql AS $$
  24. BEGIN
  25. PERFORM public.lock_trusted_delivery_asset(NEW.asset_uid);
  26. IF NEW.status='approved' AND EXISTS(SELECT 1 FROM public.trusted_delivery_legal_holds WHERE asset_uid=NEW.asset_uid AND status='active') THEN RAISE EXCEPTION 'destruction blocked by active legal hold'; END IF;
  27. RETURN NEW;
  28. END $$;
  29. DROP TRIGGER IF EXISTS trg_trusted_delivery_destruction_hold ON public.trusted_delivery_destruction_approvals;
  30. CREATE TRIGGER trg_trusted_delivery_destruction_asset_lock BEFORE INSERT OR UPDATE OF asset_uid,status ON public.trusted_delivery_destruction_approvals FOR EACH ROW EXECUTE FUNCTION public.guard_trusted_delivery_destruction_asset();
  31. CREATE OR REPLACE FUNCTION public.enforce_trusted_delivery_grant_active()
  32. RETURNS trigger LANGUAGE plpgsql AS $$
  33. BEGIN
  34. IF NEW.status='active' THEN
  35. IF NEW.approval_ref IS NULL OR NEW.approval_digest IS NULL OR NEW.purpose IS NULL OR NEW.environment IS NULL OR NEW.target_capability IS NULL OR jsonb_typeof(NEW.target_capability)<>'object' THEN RAISE EXCEPTION 'active trusted delivery grant requires bound approval and projection'; END IF;
  36. IF NOT EXISTS(SELECT 1 FROM public.trusted_delivery_policy_versions p WHERE p.uid=NEW.policy_uid AND p.status='active') OR NOT EXISTS(SELECT 1 FROM public.trusted_delivery_policy_transitions t WHERE t.policy_uid=NEW.policy_uid AND t.operation IN ('activate','rollback')) THEN RAISE EXCEPTION 'active trusted delivery grant requires active approved policy'; END IF;
  37. END IF;
  38. RETURN NEW;
  39. END $$;
  40. CREATE TRIGGER trg_trusted_delivery_grant_active_guard BEFORE INSERT OR UPDATE OF status,policy_uid,approval_ref,approval_digest,purpose,environment,target_capability ON public.trusted_delivery_grants FOR EACH ROW EXECUTE FUNCTION public.enforce_trusted_delivery_grant_active();
  41. CREATE OR REPLACE FUNCTION public.enforce_trusted_delivery_subscription_guard()
  42. RETURNS trigger LANGUAGE plpgsql AS $$
  43. DECLARE g RECORD; s RECORD;
  44. BEGIN
  45. IF TG_TABLE_NAME='trusted_delivery_subscriptions' THEN
  46. IF NEW.status='active' THEN SELECT subject_uid,asset_uid,purpose,expires_at,status INTO g FROM public.trusted_delivery_grants WHERE uid=NEW.grant_uid FOR KEY SHARE; IF NOT FOUND OR g.status<>'active' OR g.expires_at<=clock_timestamp() OR g.asset_uid<>NEW.asset_uid OR g.purpose<>NEW.purpose OR NEW.created_by<>g.subject_uid OR NEW.expires_at<=clock_timestamp() OR NEW.expires_at>g.expires_at OR EXISTS(SELECT 1 FROM public.trusted_delivery_legal_holds h WHERE h.asset_uid=NEW.asset_uid AND h.status='active') THEN RAISE EXCEPTION 'subscription activation requires current subject-bound grant without legal hold'; END IF; END IF;
  47. ELSE
  48. SELECT sub.status,sub.expires_at,sub.asset_uid,sub.grant_uid,gr.status AS grant_status,gr.expires_at AS grant_expires_at INTO s FROM public.trusted_delivery_subscriptions sub JOIN public.trusted_delivery_grants gr ON gr.uid=sub.grant_uid WHERE sub.uid=NEW.subscription_uid FOR KEY SHARE; IF NOT FOUND OR s.status<>'active' OR s.expires_at<=clock_timestamp() OR s.grant_status<>'active' OR s.grant_expires_at<=clock_timestamp() OR EXISTS(SELECT 1 FROM public.trusted_delivery_legal_holds h WHERE h.asset_uid=s.asset_uid AND h.status='active') THEN RAISE EXCEPTION 'subscription delivery requires current grant without legal hold'; END IF;
  49. END IF;
  50. RETURN NEW;
  51. END $$;
  52. CREATE TRIGGER trg_trusted_delivery_subscription_guard BEFORE INSERT OR UPDATE OF status,grant_uid,asset_uid,purpose,expires_at,created_by ON public.trusted_delivery_subscriptions FOR EACH ROW EXECUTE FUNCTION public.enforce_trusted_delivery_subscription_guard();
  53. CREATE TRIGGER trg_trusted_delivery_subscription_delivery_guard BEFORE INSERT OR UPDATE OF status,subscription_uid ON public.trusted_delivery_subscription_deliveries FOR EACH ROW EXECUTE FUNCTION public.enforce_trusted_delivery_subscription_guard();
  54. CREATE UNIQUE INDEX uq_trusted_delivery_single_revoke ON public.trusted_delivery_deliveries(grant_uid) WHERE operation='revoke';
  55. DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname='dataops_app_runtime') AND EXISTS (SELECT 1 FROM pg_roles WHERE rolname='dataops_edge_evidence_owner') THEN ALTER TABLE public.trusted_delivery_evidence OWNER TO dataops_edge_evidence_owner; ALTER TABLE public.trusted_delivery_receipts OWNER TO dataops_edge_evidence_owner; ALTER FUNCTION public.protect_trusted_delivery_evidence() OWNER TO dataops_edge_evidence_owner; ALTER FUNCTION public.protect_trusted_delivery_receipt() OWNER TO dataops_edge_evidence_owner; REVOKE INSERT,UPDATE,DELETE,TRUNCATE ON public.trusted_delivery_evidence,public.trusted_delivery_receipts FROM dataops_app_runtime; GRANT SELECT ON public.trusted_delivery_evidence,public.trusted_delivery_receipts TO dataops_app_runtime; END IF; END $$;
  56. """)
  57. def downgrade() -> None:
  58. op.execute("""
  59. DO $$ BEGIN IF EXISTS(SELECT 1 FROM public.trusted_delivery_destruction_approvals WHERE status='blocked') THEN RAISE EXCEPTION 'downgrade requires approved hardening archival migration'; END IF; END $$;
  60. DROP INDEX public.uq_trusted_delivery_single_revoke;
  61. DROP TRIGGER trg_trusted_delivery_subscription_delivery_guard ON public.trusted_delivery_subscription_deliveries;
  62. DROP TRIGGER trg_trusted_delivery_subscription_guard ON public.trusted_delivery_subscriptions;
  63. DROP FUNCTION public.enforce_trusted_delivery_subscription_guard();
  64. DROP TRIGGER trg_trusted_delivery_grant_active_guard ON public.trusted_delivery_grants;
  65. DROP FUNCTION public.enforce_trusted_delivery_grant_active();
  66. DROP TRIGGER trg_trusted_delivery_destruction_asset_lock ON public.trusted_delivery_destruction_approvals;
  67. CREATE TRIGGER trg_trusted_delivery_destruction_hold BEFORE INSERT ON public.trusted_delivery_destruction_approvals FOR EACH ROW EXECUTE FUNCTION public.block_trusted_delivery_destruction_on_hold();
  68. DROP FUNCTION public.guard_trusted_delivery_destruction_asset();
  69. DROP TRIGGER trg_trusted_delivery_hold_asset_lock ON public.trusted_delivery_legal_holds;
  70. DROP FUNCTION public.guard_trusted_delivery_hold_asset();
  71. DROP FUNCTION public.lock_trusted_delivery_asset(UUID);
  72. """)