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

Reply via email to