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]