0022_auth_challenge_nonce_pk.py
python
sha256:ab9eda7b6479e1c35cdba9a54f62bacd2825de8faacec3ba67a9a8ef45914b7d
fix: migration and wire protocol alignment
Sonnet 4.6
minor
⚠ breaking
20 days ago
| 1 | """Promote nonce_hex to PK on musehub_auth_challenges; drop challenge_id. |
| 2 | |
| 3 | The nonce_hex column IS the natural identity of a challenge row — it was |
| 4 | already UNIQUE and was the lookup key in all service code. challenge_id was a |
| 5 | redundant UUID surrogate that provided no additional information. |
| 6 | |
| 7 | Revision ID: 0022 |
| 8 | Revises: 0021 |
| 9 | """ |
| 10 | from __future__ import annotations |
| 11 | |
| 12 | from alembic import op |
| 13 | import sqlalchemy as sa |
| 14 | |
| 15 | revision = "0022" |
| 16 | down_revision = "0021" |
| 17 | branch_labels = None |
| 18 | depends_on = None |
| 19 | |
| 20 | |
| 21 | def upgrade() -> None: |
| 22 | from sqlalchemy import inspect as sa_inspect |
| 23 | conn = op.get_bind() |
| 24 | insp = sa_inspect(conn) |
| 25 | |
| 26 | if not insp.has_table("musehub_auth_challenges"): |
| 27 | # Table was never created on this instance — create it with the final |
| 28 | # schema (nonce_hex as PK, no challenge_id surrogate). |
| 29 | op.create_table( |
| 30 | "musehub_auth_challenges", |
| 31 | sa.Column("nonce_hex", sa.String(64), primary_key=True), |
| 32 | sa.Column("public_key", sa.Text, nullable=False), |
| 33 | sa.Column("expires_at", sa.DateTime(timezone=True), nullable=False), |
| 34 | ) |
| 35 | op.create_index( |
| 36 | "ix_musehub_auth_challenges_expires_at", |
| 37 | "musehub_auth_challenges", |
| 38 | ["expires_at"], |
| 39 | ) |
| 40 | return |
| 41 | |
| 42 | # Drop the old UUID primary key |
| 43 | op.drop_constraint("musehub_auth_challenges_pkey", "musehub_auth_challenges", type_="primary") |
| 44 | op.drop_column("musehub_auth_challenges", "challenge_id") |
| 45 | |
| 46 | # Drop the now-redundant unique constraint on nonce_hex (PK implies uniqueness) |
| 47 | op.drop_constraint( |
| 48 | "uq_musehub_auth_challenges_nonce_hex", "musehub_auth_challenges", type_="unique" |
| 49 | ) |
| 50 | |
| 51 | # Make nonce_hex the primary key |
| 52 | op.create_primary_key("musehub_auth_challenges_pkey", "musehub_auth_challenges", ["nonce_hex"]) |
| 53 | |
| 54 | |
| 55 | def downgrade() -> None: |
| 56 | from sqlalchemy import inspect as sa_inspect |
| 57 | conn = op.get_bind() |
| 58 | insp = sa_inspect(conn) |
| 59 | |
| 60 | if not insp.has_table("musehub_auth_challenges"): |
| 61 | return # nothing to undo |
| 62 | |
| 63 | cols = {c["name"] for c in insp.get_columns("musehub_auth_challenges")} |
| 64 | if "challenge_id" not in cols: |
| 65 | # Table was created fresh by upgrade (the if-not-exists branch) — drop it entirely. |
| 66 | op.drop_table("musehub_auth_challenges") |
| 67 | return |
| 68 | |
| 69 | # Restore the surrogate PK (new UUIDs — existing rows get new random IDs) |
| 70 | op.drop_constraint("musehub_auth_challenges_pkey", "musehub_auth_challenges", type_="primary") |
| 71 | |
| 72 | op.add_column( |
| 73 | "musehub_auth_challenges", |
| 74 | sa.Column( |
| 75 | "challenge_id", |
| 76 | sa.String(36), |
| 77 | nullable=False, |
| 78 | server_default=sa.text("gen_random_uuid()::text"), |
| 79 | ), |
| 80 | ) |
| 81 | op.create_primary_key("musehub_auth_challenges_pkey", "musehub_auth_challenges", ["challenge_id"]) |
| 82 | op.create_unique_constraint( |
| 83 | "uq_musehub_auth_challenges_nonce_hex", "musehub_auth_challenges", ["nonce_hex"] |
| 84 | ) |
File History
1 commit
sha256:ab9eda7b6479e1c35cdba9a54f62bacd2825de8faacec3ba67a9a8ef45914b7d
fix: migration and wire protocol alignment
Sonnet 4.6
minor
⚠
20 days ago