gabriel / musehub public
0022_auth_challenge_nonce_pk.py python
84 lines 2.9 KB
Raw
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