This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-1-test by this push:
new 091d852122c [v3-1-test] Fix permissions on get_event_logs endpoint
(#60936) (#60958)
091d852122c is described below
commit 091d852122c30ce017fddd9763361d3147b1b3f3
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Jan 23 17:21:27 2026 +0100
[v3-1-test] Fix permissions on get_event_logs endpoint (#60936) (#60958)
* Fix permissions on get_event_logs endpoint
* Fix CI
(cherry picked from commit c064739d3a7686834eca6773ed6497e423589a9d)
Co-authored-by: Pierre Jeambrun <[email protected]>
---
.../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 5e9fae52e65..ed75cf305ae 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
COOKIE_NAME_JWT_TOKEN
@@ -62,6 +63,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.xcom import XComModel
@@ -170,6 +172,15 @@ class PermittedDagWarningFilter(PermittedDagFilter):
return select.where(DagWarning.dag_id.in_(self.value))
+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."""
@@ -223,6 +234,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 dd87e8d7fac..0d68107ea1a 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: