Skip to content

Validate connection port is within valid TCP/UDP range (1-65535)#68541

Draft
Aydeing wants to merge 3 commits into
apache:mainfrom
Aydeing:fix/validate-connection-port-range
Draft

Validate connection port is within valid TCP/UDP range (1-65535)#68541
Aydeing wants to merge 3 commits into
apache:mainfrom
Aydeing:fix/validate-connection-port-range

Conversation

@Aydeing

@Aydeing Aydeing commented Jun 14, 2026

Copy link
Copy Markdown

closes: #68382

Airflow stores a port field on connections but never validates that the value is a valid TCP/UDP port number. This adds port range validation (1–65535) on write paths only, so existing persisted connections with now-invalid port values continue to load via the ORM without errors — addressing the maintainer review concern about not breaking existing installations.

Where validation is enforced (create/update paths)

  • Core connection model (airflow.models.connection) — _validate_port() static method called in __init__ and from_json(). SQLAlchemy's @reconstructor does not call __init__, so DB loads are unaffected.
  • Task SDK connection definition (airflow.sdk.definitions.connection) — attrs @port.validator + from_json() validation.
  • Public REST API request schema (ConnectionBody) — Pydantic Field(ge=1, le=65535).
  • CLI (--conn-port) — changed type=strtype=int for argparse type checking; range validated by the model constructor.

What is intentionally NOT validated (read/response paths)

To avoid breaking existing installations that may have persisted invalid port values:

  • Execution API ConnectionResponse — unchanged.
  • Core API ConnectionResponse — unchanged.
  • Generated SDK datamodels (_generated.py) — unchanged.
  • JSON schema (schema.json) — unchanged.

Port 0 is rejected

Per maintainer feedback on the issue: since port is optional (None = no port), port 0 has no valid use case and is rejected. Range is 1–65535.

Tests added

File Tests
airflow-core/tests/unit/models/test_connection.py test_port_within_valid_range_is_accepted (1, 22, 5432, 65535) · test_port_none_is_accepted · test_port_out_of_range_is_rejected (0, -1, 65536, 99999) · test_from_json_rejects_out_of_range_port · test_orm_load_tolerates_legacy_invalid_port
task-sdk/tests/task_sdk/definitions/test_connection.py Same matrix for the SDK Connection (constructor + from_json)
airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_connections.py test_post_should_respond_422_for_out_of_range_port (0, -1, 65536, 99999)
airflow-core/tests/unit/cli/commands/test_connection_command.py test_cli_connections_add_rejects_out_of_range_port · test_cli_connections_add_rejects_non_integer_port

Test plan

  • Standalone validator harness exercising each enforcement layer: 30/30 checks pass — confirms None/1/22/5432/65535 accepted, 0/-1/65536/99999 rejected, response schemas tolerate legacy invalid values, from_json accepts "5432" and rejects out-of-range strings.
  • All seven modified source files parse with ast.parse.
  • schema.json parses with json.loads.
  • All four modified test files parse with ast.parse.
  • ORM-load path verified: Connection.__new__(Connection); conn.port = 99999; conn.on_db_load() does not raise (legacy data still loads).
  • Full breeze testing core-tests run — requires breeze + Docker, not run locally; will run in CI on this PR.
  • prek run --from-ref main static checks — requires prek hooks installed, will run in CI.

Notes for reviewers

  • ARG_CONN_PORT type changed from str to int: argparse now rejects non-integer strings at parse time with a clearer error than the downstream ValueError from Connection(...). The model still validates the range.
  • A newsfragment (e.g. <pr_number>.bugfix.rst) will be added in a follow-up commit once this PR number is assigned, per the PR template guidance.

Was generative AI tooling used to co-author this PR?
  • Yes (Claude Code / Anthropic Claude Sonnet 4.6)

Generated-by: Claude Sonnet 4.6 following the guidelines

Aydeing added 2 commits June 14, 2026 22:37
Connections previously accepted any integer for the ``port`` field
without bounds checking. Add range validation (1-65535) on write paths:

- ``airflow.models.connection.Connection`` constructor and ``from_json``
  via a new ``_validate_port`` static method. SQLAlchemy's
  ``@reconstructor`` does not call ``__init__``, so DB loads of legacy
  rows with out-of-range port values are unaffected.
- ``airflow.sdk.definitions.connection.Connection`` via an attrs field
  validator and explicit range check in ``from_json``.
- ``ConnectionBody`` REST API request schema via ``Field(ge=1, le=65535)``.
- ``--conn-port`` CLI argument now uses ``type=int`` so argparse
  rejects non-integer input early; range is enforced by the model.

Port 0 is rejected: ``port`` is optional, so ``None`` is the no-port
sentinel and 0 has no valid use case.

Response models (execution API ``ConnectionResponse``, generated SDK
datamodels, ``schema.json``) are intentionally left unchanged so
existing installations with persisted invalid port values continue to
load through the read paths without errors.

Closes apache#68382
Cover all four enforcement points changed by the port validation:

- ``airflow.models.connection.Connection``: accepted values (1, 22,
  5432, 65535, ``None``), rejected values (0, -1, 65536, 99999), the
  same matrix for ``from_json``, and a test that asserts a legacy DB
  row with an out-of-range port still loads via the ``@reconstructor``
  ``on_db_load`` path without raising.
- ``airflow.sdk.definitions.connection.Connection``: same accept/reject
  matrix for the constructor and ``from_json``.
- REST API ``POST /connections``: ``test_post_should_respond_422_for_out_of_range_port``
  for 0, -1, 65536, 99999.
- ``airflow connections add`` CLI: rejects out-of-range port values
  and rejects non-integer ``--conn-port`` input at argparse time.
@boring-cyborg boring-cyborg Bot added area:API Airflow's REST/HTTP API area:CLI area:task-sdk labels Jun 14, 2026
@boring-cyborg

boring-cyborg Bot commented Jun 14, 2026

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contributors' Guide
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our prek-hooks will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example Dag that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
  • Always keep your Pull Requests rebased, otherwise your build might fail due to changes not related to your commits.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Connection port field does not validate that the value is a valid port number

1 participant