"""add_compliance_tables Revision ID: b014compliance Revises: b013campaigns Create Date: 2026-02-09 20:00:00.000000 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa from sqlalchemy.dialects import postgresql # revision identifiers, used by Alembic. revision: str = "b014compliance" down_revision: Union[str, None] = "b013campaigns" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ── compliance_frameworks ───────────────────────────────────── op.create_table( "compliance_frameworks", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True), sa.Column("name", sa.String, unique=True, nullable=False), sa.Column("version", sa.String, nullable=True), sa.Column("description", sa.Text, nullable=True), sa.Column("url", sa.String, nullable=True), sa.Column("is_active", sa.Boolean, server_default="true"), sa.Column("created_at", sa.DateTime, server_default=sa.func.now()), ) # ── compliance_controls ─────────────────────────────────────── op.create_table( "compliance_controls", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True), sa.Column( "framework_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("compliance_frameworks.id", ondelete="CASCADE"), nullable=False, ), sa.Column("control_id", sa.String, nullable=False), sa.Column("title", sa.String, nullable=False), sa.Column("description", sa.Text, nullable=True), sa.Column("category", sa.String, nullable=True), ) op.create_index( "ix_compliance_controls_framework", "compliance_controls", ["framework_id"], ) # ── compliance_control_mappings ─────────────────────────────── op.create_table( "compliance_control_mappings", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True), sa.Column( "compliance_control_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("compliance_controls.id", ondelete="CASCADE"), nullable=False, ), sa.Column( "technique_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("techniques.id", ondelete="CASCADE"), nullable=False, ), ) op.create_index( "ix_compliance_mappings_control", "compliance_control_mappings", ["compliance_control_id"], ) op.create_index( "ix_compliance_mappings_technique", "compliance_control_mappings", ["technique_id"], ) op.create_unique_constraint( "uq_control_technique", "compliance_control_mappings", ["compliance_control_id", "technique_id"], ) def downgrade() -> None: op.drop_table("compliance_control_mappings") op.drop_table("compliance_controls") op.drop_table("compliance_frameworks")