diff --git a/airflow/providers/sftp/hooks/sftp.py b/airflow/providers/sftp/hooks/sftp.py index 93eb3d52d45ea..85edeee46ef68 100644 --- a/airflow/providers/sftp/hooks/sftp.py +++ b/airflow/providers/sftp/hooks/sftp.py @@ -159,15 +159,16 @@ def list_directory(self, path: str) -> list[str]: files = sorted(conn.listdir(path)) return files - def mkdir(self, path: str, mode: int = 777) -> None: + def mkdir(self, path: str, mode: int = 0o777) -> None: """ Creates a directory on the remote system. + The default mode is 0777, but on some systems, the current umask value is first masked out. :param path: full path to the remote directory to create - :param mode: permissions to set the directory with + :param mode: int permissions of octal mode for directory """ conn = self.get_conn() - conn.mkdir(path, mode=int(str(mode), 8)) + conn.mkdir(path, mode=mode) def isdir(self, path: str) -> bool: """ @@ -195,12 +196,13 @@ def isfile(self, path: str) -> bool: result = False return result - def create_directory(self, path: str, mode: int = 777) -> None: + def create_directory(self, path: str, mode: int = 0o777) -> None: """ Creates a directory on the remote system. + The default mode is 0777, but on some systems, the current umask value is first masked out. :param path: full path to the remote directory to create - :param mode: int representation of octal mode for directory + :param mode: int permissions of octal mode for directory """ conn = self.get_conn() if self.isdir(path): diff --git a/tests/providers/sftp/hooks/test_sftp.py b/tests/providers/sftp/hooks/test_sftp.py index f3af70cc16d11..b471dc88b053f 100644 --- a/tests/providers/sftp/hooks/test_sftp.py +++ b/tests/providers/sftp/hooks/test_sftp.py @@ -107,12 +107,20 @@ def test_mkdir(self): self.hook.mkdir(os.path.join(TMP_PATH, TMP_DIR_FOR_TESTS, new_dir_name)) output = self.hook.describe_directory(os.path.join(TMP_PATH, TMP_DIR_FOR_TESTS)) assert new_dir_name in output + # test the directory has default permissions to 777 - umask + umask = 0o022 + output = self.hook.get_conn().lstat(os.path.join(TMP_PATH, TMP_DIR_FOR_TESTS, new_dir_name)) + assert output.st_mode & 0o777 == 0o777 - umask def test_create_and_delete_directory(self): new_dir_name = "new_dir" self.hook.create_directory(os.path.join(TMP_PATH, TMP_DIR_FOR_TESTS, new_dir_name)) output = self.hook.describe_directory(os.path.join(TMP_PATH, TMP_DIR_FOR_TESTS)) assert new_dir_name in output + # test the directory has default permissions to 777 + umask = 0o022 + output = self.hook.get_conn().lstat(os.path.join(TMP_PATH, TMP_DIR_FOR_TESTS, new_dir_name)) + assert output.st_mode & 0o777 == 0o777 - umask # test directory already exists for code coverage, should not raise an exception self.hook.create_directory(os.path.join(TMP_PATH, TMP_DIR_FOR_TESTS, new_dir_name)) # test path already exists and is a file, should raise an exception