20260811_484_trusted_delivery_controls.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. """Persist P3-WP06 trusted-delivery control profiles and release gates."""
  2. from alembic import op
  3. revision = "20260811_484"
  4. down_revision = "20260811_483"
  5. branch_labels = None
  6. depends_on = None
  7. def upgrade() -> None:
  8. op.execute(
  9. """
  10. CREATE TABLE public.trusted_delivery_control_profile_versions (
  11. uid UUID PRIMARY KEY, profile_id VARCHAR(40) NOT NULL, version VARCHAR(40) NOT NULL,
  12. status VARCHAR(20) NOT NULL CHECK(status IN ('draft','active','retired')),
  13. profile JSONB NOT NULL CHECK(jsonb_typeof(profile)='object'),
  14. profile_digest CHAR(64) NOT NULL CHECK(profile_digest ~ '^[0-9a-f]{64}$'),
  15. created_by UUID NOT NULL REFERENCES public.users(id), current_version INTEGER NOT NULL DEFAULT 1 CHECK(current_version>0),
  16. created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(), updated_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
  17. UNIQUE(profile_id,version)
  18. );
  19. CREATE UNIQUE INDEX uq_trusted_delivery_active_control_profile
  20. ON public.trusted_delivery_control_profile_versions(profile_id) WHERE status='active';
  21. CREATE TABLE public.trusted_delivery_control_profile_transitions (
  22. uid UUID PRIMARY KEY, profile_uid UUID NOT NULL REFERENCES public.trusted_delivery_control_profile_versions(uid),
  23. operation VARCHAR(20) NOT NULL CHECK(operation IN ('activate','rollback')),
  24. idempotency_key VARCHAR(160) NOT NULL UNIQUE, request_digest CHAR(64) NOT NULL CHECK(request_digest ~ '^[0-9a-f]{64}$'),
  25. approval_ref VARCHAR(200) NOT NULL, approval_digest CHAR(64) NOT NULL CHECK(approval_digest ~ '^[0-9a-f]{64}$'),
  26. actor_uid UUID NOT NULL REFERENCES public.users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp()
  27. );
  28. CREATE TABLE public.trusted_delivery_capability_approvals (
  29. uid UUID PRIMARY KEY, provider VARCHAR(20) NOT NULL CHECK(provider IN ('kms','dlp','siem','iam','target')),
  30. capability VARCHAR(80) NOT NULL, version VARCHAR(40) NOT NULL,
  31. config_digest CHAR(64) NOT NULL CHECK(config_digest ~ '^[0-9a-f]{64}$'),
  32. status VARCHAR(20) NOT NULL CHECK(status IN ('approved','revoked')),
  33. idempotency_key VARCHAR(160) NOT NULL UNIQUE, request_digest CHAR(64) NOT NULL CHECK(request_digest ~ '^[0-9a-f]{64}$'),
  34. created_by UUID NOT NULL REFERENCES public.users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
  35. UNIQUE(provider,capability,version)
  36. );
  37. CREATE UNIQUE INDEX uq_trusted_delivery_active_capability
  38. ON public.trusted_delivery_capability_approvals(provider,capability) WHERE status='approved';
  39. CREATE TABLE public.trusted_delivery_supply_chain_gates (
  40. uid UUID PRIMARY KEY, artifact_digest CHAR(64) NOT NULL CHECK(artifact_digest ~ '^[0-9a-f]{64}$'),
  41. sbom_digest CHAR(64) NOT NULL CHECK(sbom_digest ~ '^[0-9a-f]{64}$'),
  42. license_policy_digest CHAR(64) NOT NULL CHECK(license_policy_digest ~ '^[0-9a-f]{64}$'),
  43. vulnerability_scan_digest CHAR(64) NOT NULL CHECK(vulnerability_scan_digest ~ '^[0-9a-f]{64}$'),
  44. approval_id VARCHAR(160) NOT NULL, approval_version VARCHAR(40) NOT NULL,
  45. evidence_expires_at TIMESTAMPTZ NOT NULL, decision_code VARCHAR(80) NOT NULL CHECK(decision_code IN ('RELEASE_GATE_APPROVED','RELEASE_GATE_REJECTED')),
  46. idempotency_key VARCHAR(160) NOT NULL UNIQUE, request_digest CHAR(64) NOT NULL CHECK(request_digest ~ '^[0-9a-f]{64}$'),
  47. created_by UUID NOT NULL REFERENCES public.users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp()
  48. );
  49. CREATE TABLE public.trusted_delivery_control_evidence (
  50. uid UUID PRIMARY KEY, evidence_ref VARCHAR(200) NOT NULL UNIQUE,
  51. evidence_digest CHAR(64) NOT NULL CHECK(evidence_digest ~ '^[0-9a-f]{64}$'), decision_code VARCHAR(120) NOT NULL,
  52. gate_uid UUID REFERENCES public.trusted_delivery_supply_chain_gates(uid), actor_uid UUID NOT NULL REFERENCES public.users(id),
  53. created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp()
  54. );
  55. CREATE OR REPLACE FUNCTION public.protect_trusted_delivery_control_evidence() RETURNS trigger LANGUAGE plpgsql AS $$
  56. BEGIN RAISE EXCEPTION 'trusted delivery control evidence is append-only'; END $$;
  57. CREATE TRIGGER trg_trusted_delivery_control_evidence_append_only BEFORE UPDATE OR DELETE OR TRUNCATE
  58. ON public.trusted_delivery_control_evidence FOR EACH STATEMENT EXECUTE FUNCTION public.protect_trusted_delivery_control_evidence();
  59. CREATE TABLE public.trusted_delivery_destruction_approvals (
  60. uid UUID PRIMARY KEY, asset_uid UUID NOT NULL, approval_ref_one VARCHAR(200) NOT NULL, approval_ref_two VARCHAR(200) NOT NULL,
  61. evidence_digest CHAR(64) NOT NULL CHECK(evidence_digest ~ '^[0-9a-f]{64}$'), status VARCHAR(20) NOT NULL CHECK(status IN ('approved','blocked')),
  62. idempotency_key VARCHAR(160) NOT NULL UNIQUE, request_digest CHAR(64) NOT NULL CHECK(request_digest ~ '^[0-9a-f]{64}$'),
  63. created_by UUID NOT NULL REFERENCES public.users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
  64. CHECK(approval_ref_one<>approval_ref_two)
  65. );
  66. CREATE OR REPLACE FUNCTION public.block_trusted_delivery_destruction_on_hold() RETURNS trigger LANGUAGE plpgsql AS $$
  67. BEGIN
  68. IF EXISTS(SELECT 1 FROM public.trusted_delivery_legal_holds WHERE asset_uid=NEW.asset_uid AND status='active') THEN
  69. RAISE EXCEPTION 'destruction blocked by active legal hold';
  70. END IF;
  71. RETURN NEW;
  72. END $$;
  73. CREATE TRIGGER trg_trusted_delivery_destruction_hold BEFORE INSERT ON public.trusted_delivery_destruction_approvals
  74. FOR EACH ROW EXECUTE FUNCTION public.block_trusted_delivery_destruction_on_hold();
  75. """
  76. )
  77. def downgrade() -> None:
  78. op.execute(
  79. """DO $$ BEGIN
  80. IF EXISTS(SELECT 1 FROM public.trusted_delivery_control_profile_versions)
  81. OR EXISTS(SELECT 1 FROM public.trusted_delivery_capability_approvals)
  82. OR EXISTS(SELECT 1 FROM public.trusted_delivery_supply_chain_gates)
  83. OR EXISTS(SELECT 1 FROM public.trusted_delivery_control_evidence)
  84. OR EXISTS(SELECT 1 FROM public.trusted_delivery_destruction_approvals) THEN
  85. RAISE EXCEPTION 'downgrade requires approved control archival migration';
  86. END IF;
  87. END $$;
  88. DROP TABLE public.trusted_delivery_destruction_approvals;
  89. DROP FUNCTION public.block_trusted_delivery_destruction_on_hold();
  90. DROP TABLE public.trusted_delivery_control_evidence;
  91. DROP FUNCTION public.protect_trusted_delivery_control_evidence();
  92. DROP TABLE public.trusted_delivery_supply_chain_gates;
  93. DROP TABLE public.trusted_delivery_capability_approvals;
  94. DROP TABLE public.trusted_delivery_control_profile_transitions;
  95. DROP TABLE public.trusted_delivery_control_profile_versions;"""
  96. )