Skip to content

Enforce visibility filter on dag_runs/latest endpoint#1646

Open
elijahbenizzy wants to merge 1 commit into
mainfrom
improve/dag-runs-visibility-filter
Open

Enforce visibility filter on dag_runs/latest endpoint#1646
elijahbenizzy wants to merge 1 commit into
mainfrom
improve/dag-runs-visibility-filter

Conversation

@elijahbenizzy

Copy link
Copy Markdown
Contributor

Summary

Tightens the scoping of the GET /api/v1/dag_runs/latest/ endpoint in the tracking UI backend to honor the visibility contract that the rest of the get endpoints in this module already follow (documented at the top of trackingserver_base/permissions/permissions.py: "Inside any 'get' endpoints, we only access the items to which the user has visibility").

Previously, when neither project_id nor dag_template_id was supplied, the permission callback short-circuited to "allow" and the endpoint body produced an unfiltered query — returning runs from across the instance instead of the caller's accessible scope. This change makes the no-args case behave the same as every other get endpoint in the module.

Changes

  • trackingserver_base/permissions/permissions.py
    • Adds a visible_project_ids_for_user helper that returns the set of project IDs the caller can see (mirrors _get_visible_projects but returns IDs only, so it composes with __in= filters).
    • Updates the user_can_get_latest_dag_runs permission callback so it always evaluates visibility, including the no-args case.
    • Docstring updated to point to the invariant.
  • trackingserver_run_tracking/api.py
    • When neither project_id nor dag_template_id is supplied, the endpoint now injects a dag_template__project_id__in=<visible_ids> filter.
    • Behavior when an explicit project_id or dag_template_id is supplied is unchanged.

Tests

  • Unit test for the new visible_project_ids_for_user helper (tests/test_db_methods/test_permissions.py).
  • Three HTTP regression tests in tests/test_lifecycle/test_run_tracking.py:
    • Cross-user no-arg request does not return runs from projects the caller cannot see.
    • Cross-user explicit project_id request from a non-member returns 404 (matches existing behavior elsewhere).
    • Legitimate own-project request returns 200.
  • Verified the no-arg regression test fails when the endpoint scoping is reverted, so the test actually catches the case.

Adjacent

trackingserver_template/api.py:230 (get_dag_template_catalog) accepts project_id: int = None and has the same project_id is None short-circuit shape in its permission callback (user_can_get_dag_templates). Worth a follow-up to apply the same pattern there. Out of scope for this PR.

When neither project_id nor dag_template_id is supplied, scope the result
to projects the caller is a member of (directly or via a team, including
the "Public" team), matching the visibility contract already followed by
the other "get" endpoints in trackingserver_base/permissions. Adds a
shared visible_project_ids_for_user helper and regression tests covering
the no-arg case, the cross-project rejection, and the legitimate
project_id/dag_template_id paths.
@elijahbenizzy elijahbenizzy requested a review from skrawcz June 21, 2026 03:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant