potiuk opened a new pull request, #70889:
URL: https://github.com/apache/airflow/pull/70889

   The backfill routes declare `backfill_id: NonNegativeInt`, but
   `requires_access_backfill` parsed the raw path value with `int()` and 
swallowed
   the failure. Those two parsers do not agree.
   
   ### The divergence
   
   | supplied `backfill_id` | `NonNegativeInt` (the handler) | `int()` (the 
dependency) |
   |---|---|---|
   | `"42"` | 42 | 42 |
   | `"42.0"` | **42** | ValueError |
   | `"42.00"` | **42** | ValueError |
   | `"42."`, `"42e0"`, `"42.5"`, `"0x2a"` | rejected | ValueError |
   
   pydantic's lax mode accepts the two decimal spellings and coerces them to an
   int; `int()` rejects them.
   
   FastAPI resolves route dependencies *before* the endpoint's own parameter
   validation, so for those spellings the dependency's parse failed, it left the
   Dag unresolved, and the request went on to be served by the handler against
   backfill 42. The dependency and the handler disagreed about which backfill --
   and therefore which Dag -- the request concerned.
   
   ### Approach
   
   Parse with the same `TypeAdapter(NonNegativeInt)` the routes declare, so the
   two cannot diverge by construction. The adapter is module-level and named, so
   the coupling to the route signature is explicit rather than re-derived.
   
   This deliberately does **not** introduce a stricter parser. An earlier 
revision
   used `int()` with an explicit 400, which changed the public API contract: a
   malformed path value such as `/backfills/invalid_id` previously produced
   FastAPI's structured **422** (`loc: ["path", "backfill_id"]`), and a 400 from
   the dependency preempted it. Five existing route tests caught that. Matching
   the declared type keeps every existing status code and body shape intact --
   values both parsers reject still yield the handler's 422, and an unknown
   backfill still yields each route's own 404 wording.
   
   ### Test plan
   
   - [x] 
`test_requires_access_backfill_authorizes_the_backfill_the_handler_will_act_on`
         -- parametrized over `42`, `42.0`, `42.00`; asserts the Dag comes from 
the
         resolved backfill and not from a value supplied on the request
   - [x] Verified against unmodified code: `42.0` and `42.00` **fail**, `42` 
passes --
         so the test pins the divergence and not the plumbing
   - [x] `airflow-core/tests/unit/api_fastapi/core_api/test_security.py` -- 111 
passed
   - [x] 
`airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_backfills.py`
         -- 63 passed, including the four `test_invalid_id` 422 cases and 
`test_no_exist`
   - [x] `ruff check` / `ruff format` clean
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — Claude Opus 5 (1M context)
   
   Generated-by: Claude Opus 5 (1M context) following the guidelines at
   
https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to