This is an automated email from the ASF dual-hosted git repository.
potiuk 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 a61b5e893a Fix issues related to access_control={} (#34114)
a61b5e893a is described below
commit a61b5e893af83d3022aa8265f230b52c5b2ad93d
Author: Sam Wheating <[email protected]>
AuthorDate: Wed Sep 6 17:57:31 2023 -0700
Fix issues related to access_control={} (#34114)
* allow empty access control on dags
* Add test which demonstrates loss of information during ser/de
* Keep empty value when serializing access_control dict
---
airflow/models/dag.py | 2 +-
airflow/serialization/serialized_objects.py | 8 ++++++++
airflow/www/security.py | 2 +-
tests/serialization/test_dag_serialization.py | 9 +++++++++
4 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/airflow/models/dag.py b/airflow/models/dag.py
index 642d617804..2cdcfc197a 100644
--- a/airflow/models/dag.py
+++ b/airflow/models/dag.py
@@ -779,7 +779,7 @@ class DAG(LoggingMixin):
will be replaced with 'can_read', in {'role2': {'can_dag_read',
'can_dag_edit'}}
'can_dag_edit' will be replaced with 'can_edit', etc.
"""
- if not access_control:
+ if access_control is None:
return None
new_perm_mapping = {
permissions.DEPRECATED_ACTION_CAN_DAG_READ:
permissions.ACTION_CAN_READ,
diff --git a/airflow/serialization/serialized_objects.py
b/airflow/serialization/serialized_objects.py
index a7a712cf11..fa8e638d80 100644
--- a/airflow/serialization/serialized_objects.py
+++ b/airflow/serialization/serialized_objects.py
@@ -1400,6 +1400,14 @@ class SerializedDAG(DAG, BaseSerialization):
return dag
+ @classmethod
+ def _is_excluded(cls, var: Any, attrname: str, op: DAGNode):
+ # {} is explicitly different from None in the case of DAG-level access
control
+ # and as a result we need to preserve empty dicts through
serialization for this field
+ if attrname == "_access_control" and var is not None:
+ return False
+ return super()._is_excluded(var, attrname, op)
+
@classmethod
def to_dict(cls, var: Any) -> dict:
"""Stringifies DAGs and operators contained by var and returns a dict
of var."""
diff --git a/airflow/www/security.py b/airflow/www/security.py
index 7dcf2c30d0..d7ccea66de 100644
--- a/airflow/www/security.py
+++ b/airflow/www/security.py
@@ -603,7 +603,7 @@ class AirflowSecurityManager(SecurityManagerOverride,
SecurityManager, LoggingMi
if (action_name, dag_resource_name) not in perms:
self._merge_perm(action_name, dag_resource_name)
- if dag.access_control:
+ if dag.access_control is not None:
self.sync_perm_for_dag(dag_resource_name, dag.access_control)
def update_admin_permission(self) -> None:
diff --git a/tests/serialization/test_dag_serialization.py
b/tests/serialization/test_dag_serialization.py
index 7ecadf9d2a..f1c109e77b 100644
--- a/tests/serialization/test_dag_serialization.py
+++ b/tests/serialization/test_dag_serialization.py
@@ -430,6 +430,15 @@ class TestStringifiedDAGs:
print(task["task_id"], k, v)
assert actual == expected
+ def test_dag_serialization_preserves_empty_access_roles(self):
+ """Verify that an explicitly empty access_control dict is preserved."""
+ dag = collect_dags(["airflow/example_dags"])["simple_dag"]
+ dag.access_control = {}
+ serialized_dag = SerializedDAG.to_dict(dag)
+ SerializedDAG.validate_schema(serialized_dag)
+
+ assert serialized_dag["dag"]["_access_control"] == {"__type": "dict",
"__var": {}}
+
def test_dag_serialization_unregistered_custom_timetable(self):
"""Verify serialization fails without timetable registration."""
dag =
get_timetable_based_simple_dag(CustomSerializationTimetable("bar"))