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