Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions alembic/versions/0029_widen_api_key_prefix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Widen api_keys.key_prefix from 12 to 20 characters.

M13 (live/test key prefixes) changed the stored prefix to
prefix_len("omni_sk_live_"/"omni_sk_test_") + 4 display chars = 17
characters, but never widened this column from its pre-M13 size of 12
(sized for the plain "omni_sk_XXXX" scheme). Every real key creation
against a real MySQL database has failed with "Data too long for
column 'key_prefix'" since M13 shipped -- SQLite enforces no VARCHAR
length limit at all, so the existing (SQLite-backed) test suite never
caught this.

Revision ID: 0029_widen_api_key_prefix
Revises: 0028_auth_audit_integrity
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa

revision: str = "0029_widen_api_key_prefix"
down_revision: Union[str, None] = "0028_auth_audit_integrity"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
with op.batch_alter_table("api_keys") as batch_op:
batch_op.alter_column(
"key_prefix", existing_type=sa.String(length=12), type_=sa.String(length=20), existing_nullable=True,
)


def downgrade() -> None:
with op.batch_alter_table("api_keys") as batch_op:
batch_op.alter_column(
"key_prefix", existing_type=sa.String(length=20), type_=sa.String(length=12), existing_nullable=True,
)
9 changes: 8 additions & 1 deletion app/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,14 @@ class ApiKey(Base):
organization_id = Column(Integer, ForeignKey("organizations.id"), nullable=False)
created_by_user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
name = Column(String(255), nullable=True)
key_prefix = Column(String(12), nullable=True)
# M13 (live/test key prefixes) widened the stored prefix to
# len("omni_sk_live_"/"omni_sk_test_") + 4 display chars = 17, but
# this column stayed at its pre-M13 width (12, sized for the plain
# "omni_sk_XXXX" scheme) -- every real key creation against a real
# MySQL database has 500'd since M13 shipped (SQLite enforces no
# VARCHAR length at all, so no test caught it). See
# alembic/versions/0029_widen_api_key_prefix.py.
key_prefix = Column(String(20), nullable=True)
key_hash = Column(String(64), unique=True, nullable=True)
scopes = Column(JSON, nullable=True)
status = Column(String(20), default="active") # active | revoked
Expand Down
4 changes: 2 additions & 2 deletions tests/test_migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ def test_sqlite_stamp_then_upgrade_matches_real_deployment_procedure(sqlite_db_u

with engine.connect() as conn:
recorded = conn.execute(text("SELECT version_num FROM alembic_version")).scalar()
assert recorded == "0028_auth_audit_integrity"
assert recorded == "0029_widen_api_key_prefix"


def test_sqlite_0019_is_purely_additive_existing_session_rows_survive(sqlite_db_url):
Expand Down Expand Up @@ -1120,7 +1120,7 @@ def test_mysql_pre_existing_role_rows_survive_0016_as_platform_wide(mysql_db_url

with engine.connect() as conn:
recorded = conn.execute(text("SELECT version_num FROM alembic_version")).scalar()
assert recorded == "0028_auth_audit_integrity"
assert recorded == "0029_widen_api_key_prefix"


def test_mysql_0020_pre_existing_team_membership_row_backfills_member_role(mysql_db_url):
Expand Down
Loading