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

   ## Why
   
   `next_run_assets` scopes the asset scheduling expression it serves to the 
caller: an `asset` leaf whose
   id the caller may not read keeps its place in the boolean tree, so the shape 
of the schedule stays
   honest, but its `uri`, `name` and `id` are blanked and `hidden` is set 
(#72864). The UI dependencies
   graph followed the same rule (#73008).
   
   Four endpoints still served `DagModel.asset_expression` verbatim:
   
   | Endpoint | Guard | Exposure |
   | --- | --- | --- |
   | `GET /api/v2/dags/{dag_id}/details` | Dag `GET` only | one Dag, reachable 
with `curl` — no UI needed |
   | `GET /ui/dags` | Dag `GET` only | every readable Dag in one response |
   | `GET /ui/partitioned_dag_runs` | asset `GET`, all-or-nothing | every Dag 
in the page |
   | `GET /ui/pending_partitioned_dag_run/{dag_id}` | asset + Dag `GET` | one 
Dag |
   
   Dag access and asset access are separate resources in the auth manager 
(`is_authorized_dag` vs
   `is_authorized_asset`, with `filter_authorized_assets` as the batch API), 
and Dag source code is a
   separate access entity again (`DagAccessEntity.CODE`), so a caller holding 
Dag `GET` is not entitled to
   the identity of the assets that Dag waits on. Asset names and uris commonly 
encode bucket, table or
   dataset names, which is why the rest of the asset API already scopes them.
   
   Reachability is the same as for the endpoints already fixed: the FAB auth 
manager returns every asset
   id and the simple auth manager grants all or nothing above its lowest role, 
so nothing is redacted
   there. Deployments whose auth manager authorizes assets individually are the 
ones affected.
   
   ## What
   
   - `routes/public/dags.py` — `get_dag_details` takes 
`ReadableAssetsFilterDep` and redacts the
     expression on the response. The redaction deliberately does not touch 
`dag_model`: that is a live
     ORM instance whose session commits when the request ends, so assigning the 
blanked leaves onto it
     would persist them.
   - `datamodels/common.py` — new `validate_asset_expression`. FastAPI does not 
validate the nested
     models of an already-built response, so an expression rewritten after 
`model_validate` has to be
     validated explicitly; without it the rewritten tree bypasses 
`MaybeAssetExpression` and a legacy
     stored shape would reach the client verbatim instead of as `null`.
   - `routes/ui/dags.py` — the Dag-list builder redacts each Dag's expression. 
The readable-asset id set
     is resolved once per request, not per Dag.
   - `routes/ui/partitioned_dag_runs.py` — both endpoints redact (the 
collection's per-Dag
     `asset_expressions` map and the detail's single `asset_expression`).
   - Tests — one per endpoint, each asserting a readable leaf survives intact 
and an unreadable one comes
     back blanked with `hidden`. All four fail against `main`. The Dag details 
test also asserts the
     stored expression is unchanged after the request, which is what pins the 
ORM caveat above. Two
     query-count assertions in the partitioned tests move up by the one 
`AssetModel.id` select the new
     dependency adds, and the comment enumerating them is updated.
   
   No schema change: `hidden` is already part of `AssetExpressionAssetInfo` in 
the public OpenAPI spec and
   in the generated TypeScript and airflow-ctl models (#72864 added it). What 
changes is the value served
   on these four endpoints, which is a behavioural change on a stable API — 
happy to add a newsfragment if
   reviewers want one.
   
   Deliberately out of scope: the `assets` array of the pending partitioned Dag 
run response carries the
   same asset names and uris, and the UI renders from it, so scoping that is a 
separate change. A comment
   in the test records it.
   
   Checks run locally: the full `airflow-core/tests/unit/api_fastapi` suite 
(5282 passed, 21 skipped on
   backend-gated tests), `providers/fab` auth manager tests (137 passed), 
`mypy-airflow-core`, and the
   pre-commit and manual prek stages — all clean. Not run locally: `breeze 
build-docs` and the broader
   `Always` / provider matrices that `breeze verify` lists for Docker.
   
   related: #72864, #73008
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes — Claude Code (Opus 5)
   
   Generated-by: Claude Code (Opus 5) following [the 
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
   
   ---
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
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