henry3260 opened a new pull request, #75213:
URL: https://github.com/apache/airflow/pull/75213
## Why
The pending partitioned Dag run detail response (`GET
/ui/partitioned_dag_runs/{dag_id}/pending`)
carries two asset-bearing fields. `asset_expression` is scoped to the assets
the caller may read;
the sibling `assets` array was not. The query that builds it
(`routes/ui/partitioned_dag_runs.py`) filters on nothing but
`DagScheduleAssetReference.dag_id`,
so every asset the Dag schedules on comes back with its full name and uri.
That makes one payload contradict itself — it can blank an asset inside the
boolean tree while
spelling its name and uri out one key over:
```json
{
"assets": [{"asset_id": 7, "asset_name": "sales_daily", "asset_uri":
"s3://bucket/sales"}],
"asset_expression": {"asset": {"group": "asset", "hidden": true, "id":
null, "name": null, "uri": null}}
}
```
The route's own asset dependency does not close the gap:
`requires_access_asset(method="GET")`
reads `asset_id` from the path (`core_api/security.py`), and this route has
none, so it asks the
coarse "may you read assets at all" question rather than "may you read asset
#7".
Reachability is the same as for the expression redaction: with FAB or
SimpleAuthManager every
asset id is authorized, so nothing changes in a stock deployment. The gap is
reachable by a
third-party auth manager that implements per-asset
`filter_authorized_assets`.
## What
Backend — `airflow-core/src/airflow/api_fastapi/core_api/`:
- `datamodels/ui/partitioned_dag_runs.py`:
`PartitionedDagRunAssetResponse.asset_id`, `.asset_name`
and `.asset_uri` become nullable and a `hidden` flag is added, mirroring
the shape
`redact_asset_expression` already produces for the sibling field.
- `routes/ui/partitioned_dag_runs.py`: blanks those three fields and sets
`hidden` for an asset
outside `ReadableAssetsFilterDep`. The redaction lands on the response
only — the row is still
read in full, because the rollup mapper is keyed by the asset's real name
and uri and the
received-key lookup by its real id. `readable_asset_ids` is hoisted so the
`assets` loop and the
`asset_expression` call share it; no extra query.
Deliberately kept: `received_count`, `required_count`, `received_keys` and
`required_keys` of a
blanked asset. They describe the Dag's own schedule, which a caller who
reached this endpoint can
already read, and dropping them would leave a stuck run with no explanation
at all. The run's
`total_required` / `total_received` therefore stay accurate.
Frontend — `airflow-core/src/airflow/ui/`:
- `src/components/AssetProgressCell.tsx` renders a lock icon and a muted
"Hidden asset" label in
place of the asset link for a hidden asset, and drops hidden assets from
the `events` list it
feeds `AssetExpression` (a blanked asset has no id to match an expression
leaf on, and the leaf
it would have matched is redacted to `id: null` anyway).
- `public/i18n/locales/en/common.json`: adds `expression.hiddenAsset`.
Generated: `openapi/_private_ui.yaml` and the two
`ui/openapi-gen/requests/*.gen.ts` files were
regenerated. This endpoint is UI-only — `v2-rest-api-generated.yaml`
regenerates byte-identical and
no airflow-ctl model references the response — so no public REST API surface
changes.
Tests:
- `tests/unit/api_fastapi/core_api/routes/ui/test_partitioned_dag_runs.py`:
the existing
`TestGetPendingPartitionedDagRun::test_hides_assets_the_caller_may_not_read`
now also asserts the
`assets` array is blanked and that `total_required` still counts the
hidden asset. Its comment
disclaiming the `assets` array is removed. No query-count change.
- `src/components/AssetProgressCell.test.tsx`: a new test opens the popover
and asserts the hidden
asset renders a label while the readable one stays a link, with exactly
one link in the tree.
Verified locally: the module's 51 backend tests pass; the full UI suite
passes (1981 tests);
`prek --stage pre-commit` and `--stage manual` pass. Both new assertions
fail when the source
change is reverted.
Notes for reviewers:
- This builds on #75180, which added `ReadableAssetsFilterDep` to this route
for the sibling
`asset_expression` field, and shares the `expression.hiddenAsset` i18n key
with #75178. Please
review those first; this branch rebases cleanly onto `main` once they land.
- No newsfragment: `/ui/` endpoints are served to the bundled UI rather than
to API clients, and
the public v2 spec is unchanged. Happy to add one if you read it
differently.
---
##### 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]