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 c064739d3a7 Fix permissions on get_event_logs endpoint (#60936)
c064739d3a7 is described below
commit c064739d3a7686834eca6773ed6497e423589a9d
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Fri Jan 23 01:04:42 2026 +0100
Fix permissions on get_event_logs endpoint (#60936)
* Fix permissions on get_event_logs endpoint
* Fix CI
---
.../api_fastapi/core_api/routes/public/event_logs.py | 9 ++++++++-
airflow-core/src/airflow/api_fastapi/core_api/security.py | 14 ++++++++++++++
.../api_fastapi/core_api/routes/public/test_event_logs.py | 4 ++--
3 files changed, 24 insertions(+), 3 deletions(-)
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/event_logs.py
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/event_logs.py
index 8909b5ff1bc..529fbb94a6b 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/event_logs.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/event_logs.py
@@ -43,7 +43,11 @@ from airflow.api_fastapi.core_api.datamodels.event_logs
import (
EventLogResponse,
)
from airflow.api_fastapi.core_api.openapi.exceptions import
create_openapi_http_exception_doc
-from airflow.api_fastapi.core_api.security import DagAccessEntity,
requires_access_dag
+from airflow.api_fastapi.core_api.security import (
+ DagAccessEntity,
+ ReadableEventLogsFilterDep,
+ requires_access_dag,
+)
from airflow.models import Log
event_logs_router = AirflowRouter(tags=["Event Log"], prefix="/eventLogs")
@@ -126,6 +130,7 @@ def get_event_logs(
run_id_pattern: Annotated[_SearchParam,
Depends(search_param_factory(Log.run_id, "run_id_pattern"))],
owner_pattern: Annotated[_SearchParam,
Depends(search_param_factory(Log.owner, "owner_pattern"))],
event_pattern: Annotated[_SearchParam,
Depends(search_param_factory(Log.event, "event_pattern"))],
+ readable_event_logs_filter: ReadableEventLogsFilterDep,
) -> EventLogCollectionResponse:
"""Get all Event Logs."""
query = select(Log).options(joinedload(Log.task_instance),
joinedload(Log.dag_model))
@@ -151,6 +156,8 @@ def get_event_logs(
run_id_pattern,
owner_pattern,
event_pattern,
+ # Permission
+ readable_event_logs_filter,
],
offset=offset,
limit=limit,
diff --git a/airflow-core/src/airflow/api_fastapi/core_api/security.py
b/airflow-core/src/airflow/api_fastapi/core_api/security.py
index adca02f2e77..3b92e845e73 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/security.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/security.py
@@ -25,6 +25,7 @@ from fastapi import Depends, HTTPException, Request, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer,
OAuth2PasswordBearer
from jwt import ExpiredSignatureError, InvalidTokenError
from pydantic import NonNegativeInt
+from sqlalchemy import or_
from airflow.api_fastapi.app import get_auth_manager
from airflow.api_fastapi.auth.managers.base_auth_manager import (
@@ -65,6 +66,7 @@ from airflow.configuration import conf
from airflow.models import Connection, Pool, Variable
from airflow.models.dag import DagModel, DagRun, DagTag
from airflow.models.dagwarning import DagWarning
+from airflow.models.log import Log
from airflow.models.taskinstance import TaskInstance as TI
from airflow.models.team import Team
from airflow.models.xcom import XComModel
@@ -188,6 +190,15 @@ class PermittedDagWarningFilter(PermittedDagFilter):
return select.where(DagWarning.dag_id.in_(self.value or set()))
+class PermittedEventLogFilter(PermittedDagFilter):
+ """A parameter that filters the permitted even logs for the user."""
+
+ def to_orm(self, select: Select) -> Select:
+ # Event Logs not related to Dags have dag_id as None and are always
returned.
+ # return select.where(Log.dag_id.in_(self.value or set()) or
Log.dag_id.is_(None))
+ return select.where(or_(Log.dag_id.in_(self.value or set()),
Log.dag_id.is_(None)))
+
+
class PermittedTIFilter(PermittedDagFilter):
"""A parameter that filters the permitted task instances for the user."""
@@ -240,6 +251,9 @@ ReadableDagWarningsFilterDep = Annotated[
ReadableTIFilterDep = Annotated[
PermittedTIFilter, Depends(permitted_dag_filter_factory("GET",
PermittedTIFilter))
]
+ReadableEventLogsFilterDep = Annotated[
+ PermittedTIFilter, Depends(permitted_dag_filter_factory("GET",
PermittedEventLogFilter))
+]
ReadableXComFilterDep = Annotated[
PermittedXComFilter, Depends(permitted_dag_filter_factory("GET",
PermittedXComFilter))
]
diff --git
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_event_logs.py
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_event_logs.py
index c71dc587a15..3decc63918a 100644
---
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_event_logs.py
+++
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_event_logs.py
@@ -302,7 +302,7 @@ class TestGetEventLogs(TestEventLogsEndpoint):
def test_get_event_logs(
self, test_client, query_params, expected_status_code,
expected_total_entries, expected_events
):
- with assert_queries_count(2):
+ with assert_queries_count(3):
response = test_client.get("/eventLogs", params=query_params)
assert response.status_code == expected_status_code
if expected_status_code != 200:
@@ -341,7 +341,7 @@ class TestGetEventLogs(TestEventLogsEndpoint):
def test_get_event_logs_order_by(
self, test_client, query_params, expected_status_code,
expected_total_entries, expected_events
):
- with assert_queries_count(2):
+ with assert_queries_count(3):
response = test_client.get("/eventLogs", params=query_params)
assert response.status_code == expected_status_code
if expected_status_code != 200: