"""audit hardening migration — minimal standalone mirror of 0002. Revision ID: 0002 Revises: 0001 """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "0002" down_revision = "0001" branch_labels = None depends_on = None OLD_CONTENT_STATUSES = ("DRAFT", "APPROVED", "PUBLISHED") NEW_CONTENT_STATUSES = ("DRAFT", "APPROVED", "PUBLISHED", "SKIPPED") def upgrade() -> None: with op.batch_alter_table("audit_log") as batch: batch.add_column(sa.Column("prev_hash", sa.String(length=64), nullable=True)) batch.add_column(sa.Column("entry_hash", sa.String(length=64), nullable=True)) batch.create_index("ix_audit_log_entry_hash", ["entry_hash"]) with op.batch_alter_table("proposals") as batch: batch.alter_column("risk_score", new_column_name="match_score") with op.batch_alter_table("mail_messages") as batch: batch.add_column(sa.Column("approved_hash", sa.String(length=64), nullable=True)) batch.add_column(sa.Column("approved_by", sa.String(length=128), nullable=True)) if op.get_bind().dialect.name == "postgresql": op.execute("ALTER TYPE contentstatus ADD VALUE IF NOT EXISTS 'SKIPPED'") with op.batch_alter_table("content_items") as batch: batch.alter_column( "status", existing_type=sa.Enum(*OLD_CONTENT_STATUSES, name="contentstatus"), type_=sa.Enum(*NEW_CONTENT_STATUSES, name="contentstatus"), existing_nullable=False, ) batch.add_column(sa.Column("attempts", sa.Integer(), nullable=False, server_default="0")) batch.add_column(sa.Column("approved_hash", sa.String(length=64), nullable=True)) def downgrade() -> None: with op.batch_alter_table("content_items") as batch: batch.drop_column("approved_hash") batch.drop_column("attempts") batch.alter_column( "status", existing_type=sa.Enum(*NEW_CONTENT_STATUSES, name="contentstatus"), type_=sa.Enum(*OLD_CONTENT_STATUSES, name="contentstatus"), existing_nullable=False, ) with op.batch_alter_table("mail_messages") as batch: batch.drop_column("approved_by") batch.drop_column("approved_hash") with op.batch_alter_table("proposals") as batch: batch.alter_column("match_score", new_column_name="risk_score") with op.batch_alter_table("audit_log") as batch: batch.drop_index("ix_audit_log_entry_hash") batch.drop_column("entry_hash") batch.drop_column("prev_hash")