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
5 changes: 4 additions & 1 deletion airflow-core/docs/migrations-ref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ Here's the list of all the Database Migrations that are executed via when you ru
+-------------------------+------------------+-------------------+--------------------------------------------------------------+
| Revision ID | Revises ID | Airflow Version | Description |
+=========================+==================+===================+==============================================================+
| ``b6a9c2e7d410`` (head) | ``f8c2a1d94e03`` | ``3.4.0`` | Add draining state to DagModel. |
| ``5182d0596ee2`` (head) | ``b6a9c2e7d410`` | ``3.4.0`` | Widen revoked_token.jti to store external-issuer token |
| | | | identifiers. |
+-------------------------+------------------+-------------------+--------------------------------------------------------------+
| ``b6a9c2e7d410`` | ``f8c2a1d94e03`` | ``3.4.0`` | Add draining state to DagModel. |
+-------------------------+------------------+-------------------+--------------------------------------------------------------+
| ``f8c2a1d94e03`` | ``8d3f1a6b2c47`` | ``3.4.0`` | Add team_name and bundle_names scope columns to job table. |
+-------------------------+------------------+-------------------+--------------------------------------------------------------+
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

"""
Widen revoked_token.jti to store external-issuer token identifiers.

Revision ID: 5182d0596ee2
Revises: b6a9c2e7d410
Create Date: 2026-09-22 00:00:00.000000

"""

from __future__ import annotations

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = "5182d0596ee2"
down_revision = "b6a9c2e7d410"
branch_labels = None
depends_on = None
airflow_version = "3.4.0"


def upgrade():
"""Widen ``revoked_token.jti`` from 32 to 255 characters."""
with op.batch_alter_table("revoked_token") as batch_op:
batch_op.alter_column(
"jti", existing_type=sa.String(32), type_=sa.String(255), existing_nullable=False
)


def downgrade():
"""Narrow ``revoked_token.jti`` from 255 back to 32 characters."""
with op.batch_alter_table("revoked_token") as batch_op:
batch_op.alter_column(
"jti", existing_type=sa.String(255), type_=sa.String(32), existing_nullable=False
)
2 changes: 1 addition & 1 deletion airflow-core/src/airflow/models/revoked_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class RevokedToken(Base):
# Track last cleanup time to avoid running cleanup on every request
_last_cleanup_time: ClassVar[float] = 0.0

jti: Mapped[str] = mapped_column(String(32), primary_key=True)
jti: Mapped[str] = mapped_column(String(255), primary_key=True)
exp: Mapped[datetime] = mapped_column(UtcDateTime, nullable=False, index=True)

@classmethod
Expand Down
2 changes: 1 addition & 1 deletion airflow-core/src/airflow/utils/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class MappedClassProtocol(Protocol):
"3.1.8": "509b94a1042d",
"3.2.0": "1d6611b6ab7c",
"3.3.0": "d2f4e1b3c5a7",
"3.4.0": "b6a9c2e7d410",
"3.4.0": "5182d0596ee2",
}

# Prefix used to identify tables holding data moved during migration.
Expand Down
11 changes: 11 additions & 0 deletions airflow-core/tests/unit/models/test_revoked_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,24 @@
# under the License.
from __future__ import annotations

import uuid
from datetime import datetime, timedelta, timezone
from unittest.mock import MagicMock, patch

from airflow.models.revoked_token import RevokedToken


class TestRevokedTokenModel:
def test_jti_column_fits_external_issuer_identifiers(self):
"""The ``jti`` column must hold identifiers longer than Airflow's own 32-char ``uuid4().hex``.

External identity providers (accepted via ``[api_auth] trusted_jwks_url``) mint ``jti``
claims such as 36-char RFC 4122 UUIDs; a 32-char column silently drops them on databases
that enforce length, so revocation never records them.
"""
assert RevokedToken.__table__.c.jti.type.length == 255
assert len(str(uuid.uuid4())) <= RevokedToken.__table__.c.jti.type.length

def test_revoke_inserts_row(self):
"""Test that revoke calls session.merge with a RevokedToken instance."""
mock_session = MagicMock()
Expand Down
1 change: 1 addition & 0 deletions docs/spelling_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,7 @@ Json
json
jsonl
JsonValue
jti
juli
Jupyter
jupyter
Expand Down