This is an automated email from the ASF dual-hosted git repository.
vincbeck 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 69ab304ffa3 Add deprecation warnings + doc for
`airflow.security.permissions` (#53796)
69ab304ffa3 is described below
commit 69ab304ffa3d9b847b7dd0ee90ee6ef100223d66
Author: Zach <[email protected]>
AuthorDate: Mon Jul 28 12:50:58 2025 -0400
Add deprecation warnings + doc for `airflow.security.permissions` (#53796)
* Add deprecation warnings and doc for airflow.security.permissions
* add news fragment
* Add reference from auth manager doc to deprecation doc
* Fix doc relative links and wording
* fix doc: replace table with list + arrows
---
.../docs/core-concepts/auth-manager/index.rst | 2 +-
.../docs/security/deprecated_permissions.rst | 60 ++++++++++++++++++++++
airflow-core/newsfragments/53796.misc.rst | 1 +
airflow-core/src/airflow/security/permissions.py | 10 ++++
.../test_permissions_deprecation_warning.py | 34 ++++++++++++
task-sdk/src/airflow/sdk/definitions/dag.py | 8 +++
task-sdk/tests/task_sdk/definitions/test_dag.py | 34 +++++++++++-
7 files changed, 147 insertions(+), 2 deletions(-)
diff --git a/airflow-core/docs/core-concepts/auth-manager/index.rst
b/airflow-core/docs/core-concepts/auth-manager/index.rst
index b729fc5a848..845d03b03d0 100644
--- a/airflow-core/docs/core-concepts/auth-manager/index.rst
+++ b/airflow-core/docs/core-concepts/auth-manager/index.rst
@@ -239,7 +239,7 @@ Additional Caveats
^^^^^^^^^^^^^^^^^^
* Your auth manager should not reference anything from the
``airflow.security.permissions`` module, as that module is in the process of
being deprecated.
- Instead, your code should use the definitions in
``airflow.api_fastapi.auth.managers.models.resource_details``.
+ Instead, your code should use the definitions in
``airflow.api_fastapi.auth.managers.models.resource_details``. For more details
on the ``airflow.security.permissions`` deprecation, see
:doc:`/security/deprecated_permissions`
* The ``access_control`` attribute of a DAG instance is only compatible with
the FAB auth manager. Custom auth manager implementations should leverage
``get_authorized_dag_ids`` for DAG instance attribute-based access controls in
more customizable ways (e.g. authorization based on DAG tags, DAG bundles,
etc.).
* You may find it useful to define a private, generalized ``_is_authorized``
method which acts as the standardized authorization mechanism, and which each
public ``is_authorized_*`` method calls with the appropriate parameters.
diff --git a/airflow-core/docs/security/deprecated_permissions.rst
b/airflow-core/docs/security/deprecated_permissions.rst
new file mode 100644
index 00000000000..69deb91e58e
--- /dev/null
+++ b/airflow-core/docs/security/deprecated_permissions.rst
@@ -0,0 +1,60 @@
+ .. Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ .. http://www.apache.org/licenses/LICENSE-2.0
+
+ .. Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+Deprecation Notice for airflow.security.permissions
+===================================================
+
+Since the release of Airflow 3, the Flask AppBuilder (AKA "FAB") provider is
+`no longer a core Airflow dependency
<https://cwiki.apache.org/confluence/display/AIRFLOW/AIP-79%3A+Remove+Flask+AppBuilder+as+Core+dependency>`_.
+However, some modules specifically designed for
:doc:`apache-airflow-providers-fab:auth-manager/index` remain in the core
Airflow distribution as a
+backwards-compatible convenience for Airflow users. One such module which
remains in the core distribution for backwards compatibility purposes is
``airflow.security.permissions``
+
+If your deployment depends on ``airflow.security.permissions`` for any custom
role definitions, or for any custom Auth Manager logic --
+regardless of whether you use the FAB Auth Manager or some other Auth Manager
-- you should transition
+to the new authorization standard definitions for resources and actions.
+The deprecated ``airflow.security.permissions`` will be removed in Airflow 4.
+
+Does this Deprecation Affect My Airflow System?
+-----------------------------------------------
+
+Generally speaking, this deprecation warning applies to any Airflow system in
which **either** of the following is true:
+
+* The Airflow deployment relies on ``airflow.security.permissions`` to define
custom RBAC roles.
+* The Airflow deployment has other custom logic which relies on
``airflow.security.permissions``, including any custom
:doc:`/core-concepts/auth-manager/index` dependencies.
+
+However, if you rely on the **unmodified**
:doc:`apache-airflow-providers-fab:auth-manager/index` and you **do not** use
any custom role definitions, then the rest of this doc does not apply to you.
+Similarly, if you rely on the :doc:`/core-concepts/auth-manager/simple/index`
or any of the other provider Auth Managers, and have no custom code using
``airflow.security.permissions``, then the rest of this doc does not apply to
you.
+
+.. note::
+ Each customized Airflow RBAC setup differs on a case-by-case basis. As
such, this doc can only provide general
+ guidance for the transition to the new Airflow authorization standards,
without being overly prescriptive.
+
+How to Migrate to the New Authorization Standard Definitions
+------------------------------------------------------------
+
+Refer to the list below for the deprecated permissions module components, and
the corresponding supported
+replacement available from Airflow core:
+
+* ``airflow.security.permissions.ACTION_*`` -->
``airflow.api_fastapi.auth.managers.base_auth_manager.ResourceMethod``
+* ``airflow.security.permissions.RESOURCE_*`` -->
``airflow.api_fastapi.auth.managers.models.resource_details``
+* ``DAG.access_control`` --> DAG-level permissions should be handled by the
chosen Auth Manager's ``filter_authorized_dag_ids`` method.
+
+If you maintain a custom :doc:`/core-concepts/auth-manager/index` which relies
on the deprecated module, it is
+recommended you refer to the ``SimpleAuthManager``'s `source code
<https://github.com/apache/airflow/blob/main/airflow-core/src/airflow/api_fastapi/auth/managers/simple/simple_auth_manager.py>`_
+as an example for how you might use the ``ResourceMethod`` and
``resource_details`` components.
+
+If you rely on custom role definitions based off the deprecated module, you
should refer to the documentation of the auth manager your system uses.
diff --git a/airflow-core/newsfragments/53796.misc.rst
b/airflow-core/newsfragments/53796.misc.rst
new file mode 100644
index 00000000000..07c127679c5
--- /dev/null
+++ b/airflow-core/newsfragments/53796.misc.rst
@@ -0,0 +1 @@
+Add ``RemovedInAirflow4Warning`` warnings for ``airflow.security.permissions``
imports and ``access_control`` DAG attribute usage.
diff --git a/airflow-core/src/airflow/security/permissions.py
b/airflow-core/src/airflow/security/permissions.py
index 7545fe9d930..008d7855ef9 100644
--- a/airflow-core/src/airflow/security/permissions.py
+++ b/airflow-core/src/airflow/security/permissions.py
@@ -16,8 +16,18 @@
# under the License.
from __future__ import annotations
+import warnings
from typing import TypedDict
+from airflow.exceptions import RemovedInAirflow4Warning
+
+warnings.warn(
+ "The airflow.security.permissions module is deprecated; please see
https://airflow.apache.org/docs/apache-airflow/stable/security/deprecated_permissions.html",
+ RemovedInAirflow4Warning,
+ stacklevel=2,
+)
+
+
# Resource Constants
RESOURCE_ACTION = "Permissions"
RESOURCE_ADMIN_MENU = "Admin"
diff --git
a/airflow-core/tests/unit/security/test_permissions_deprecation_warning.py
b/airflow-core/tests/unit/security/test_permissions_deprecation_warning.py
new file mode 100644
index 00000000000..844696f19eb
--- /dev/null
+++ b/airflow-core/tests/unit/security/test_permissions_deprecation_warning.py
@@ -0,0 +1,34 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+import importlib
+import re
+
+import pytest
+
+from airflow.exceptions import RemovedInAirflow4Warning
+from airflow.security import permissions
+
+
+def test_permissions_import_warns() -> None:
+ """Ensures that imports of `airflow.security.permissions` trigger a
`RemovedInAirflow4Warning`."""
+ with pytest.warns(
+ RemovedInAirflow4Warning, match=re.escape("The
airflow.security.permissions module is deprecated")
+ ):
+ importlib.reload(permissions)
diff --git a/task-sdk/src/airflow/sdk/definitions/dag.py
b/task-sdk/src/airflow/sdk/definitions/dag.py
index 05bd34e95bf..7cc7eb7f030 100644
--- a/task-sdk/src/airflow/sdk/definitions/dag.py
+++ b/task-sdk/src/airflow/sdk/definitions/dag.py
@@ -23,6 +23,7 @@ import itertools
import logging
import os
import sys
+import warnings
import weakref
from collections import abc
from collections.abc import Callable, Collection, Iterable, MutableSet
@@ -46,6 +47,7 @@ from airflow.exceptions import (
DuplicateTaskIdFound,
FailFastDagInvalidTriggerRule,
ParamValidationError,
+ RemovedInAirflow4Warning,
TaskNotFound,
)
from airflow.sdk.bases.operator import BaseOperator
@@ -468,6 +470,12 @@ class DAG:
self.default_args["start_date"] =
timezone.convert_to_utc(start_date)
if end_date := self.default_args.get("end_date", None):
self.default_args["end_date"] = timezone.convert_to_utc(end_date)
+ if self.access_control is not None:
+ warnings.warn(
+ "The airflow.security.permissions module is deprecated; please
see
https://airflow.apache.org/docs/apache-airflow/stable/security/deprecated_permissions.html",
+ RemovedInAirflow4Warning,
+ stacklevel=2,
+ )
@params.validator
def _validate_params(self, _, params: ParamsDict):
diff --git a/task-sdk/tests/task_sdk/definitions/test_dag.py
b/task-sdk/tests/task_sdk/definitions/test_dag.py
index b97ac29c1c8..b0683942c84 100644
--- a/task-sdk/tests/task_sdk/definitions/test_dag.py
+++ b/task-sdk/tests/task_sdk/definitions/test_dag.py
@@ -16,13 +16,15 @@
# under the License.
from __future__ import annotations
+import re
+import warnings
import weakref
from datetime import datetime, timedelta, timezone
from typing import Any
import pytest
-from airflow.exceptions import DuplicateTaskIdFound
+from airflow.exceptions import DuplicateTaskIdFound, RemovedInAirflow4Warning
from airflow.sdk.bases.operator import BaseOperator
from airflow.sdk.definitions.dag import DAG, dag as dag_decorator
from airflow.sdk.definitions.param import DagParam, Param, ParamsDict
@@ -141,6 +143,36 @@ class TestDag:
assert op8.dag == dag
assert op9.dag == dag2
+ def test_none_or_empty_access_control_does_not_warn(self) -> None:
+ """Ensure that `RemovedInAirflow4Warning` warnings do not arise when
`access_control` is `None`."""
+ with warnings.catch_warnings():
+ warnings.simplefilter("error")
+ _ = DAG("test-no-warnings-dag", access_control=None,
schedule=None, start_date=DEFAULT_DATE)
+
+ @pytest.mark.parametrize(
+ "role_access_control_entry",
+ [
+ {},
+ {"DAGs": {}},
+ {"DAG Runs": {}},
+ {"DAGs": {}, "DAG Runs": {}},
+ {"DAGs": {"can_read"}},
+ {"DAG Runs": {"can_read"}},
+ {"DAGs": {"can_read"}, "DAG Runs": {"can_read"}},
+ ],
+ )
+ def test_non_empty_access_control_warns(self, role_access_control_entry:
dict[str, set[str]]) -> None:
+ """Ensure that `RemovedInAirflow4Warning` warnings are triggered when
`access_control` is non-empty."""
+ access_control = (
+ {"fake-role": role_access_control_entry}
+ if len(role_access_control_entry) > 0
+ else role_access_control_entry
+ )
+ with pytest.warns(
+ RemovedInAirflow4Warning, match=re.escape("The
airflow.security.permissions module is deprecated")
+ ):
+ _ = DAG("should-warn-dag", access_control=access_control,
schedule=None, start_date=DEFAULT_DATE)
+
def test_params_not_passed_is_empty_dict(self):
"""
Test that when 'params' is _not_ passed to a new Dag, that the params