"""Identity-consumer request — single-use token-issue guard. Adds ``identity_consumer_requests.token_issued_at``: the authoritative single-use marker for the no-login one-time token-issue link. Set inside the mint transaction (with the request row locked) so the link can mint exactly one token and cannot be replayed after the token is revoked (security review fix, 2026-06-15). """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "288" down_revision = "287" branch_labels = None depends_on = None TABLE = "identity_consumer_requests" COL = "token_issued_at" def _column_exists(bind, table: str, column: str) -> bool: return bind.execute( sa.text( "SELECT 1 FROM information_schema.COLUMNS " "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :t " "AND COLUMN_NAME = :c" ), {"t": table, "c": column}, ).scalar() is not None def upgrade() -> None: bind = op.get_bind() if not _column_exists(bind, TABLE, COL): op.add_column( TABLE, sa.Column(COL, sa.DateTime(timezone=True), nullable=True), ) def downgrade() -> None: if _column_exists(op.get_bind(), TABLE, COL): op.drop_column(TABLE, COL)