90 lines
4.0 KiB
Python
90 lines
4.0 KiB
Python
# #region Alembic.Migration.SessionActivityLogicalSessions [C:2] [TYPE Migration] [SEMANTICS alembic,migration,session,activity,sid]
|
|
# @BRIEF Convert session_activity from per-JWT tracking to logical-session (sid) tracking.
|
|
# @PRE Previous migration (o1p2q3r4s5t6) has been applied.
|
|
# @POST session_activity rows are keyed by sid; is_revoked column present for whole-session revocation.
|
|
# @SIDE_EFFECT DDL execution — renames jti -> sid, adds is_revoked column.
|
|
# @RELATION DEPENDS_ON -> [Models.Auth.SessionActivity]
|
|
# @RATIONALE Replacement JWTs share one logical session (sid). Existing rows carry their
|
|
# historical jti forward as sid; they are non-renewable but still enforceable.
|
|
# @REJECTED Dropping and recreating the table was rejected — loses existing audit rows and
|
|
# would break live deployments that already enforce idle timeouts.
|
|
"""convert session_activity to logical session rows
|
|
|
|
Revision ID: a1b2c3d4e5f7
|
|
Revises: o1p2q3r4s5t6
|
|
Create Date: 2026-08-06 12:00:00.000000
|
|
|
|
"""
|
|
from collections.abc import Sequence
|
|
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
from sqlalchemy import inspect
|
|
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision: str = "a1b2c3d4e5f7"
|
|
down_revision: str | Sequence[str] | None = "o1p2q3r4s5t6"
|
|
branch_labels: str | Sequence[str] | None = None
|
|
depends_on: str | Sequence[str] | None = None
|
|
|
|
|
|
# #region Migration.SessionActivityLogicalSessions.TableExists [C:1] [TYPE Function] [SEMANTICS alembic,helper,table]
|
|
# @BRIEF Check if a table already exists in the database.
|
|
def _table_exists(table_name: str) -> bool:
|
|
conn = op.get_bind()
|
|
inspector = inspect(conn)
|
|
return table_name in inspector.get_table_names()
|
|
# #endregion Migration.SessionActivityLogicalSessions.TableExists
|
|
|
|
|
|
# #region Migration.SessionActivityLogicalSessions.ColumnNames [C:1] [TYPE Function] [SEMANTICS alembic,helper,column]
|
|
# @BRIEF Return the set of column names of a table.
|
|
def _column_names(table_name: str) -> set[str]:
|
|
inspector = inspect(op.get_bind())
|
|
return {c["name"] for c in inspector.get_columns(table_name)}
|
|
# #endregion Migration.SessionActivityLogicalSessions.ColumnNames
|
|
|
|
|
|
# #region Migration.SessionActivityLogicalSessions.Upgrade [C:2] [TYPE Function] [SEMANTICS alembic,upgrade]
|
|
# @BRIEF Rename jti -> sid (when needed) and add is_revoked column.
|
|
# @PRE session_activity table exists.
|
|
# @POST session_activity keyed by sid with is_revoked defaulting to False.
|
|
# @SIDE_EFFECT Executes ALTER TABLE DDL.
|
|
def upgrade() -> None:
|
|
"""Convert session_activity to logical-session keying and add revocation state."""
|
|
if not _table_exists("session_activity"):
|
|
return
|
|
cols = _column_names("session_activity")
|
|
with op.batch_alter_table("session_activity") as batch_op:
|
|
if "jti" in cols and "sid" not in cols:
|
|
batch_op.alter_column("jti", new_column_name="sid")
|
|
if "is_revoked" not in cols:
|
|
batch_op.add_column(
|
|
sa.Column(
|
|
"is_revoked",
|
|
sa.Boolean(),
|
|
nullable=False,
|
|
server_default=sa.false(),
|
|
)
|
|
)
|
|
# #endregion Migration.SessionActivityLogicalSessions.Upgrade
|
|
|
|
|
|
# #region Migration.SessionActivityLogicalSessions.Downgrade [C:1] [TYPE Function] [SEMANTICS alembic,downgrade]
|
|
# @BRIEF Revert sid -> jti and drop is_revoked.
|
|
# @POST session_activity restored to per-JWT keying without revocation state.
|
|
# @SIDE_EFFECT Executes ALTER TABLE DDL.
|
|
def downgrade() -> None:
|
|
"""Revert logical-session keying back to jti and drop is_revoked."""
|
|
if not _table_exists("session_activity"):
|
|
return
|
|
cols = _column_names("session_activity")
|
|
with op.batch_alter_table("session_activity") as batch_op:
|
|
if "sid" in cols and "jti" not in cols:
|
|
batch_op.alter_column("sid", new_column_name="jti")
|
|
if "is_revoked" in cols:
|
|
batch_op.drop_column("is_revoked")
|
|
# #endregion Migration.SessionActivityLogicalSessions.Downgrade
|
|
# #endregion Alembic.Migration.SessionActivityLogicalSessions
|