This is an automated email from the ASF dual-hosted git repository.

taragolis 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 e90febceb5 Make sure impersonation tests use a temporary 
`AIRFLOW_HOME` (#33422)
e90febceb5 is described below

commit e90febceb549f669e887de4219cc19ba48b73a4c
Author: Andrey Anshin <[email protected]>
AuthorDate: Thu Aug 17 03:22:51 2023 +0400

    Make sure impersonation tests use a temporary `AIRFLOW_HOME` (#33422)
---
 tests/core/test_impersonation_tests.py | 88 +++++++++++++++++++++++++++++-----
 1 file changed, 75 insertions(+), 13 deletions(-)

diff --git a/tests/core/test_impersonation_tests.py 
b/tests/core/test_impersonation_tests.py
index 3827f89896..b92d437f16 100644
--- a/tests/core/test_impersonation_tests.py
+++ b/tests/core/test_impersonation_tests.py
@@ -17,13 +17,17 @@
 # under the License.
 from __future__ import annotations
 
+import contextlib
 import logging
 import os
 import subprocess
 import sys
+import tempfile
+from pathlib import Path
 
 import pytest
 
+from airflow.configuration import conf
 from airflow.jobs.backfill_job_runner import BackfillJobRunner
 from airflow.jobs.job import Job, run_job
 from airflow.models import DagBag, DagRun, TaskInstance
@@ -45,6 +49,42 @@ TEST_USER = "airflow_test_user"
 logger = logging.getLogger(__name__)
 
 
[email protected]
+def set_permissions(settings: dict[Path | str, int]):
+    """Helper for recursively set permissions only for specific path and 
revert it back."""
+    orig_permissions = []
+    try:
+        print(" Change file/directory permissions ".center(72, "+"))
+        for path, mode in settings.items():
+            if isinstance(path, str):
+                path = Path(path)
+            if len(path.parts) <= 1:
+                raise SystemError(f"Unable to change permission for the root 
directory: {path}.")
+
+            st_mode = os.stat(path).st_mode
+            new_st_mode = st_mode | mode
+            if new_st_mode > st_mode:
+                print(f"Path={path}, mode={oct(st_mode)}, 
new_mode={oct(new_st_mode)}")
+                orig_permissions.append((path, st_mode))
+                os.chmod(path, new_st_mode)
+
+            parent_path = path.parent
+            while len(parent_path.parts) > 1:
+                st_mode = os.stat(parent_path).st_mode
+                new_st_mode = st_mode | 0o755  # grant r/o access to the 
parent directories
+                if new_st_mode > st_mode:
+                    print(f"Path={parent_path}, mode={oct(st_mode)}, 
new_mode={oct(new_st_mode)}")
+                    orig_permissions.append((parent_path, st_mode))
+                    os.chmod(parent_path, new_st_mode)
+
+                parent_path = parent_path.parent
+        print("".center(72, "+"))
+        yield
+    finally:
+        for path, mode in orig_permissions:
+            os.chmod(path, mode)
+
+
 @pytest.fixture
 def check_original_docker_image():
     if not os.path.isfile("/.dockerenv") or 
os.environ.get("PYTHON_BASE_IMAGE") is None:
@@ -55,18 +95,7 @@ def check_original_docker_image():
             "and only allow to run the test there. This is done by checking 
/.dockerenv file "
             "(always present inside container) and checking for 
PYTHON_BASE_IMAGE variable."
         )
-
-
[email protected]
-def set_permissions(check_original_docker_image):
-    airflow_home = os.environ["AIRFLOW_HOME"]
-    subprocess.check_call(
-        'find "%s" -exec sudo chmod og+w {} +; sudo chmod og+rx /root' % 
airflow_home, shell=True
-    )
     yield
-    subprocess.check_call(
-        'find "%s" -exec sudo chmod og-w {} +; sudo chmod og-rx /root' % 
airflow_home, shell=True
-    )
 
 
 @pytest.fixture
@@ -84,15 +113,48 @@ def create_user(check_original_docker_image):
                 f"{command!r} without a password prompt (check sudoers 
file)?\n"
                 f"{e.stdout.decode() if e.stdout else ''}"
             )
-    yield
+    yield TEST_USER
     subprocess.check_call(["sudo", "userdel", "-r", TEST_USER])
 
 
[email protected]
+def create_airflow_home(create_user, tmp_path, monkeypatch):
+    sql_alchemy_conn = conf.get_mandatory_value("database", "sql_alchemy_conn")
+    username = create_user
+    airflow_home = tmp_path / "airflow-home"
+
+    if not airflow_home.exists():
+        airflow_home.mkdir(parents=True, exist_ok=True)
+
+    permissions = {
+        # By default, ``tmp_path`` save temporary files/directories in user 
temporary directory
+        # something like: `/tmp/pytest-of-root` and other users might be 
limited to access to it,
+        # so we need to grant at least r/o access to everyone.
+        airflow_home: 0o777,
+        # Grant full access to system-wide temporary directory (if for some 
reason it not set)
+        tempfile.gettempdir(): 0o777,
+    }
+
+    if sql_alchemy_conn.lower().startswith("sqlite"):
+        sqlite_file = Path(sql_alchemy_conn.replace("sqlite:///", ""))
+        # Grant r/w access to sqlite file.
+        permissions[sqlite_file] = 0o766
+        # Grant r/w access to directory where sqlite file placed
+        # otherwise we can't create temporary files during write access.
+        permissions[sqlite_file.parent] = 0o777
+
+    monkeypatch.setenv("AIRFLOW_HOME", str(airflow_home))
+
+    with set_permissions(permissions):
+        subprocess.check_call(["sudo", "chown", f"{username}:root", 
str(airflow_home), "-R"], close_fds=True)
+        yield airflow_home
+
+
 class BaseImpersonationTest:
     dagbag: DagBag
 
     @pytest.fixture(autouse=True)
-    def setup_impersonation_tests(self, set_permissions, create_user):
+    def setup_impersonation_tests(self, create_airflow_home):
         """Setup test cases for all impersonation tests."""
         db.clear_db_runs()
         db.clear_db_jobs()

Reply via email to