diff --git a/changelogs/fragments/72966-allow-tilde-inside-galaxy-roles.yml b/changelogs/fragments/72966-allow-tilde-inside-galaxy-roles.yml new file mode 100644 index 00000000000..29f8e65694d --- /dev/null +++ b/changelogs/fragments/72966-allow-tilde-inside-galaxy-roles.yml @@ -0,0 +1,2 @@ +bugfixes: + - Allow `~` to be present in file names in galaxy roles (https://github.com/ansible/ansible/issues/72966) diff --git a/lib/ansible/galaxy/role.py b/lib/ansible/galaxy/role.py index 7de44dedf84..391df72545c 100644 --- a/lib/ansible/galaxy/role.py +++ b/lib/ansible/galaxy/role.py @@ -334,7 +334,11 @@ class GalaxyRole(object): n_parts = n_member_name.replace(n_archive_parent_dir, "", 1).split(os.sep) n_final_parts = [] for n_part in n_parts: - if n_part != '..' and '~' not in n_part and '$' not in n_part: + # TODO if the condition triggers it produces a broken installation. + # It will create the parent directory as an empty file and will + # explode if the directory contains valid files. + # Leaving this as is since the whole module needs a rewrite. + if n_part != '..' and not n_part.startswith('~') and '$' not in n_part: n_final_parts.append(n_part) member.name = os.path.join(*n_final_parts) role_tar_file.extract(member, to_native(self.path)) diff --git a/test/integration/targets/ansible-galaxy-role/aliases b/test/integration/targets/ansible-galaxy-role/aliases new file mode 100644 index 00000000000..62548acd35e --- /dev/null +++ b/test/integration/targets/ansible-galaxy-role/aliases @@ -0,0 +1,2 @@ +shippable/posix/group4 +skip/python2.6 # build uses tarfile with features not available until 2.7 diff --git a/test/integration/targets/ansible-galaxy-role/meta/main.yml b/test/integration/targets/ansible-galaxy-role/meta/main.yml new file mode 100644 index 00000000000..e6bc9ccb622 --- /dev/null +++ b/test/integration/targets/ansible-galaxy-role/meta/main.yml @@ -0,0 +1 @@ +dependencies: [setup_remote_tmp_dir] diff --git a/test/integration/targets/ansible-galaxy-role/tasks/main.yml b/test/integration/targets/ansible-galaxy-role/tasks/main.yml new file mode 100644 index 00000000000..e49e4e2958a --- /dev/null +++ b/test/integration/targets/ansible-galaxy-role/tasks/main.yml @@ -0,0 +1,58 @@ +- name: Archive directories + file: + state: directory + path: "{{ remote_tmp_dir }}/role.d/{{item}}" + loop: + - meta + - tasks + +- name: Metadata file + copy: + content: "'galaxy_info': {}" + dest: "{{ remote_tmp_dir }}/role.d/meta/main.yml" + +- name: Valid files + copy: + content: "" + dest: "{{ remote_tmp_dir }}/role.d/tasks/{{item}}" + loop: + - "main.yml" + - "valid~file.yml" + +- name: Valid role archive + command: "tar cf {{ remote_tmp_dir }}/valid-role.tar {{ remote_tmp_dir }}/role.d" + +- name: Invalid file + copy: + content: "" + dest: "{{ remote_tmp_dir }}/role.d/tasks/~invalid.yml" + +- name: Valid requirements file + copy: + dest: valid-requirements.yml + content: "[{'src': '{{ remote_tmp_dir }}/valid-role.tar', 'name': 'valid-testrole'}]" + +- name: Invalid role archive + command: "tar cf {{ remote_tmp_dir }}/invalid-role.tar {{ remote_tmp_dir }}/role.d" + +- name: Invalid requirements file + copy: + dest: invalid-requirements.yml + content: "[{'src': '{{ remote_tmp_dir }}/invalid-role.tar', 'name': 'invalid-testrole'}]" + +- name: Install valid role + command: ansible-galaxy install -r valid-requirements.yml + +- name: Uninstall valid role + command: ansible-galaxy role remove valid-testrole + +- name: Install invalid role + command: ansible-galaxy install -r invalid-requirements.yml + ignore_errors: yes + register: invalid + +- assert: + that: "invalid.rc != 0" + +- name: Uninstall invalid role + command: ansible-galaxy role remove invalid-testrole