"""add_dual_validation_fields_to_tests Revision ID: b003dualvalid Revises: b002evidteam Create Date: 2026-02-09 10:02: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 = 'b003dualvalid' down_revision: Union[str, Sequence[str], None] = 'b002evidteam' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: """Drop legacy validated_by/validated_at and add dual validation columns.""" # Drop legacy single-validation columns op.drop_constraint('tests_validated_by_fkey', 'tests', type_='foreignkey') op.drop_column('tests', 'validated_by') op.drop_column('tests', 'validated_at') # ── Red Team fields ───────────────────────────────────────── op.add_column('tests', sa.Column('red_summary', sa.Text(), nullable=True)) op.add_column('tests', sa.Column('attack_success', sa.Boolean(), nullable=True)) op.add_column('tests', sa.Column('red_validated_by', sa.UUID(), nullable=True)) op.add_column('tests', sa.Column('red_validated_at', sa.DateTime(), nullable=True)) op.add_column('tests', sa.Column('red_validation_status', sa.String(), nullable=True)) op.add_column('tests', sa.Column('red_validation_notes', sa.Text(), nullable=True)) # ── Blue Team fields ──────────────────────────────────────── op.add_column('tests', sa.Column('blue_summary', sa.Text(), nullable=True)) op.add_column('tests', sa.Column( 'detection_result', postgresql.ENUM('detected', 'not_detected', 'partially_detected', name='testresult', create_type=False), nullable=True, )) op.add_column('tests', sa.Column('blue_validated_by', sa.UUID(), nullable=True)) op.add_column('tests', sa.Column('blue_validated_at', sa.DateTime(), nullable=True)) op.add_column('tests', sa.Column('blue_validation_status', sa.String(), nullable=True)) op.add_column('tests', sa.Column('blue_validation_notes', sa.Text(), nullable=True)) # ── Foreign keys ──────────────────────────────────────────── op.create_foreign_key( 'fk_tests_red_validated_by', 'tests', 'users', ['red_validated_by'], ['id'], ) op.create_foreign_key( 'fk_tests_blue_validated_by', 'tests', 'users', ['blue_validated_by'], ['id'], ) def downgrade() -> None: """Reverse: drop dual validation columns and restore legacy columns.""" # Drop FKs op.drop_constraint('fk_tests_blue_validated_by', 'tests', type_='foreignkey') op.drop_constraint('fk_tests_red_validated_by', 'tests', type_='foreignkey') # Drop new columns op.drop_column('tests', 'blue_validation_notes') op.drop_column('tests', 'blue_validation_status') op.drop_column('tests', 'blue_validated_at') op.drop_column('tests', 'blue_validated_by') op.drop_column('tests', 'detection_result') op.drop_column('tests', 'blue_summary') op.drop_column('tests', 'red_validation_notes') op.drop_column('tests', 'red_validation_status') op.drop_column('tests', 'red_validated_at') op.drop_column('tests', 'red_validated_by') op.drop_column('tests', 'attack_success') op.drop_column('tests', 'red_summary') # Restore legacy columns op.add_column('tests', sa.Column('validated_by', sa.UUID(), nullable=True)) op.add_column('tests', sa.Column('validated_at', sa.DateTime(), nullable=True)) op.create_foreign_key( 'tests_validated_by_fkey', 'tests', 'users', ['validated_by'], ['id'], )