Skip to content

Require starlette>=1.0.1 for Host header parsing fix#67326

Open
potiuk wants to merge 3 commits into
apache:mainfrom
potiuk:bump-starlette-1.0.1-host-header-fix
Open

Require starlette>=1.0.1 for Host header parsing fix#67326
potiuk wants to merge 3 commits into
apache:mainfrom
potiuk:bump-starlette-1.0.1-host-header-fix

Conversation

@potiuk
Copy link
Copy Markdown
Member

@potiuk potiuk commented May 22, 2026

Summary

  • Bumps the starlette floor in airflow-core/pyproject.toml from
    >=0.45.0 to >=1.0.1 to pick up the Host-header parsing fix in
    Kludex/starlette#3279.
  • Adds a matching [tool.uv.exclude-newer-package] override
    (starlette = "6 hours") so the bump can resolve before 1.0.1
    ages past the project's global 4-day cooldown.
  • Teaches scripts/ci/prek/upgrade_important_versions.py to honour
    manual cooldown overrides when checking PyPI and to retire those
    overrides automatically once the global window catches up, so each
    workaround line — and its # REMOVE BY … marker — clean themselves
    out without anyone watching the calendar.

Why this matters for Airflow

The upstream PR closes a case where request.url.path could diverge
from the ASGI scope["path"] when the Host header contains
characters that are invalid per RFC 9110 §7.2 (/, ?, #, @,
\, space). Airflow has authorisation paths that compare against
request.url.path while the downstream app serves the file at
scope["path"]:

  • airflow-core/src/airflow/utils/serve_logs/log_server.py
    (JWTAuthStaticFiles)
  • providers/edge3/src/airflow/providers/edge3/worker_api/auth.py
    (jwt_token_authorization_rest)

Bumping the floor closes the underlying divergence. Defence-in-depth
follow-ups (comparing scope["path"] directly instead of
request.url.path) can come in a separate PR.

Test plan

  • uv run --project scripts pytest scripts/tests/ci/prek/test_upgrade_important_versions.py — 19 passed (5 existing + 14 new covering _parse_duration_hours, _parse_manual_overrides, _remove_override_entry, and the per-package cooldown branch).
  • prek run --files … on every touched file — all hooks pass (ruff, ruff-format, mypy-scripts, license headers, codespell, uv.lock sync, …).
  • uv lock resolves starlette==1.0.1 once the per-package override is in place; verified by diffing uv.lock.

Was generative AI tooling used to co-author this PR?
  • Yes — Claude Code (Opus 4.7)

Generated-by: Claude Code (Opus 4.7) following the guidelines


Drafted-by: Claude Code (Opus 4.7); reviewed by @potiuk before posting

potiuk added 2 commits May 22, 2026 13:23
Starlette 1.0.1 carries a Host-header parsing fix
(Kludex/starlette#3279): when the `Host`
header contains characters that are invalid per RFC 9110 §7.2
(`/`, `?`, `#`, `@`, `\`, spaces, ...), the URL string Starlette
builds before calling `urlsplit` would push parts of `scope["path"]`
into the netloc / query / fragment, leaving `request.url.path`
disagreeing with the ASGI `scope["path"]` that downstream apps and
`StaticFiles` actually serve.

Airflow has two places that authorise off `request.url.path` and
dispatch off `scope["path"]`:

- `airflow-core/src/airflow/utils/serve_logs/log_server.py` —
  `JWTAuthStaticFiles.validate_jwt_token` compares
  `request.url.path` against the JWT's `filename` claim; the
  `StaticFiles` superclass then serves the file at `scope["path"]`.
  A malformed `Host` header makes those two disagree, letting a
  holder of any valid log-read token read any other task log on
  the same worker.

- `providers/edge3/src/airflow/providers/edge3/worker_api/auth.py` —
  `jwt_token_authorization_rest` derives the called "method" from
  `request.url.path` while FastAPI routes by `scope["path"]`. Same
  shape of bypass on the Edge3 worker control plane.

Bumping the floor to 1.0.1 closes both. A matching
`[tool.uv.exclude-newer-package]` override is added so the security
floor can be resolved before 1.0.1 ages past the project's global
4-day cooldown — the next commit teaches
`upgrade_important_versions.py` to retire that override automatically
once the cooldown catches up.
… script

`upgrade_important_versions.py` enforced its own 4-day PyPI cooldown
(`COOLDOWN_DAYS = 4`), which mirrored the root pyproject.toml's global
`exclude-newer = "4 days"`. When a per-package override was added under
`[tool.uv.exclude-newer-package]` (e.g. `uv = "12 hours"`) to let a
freshly-published release through the global window, the script kept
applying its broader cooldown and would pick a stale version that
disagreed with what `uv lock` would resolve against pyproject.toml.

This change makes the script:

1. Parse manual override blocks (the lines after the
   "# End of automatically generated …" sentinels under
   `[tool.uv.exclude-newer-package]` and
   `[tool.uv.pip.exclude-newer-package]`) and use any duration-shaped
   override as the per-package cooldown when checking PyPI.
2. Sweep up overrides whose target package is already older than the
   global 4-day window — the entry, plus its `# REMOVE BY …` markers,
   are removed from pyproject.toml so the workaround retires itself
   without anyone having to remember the calendar date in the comment.

The "Manual overrides" header and broader context comments are left
in place on purpose — the diff makes them obviously orphaned for a
reviewer to prune in the same PR, but the script doesn't try to guess
which surrounding lines belonged to which entry.
@boring-cyborg boring-cyborg Bot added area:dev-tools backport-to-v3-2-test Mark PR with this label to backport to v3-2-test branch labels May 22, 2026
@potiuk potiuk added this to the Airflow 3.2.2 milestone May 22, 2026
@potiuk potiuk requested a review from vatsrahul1001 May 22, 2026 13:13
@github-actions
Copy link
Copy Markdown
Contributor

uv.lock on main just moved via #67383 ("Cleanup older/outddated uv cooldown exception"), commit 62845dd and this PR currently conflicts.

Quickest fix:

git fetch upstream main && git rebase upstream/main
rm uv.lock && uv lock
git add uv.lock && git rebase --continue
git push --force-with-lease

Automated nudge — ignore if you're not ready to rebase. This comment is updated in place on future uv.lock bumps.

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

Labels

area:dev-tools backport-to-v3-2-test Mark PR with this label to backport to v3-2-test branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants