diff --git a/changelogs/fragments/80128-symbolic-modes-X-use-computed.yml b/changelogs/fragments/80128-symbolic-modes-X-use-computed.yml new file mode 100644 index 00000000000..c7f2434e8ef --- /dev/null +++ b/changelogs/fragments/80128-symbolic-modes-X-use-computed.yml @@ -0,0 +1,3 @@ +bugfixes: + - file modules - Make symbolic modes with X use the computed permission, not original file (https://github.com/ansible/ansible/issues/80128) + - copy unit tests - Fixing "dir all perms" documentation and formatting for easier reading. diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index 98ce69f5864..161d6e79e2d 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -1074,7 +1074,7 @@ class AnsibleModule(object): raise ValueError("bad symbolic permission for mode: %s" % mode) for user in users: - mode_to_apply = cls._get_octal_mode_from_symbolic_perms(path_stat, user, perms, use_umask) + mode_to_apply = cls._get_octal_mode_from_symbolic_perms(path_stat, user, perms, use_umask, new_mode) new_mode = cls._apply_operation_to_mode(user, opers[idx], mode_to_apply, new_mode) return new_mode @@ -1099,9 +1099,9 @@ class AnsibleModule(object): return new_mode @staticmethod - def _get_octal_mode_from_symbolic_perms(path_stat, user, perms, use_umask): - prev_mode = stat.S_IMODE(path_stat.st_mode) - + def _get_octal_mode_from_symbolic_perms(path_stat, user, perms, use_umask, prev_mode=None): + if prev_mode is None: + prev_mode = stat.S_IMODE(path_stat.st_mode) is_directory = stat.S_ISDIR(path_stat.st_mode) has_x_permissions = (prev_mode & EXEC_PERM_BITS) > 0 apply_X_permission = is_directory or has_x_permissions diff --git a/test/units/modules/test_copy.py b/test/units/modules/test_copy.py index 20c309b60fc..9de86118ae4 100644 --- a/test/units/modules/test_copy.py +++ b/test/units/modules/test_copy.py @@ -128,16 +128,19 @@ def test_split_pre_existing_dir_working_dir_exists(directory, expected, mocker): # # Info helpful for making new test cases: # -# base_mode = {'dir no perms': 0o040000, -# 'file no perms': 0o100000, -# 'dir all perms': 0o400000 | 0o777, -# 'file all perms': 0o100000, | 0o777} +# base_mode = { +# 'dir no perms': 0o040000, +# 'file no perms': 0o100000, +# 'dir all perms': 0o040000 | 0o777, +# 'file all perms': 0o100000 | 0o777} # -# perm_bits = {'x': 0b001, +# perm_bits = { +# 'x': 0b001, # 'w': 0b010, # 'r': 0b100} # -# role_shift = {'u': 6, +# role_shift = { +# 'u': 6, # 'g': 3, # 'o': 0} @@ -172,6 +175,10 @@ DATA = ( # Going from no permissions to setting all for user, group, and/or oth # chmod a-X statfile <== removes execute from statfile (0o100777, u'a-X', 0o0666), + # Verify X uses computed not original mode + (0o100777, u'a=,u=rX', 0o0400), + (0o040777, u'a=,u=rX', 0o0500), + # Multiple permissions (0o040000, u'u=rw-x+X,g=r-x+X,o=r-x+X', 0o0755), (0o100000, u'u=rw-x+X,g=r-x+X,o=r-x+X', 0o0644),