You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by pi...@apache.org on 2025/03/17 13:36:17 UTC
(airflow) branch main updated: AIP-84 - add auth to dag report (#47842)
This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 62cc9aef19e AIP-84 - add auth to dag report (#47842)
62cc9aef19e is described below
commit 62cc9aef19e2d95021498ef0d29c2726150809b3
Author: Kalyan R <ka...@live.com>
AuthorDate: Mon Mar 17 19:06:10 2025 +0530
AIP-84 - add auth to dag report (#47842)
* add auth to dag report
* sync dags to DB
* refactor
* refactor(api_fastapi): rewrite dag_report filtering
---------
Co-authored-by: Wei Lee <we...@gmail.com>
---
.../api_fastapi/core_api/openapi/v1-generated.yaml | 2 ++
.../core_api/routes/public/dag_report.py | 25 +++++++++++++++++++---
.../core_api/routes/public/test_dag_report.py | 11 +++++++++-
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/airflow/api_fastapi/core_api/openapi/v1-generated.yaml b/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
index 3611dcdee3d..ec8ac63515a 100644
--- a/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
+++ b/airflow/api_fastapi/core_api/openapi/v1-generated.yaml
@@ -2860,6 +2860,8 @@ paths:
summary: Get Dag Reports
description: Get DAG report.
operationId: get_dag_reports
+ security:
+ - OAuth2PasswordBearer: []
parameters:
- name: subdir
in: query
diff --git a/airflow/api_fastapi/core_api/routes/public/dag_report.py b/airflow/api_fastapi/core_api/routes/public/dag_report.py
index 095be7135b2..7c7163ac35b 100644
--- a/airflow/api_fastapi/core_api/routes/public/dag_report.py
+++ b/airflow/api_fastapi/core_api/routes/public/dag_report.py
@@ -17,10 +17,11 @@
from __future__ import annotations
+import ast
import os
from typing import cast
-from fastapi import HTTPException, status
+from fastapi import Depends, HTTPException, status
from airflow import settings
from airflow.api_fastapi.common.router import AirflowRouter
@@ -29,6 +30,10 @@ from airflow.api_fastapi.core_api.datamodels.dag_report import (
DagReportResponse,
)
from airflow.api_fastapi.core_api.openapi.exceptions import create_openapi_http_exception_doc
+from airflow.api_fastapi.core_api.security import (
+ ReadableDagsFilterDep,
+ requires_access_dag,
+)
from airflow.models.dagbag import DagBag
dag_report_router = AirflowRouter(tags=["DagReport"], prefix="/dagReports")
@@ -41,16 +46,30 @@ dag_report_router = AirflowRouter(tags=["DagReport"], prefix="/dagReports")
status.HTTP_400_BAD_REQUEST,
]
),
+ dependencies=[Depends(requires_access_dag(method="GET"))],
)
def get_dag_reports(
subdir: str,
+ readable_dags_filter: ReadableDagsFilterDep,
):
"""Get DAG report."""
fullpath = os.path.normpath(subdir)
if not fullpath.startswith(settings.DAGS_FOLDER):
raise HTTPException(status.HTTP_400_BAD_REQUEST, "subdir should be subpath of DAGS_FOLDER settings")
+
dagbag = DagBag(fullpath)
+
+ readable_dag_ids: set[str] | None = readable_dags_filter.value
+ if readable_dag_ids:
+ filtered_dagbag_stats = [
+ file_load_stat
+ for file_load_stat in dagbag.dagbag_stats
+ if len(set(ast.literal_eval(file_load_stat.dags)) - readable_dag_ids) == 0
+ ]
+ else:
+ filtered_dagbag_stats = []
+
return DagReportCollectionResponse(
- dag_reports=cast(list[DagReportResponse], dagbag.dagbag_stats),
- total_entries=len(dagbag.dagbag_stats),
+ dag_reports=cast(list[DagReportResponse], filtered_dagbag_stats),
+ total_entries=len(filtered_dagbag_stats),
)
diff --git a/tests/api_fastapi/core_api/routes/public/test_dag_report.py b/tests/api_fastapi/core_api/routes/public/test_dag_report.py
index c5eae24703d..1ba0d1c34bd 100644
--- a/tests/api_fastapi/core_api/routes/public/test_dag_report.py
+++ b/tests/api_fastapi/core_api/routes/public/test_dag_report.py
@@ -24,7 +24,7 @@ import pytest
from airflow.utils.file import list_py_file_paths
from tests_common.test_utils.config import conf_vars
-from tests_common.test_utils.db import clear_db_dags
+from tests_common.test_utils.db import clear_db_dags, parse_and_sync_to_db
pytestmark = pytest.mark.db_test
@@ -84,6 +84,7 @@ class TestDagReportEndpoint:
)
def test_should_response_200(self, test_client, subdir, include_example, expected_total_entries):
with conf_vars({("core", "load_examples"): str(include_example)}):
+ parse_and_sync_to_db(subdir, include_examples=include_example)
response = test_client.get("/public/dagReports", params={"subdir": subdir})
assert response.status_code == 200
response_json = response.json()
@@ -124,3 +125,11 @@ class TestDagReportEndpoint:
}
]
}
+
+ def test_should_respond_401(self, unauthenticated_test_client):
+ response = unauthenticated_test_client.get("/public/dagReports")
+ assert response.status_code == 401
+
+ def test_should_respond_403(self, unauthorized_test_client):
+ response = unauthorized_test_client.get("/public/dagReports")
+ assert response.status_code == 403