Resolve the Dag's team when authorizing a Dag found by lookup - #70893
Resolve the Dag's team when authorizing a Dag found by lookup#70893potiuk wants to merge 5 commits into
Conversation
SameerMesiah97
left a comment
There was a problem hiding this comment.
Looks good. The test could be improved though.
amoghrajesh
left a comment
There was a problem hiding this comment.
Maybe a later PR, but worth a guardrail like a DagDetails.for_dag(dag_id, *, session) constructor that always resolves the team
Two authorization checks build DagDetails(id=dag_id) without team_name: materialize_asset, where the Dag is resolved from the asset, and the XCom-specific check in wait_dag_run_until_finished. Every other call site passes the team, resolved with DagModel.get_team_name. A team-aware auth manager distinguishes a team-scoped Dag from a global one by that field, so omitting it asks about a differently-scoped resource than the one being acted on. In wait_dag_run_until_finished the route dependency already resolves the team for its RUN check, so the two checks in the same handler disagreed. Resolve the team at both sites, reusing the request session.
20840db to
87dcc78
Compare
|
Both review threads addressed, and the second call site now has its own regression test. On the Not in this PR though. It is milestoned for 3.3.1, and changing how Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting |
The existing wait-endpoint test uses a Dag with no team, where the resolved and unresolved forms are indistinguishable, so nothing caught the second check asking about a differently-scoped resource than the route dependency did.
87dcc78 to
9ebd025
Compare
|
Both threads addressed and resolved. The missing regression test for Drafted-by: Claude Code (Opus 5); reviewed by @potiuk before posting |
amoghrajesh
left a comment
There was a problem hiding this comment.
OK by me, but if someone like @vincbeck / @o-nikolas could review, that would be nice.
…t_dag_run.py Co-authored-by: Amogh Desai <amoghrajesh1999@gmail.com>
…t_assets.py Co-authored-by: Amogh Desai <amoghrajesh1999@gmail.com>
Two authorization checks build
DagDetails(id=dag_id)withoutteam_name:materialize_asset, where the Dag is resolved from the asset rather thannamed by the caller;
wait_dag_run_until_finished.Every other call site resolves the team with
DagModel.get_team_nameand passesit --
security.py:194,security.py:235,security.py:868,import_error.py:314,services/public/task_instances.py:405.Why it matters
A team-aware auth manager distinguishes a team-scoped Dag from a global one by
that field. The Keycloak manager, for instance, selects the resource it asks
about from it --
DAG:<team>when set, plainDAGwhen not -- so omitting itasks about a differently-scoped resource than the one being acted on.
wait_dag_run_until_finishedis the clearer illustration: its route dependencyalready resolves the team for the RUN check, so the two checks in the same
handler disagreed about the scope of the same Dag.
Approach
Resolve the team at both sites with
DagModel.get_team_name(dag_id, session=session),reusing the request session rather than opening a new one.
After this,
grep -rn "DagDetails(id=" airflow-core/srcreturns no call sitewithout
team_name.Test plan
test_authorizes_against_the_dags_team-- parametrized over a team-scopedDag and a global one; asserts the
DagDetailsreaching the auth managercarries the resolved team
global case passes either way -- so the test pins the resolution, not the
plumbing
test_assets.py-- 178 passedtest_dag_run.py-- 358 passed; the 2 failures inTestBulkClearDagRuns/TestBulkDagRuns(UNIQUE constraint failed: team.name) are pre-existing and reproduce identically on unmodifiedmainruff check/ruff formatcleanWas generative AI tooling used to co-author this PR?
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