From 07ad1b2641e0351c912fda018f4c773d725bf45e Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Wed, 24 Apr 2024 10:22:25 -0400 Subject: [PATCH] inspect components, ansible_managed templatable (#83053) (#83130) * inspect components, ansible_managed templatable fixes #82322 (cherry picked from commit 124d03145cafff709b9c37daa8b2b5d29b7d0168) --- .../fragments/ansible_managed_restore.yml | 2 + lib/ansible/template/__init__.py | 20 +++---- .../targets/template/ansible_managed.yml | 56 ++++++++++++++++--- .../template/ansible_managed_79129.yml | 29 ---------- .../template/ansible_managed_templated.cfg | 2 + test/integration/targets/template/runme.sh | 6 +- 6 files changed, 64 insertions(+), 51 deletions(-) create mode 100644 changelogs/fragments/ansible_managed_restore.yml delete mode 100644 test/integration/targets/template/ansible_managed_79129.yml create mode 100644 test/integration/targets/template/ansible_managed_templated.cfg diff --git a/changelogs/fragments/ansible_managed_restore.yml b/changelogs/fragments/ansible_managed_restore.yml new file mode 100644 index 00000000000..63d15bf9dca --- /dev/null +++ b/changelogs/fragments/ansible_managed_restore.yml @@ -0,0 +1,2 @@ +bugfixes: + - ansible_managed restored it's 'templatability' by ensuring the possible injection routes are cut off earlier in the process. diff --git a/lib/ansible/template/__init__.py b/lib/ansible/template/__init__.py index 2d7920ac202..d70e1368858 100644 --- a/lib/ansible/template/__init__.py +++ b/lib/ansible/template/__init__.py @@ -85,26 +85,26 @@ def generate_ansible_template_vars(path, fullpath=None, dest_path=None): template_uid = os.stat(b_path).st_uid temp_vars = { - 'template_host': to_text(os.uname()[1]), - 'template_path': path, + 'template_host': to_unsafe_text(os.uname()[1]), + 'template_path': to_unsafe_text(path), 'template_mtime': datetime.datetime.fromtimestamp(os.path.getmtime(b_path)), - 'template_uid': to_text(template_uid), + 'template_uid': to_unsafe_text(template_uid), 'template_run_date': datetime.datetime.now(), - 'template_destpath': to_native(dest_path) if dest_path else None, + 'template_destpath': wrap_var(to_native(dest_path)) if dest_path else None, } if fullpath is None: - temp_vars['template_fullpath'] = os.path.abspath(path) + temp_vars['template_fullpath'] = wrap_var(os.path.abspath(path)) else: - temp_vars['template_fullpath'] = fullpath + temp_vars['template_fullpath'] = wrap_var(fullpath) managed_default = C.DEFAULT_MANAGED_STR managed_str = managed_default.format( - host=temp_vars['template_host'], - uid=temp_vars['template_uid'], - file=temp_vars['template_path'].replace('%', '%%'), + host="{{ template_host }}", + uid="{{ template_uid }}", + file="{{ template_path }}" ) - temp_vars['ansible_managed'] = to_unsafe_text(time.strftime(to_native(managed_str), time.localtime(os.path.getmtime(b_path)))) + temp_vars['ansible_managed'] = time.strftime(to_native(managed_str), time.localtime(os.path.getmtime(b_path))) return temp_vars diff --git a/test/integration/targets/template/ansible_managed.yml b/test/integration/targets/template/ansible_managed.yml index 2bd7c2c4f7d..a94e57efbcc 100644 --- a/test/integration/targets/template/ansible_managed.yml +++ b/test/integration/targets/template/ansible_managed.yml @@ -2,13 +2,51 @@ - hosts: testhost gather_facts: False tasks: - - set_fact: + - name: set output_dir + set_fact: output_dir: "{{ lookup('env', 'OUTPUT_DIR') }}" - - file: - path: '{{ output_dir }}/café.txt' - state: 'absent' - # Smoketest that ansible_managed with non-ascii chars works: - # https://github.com/ansible/ansible/issues/27262 - - template: - src: 'templates/café.j2' - dest: '{{ output_dir }}/café.txt' + tags: ['always'] + + - name: Smoketest that ansible_managed with non-ascii chars works, https://github.com/ansible/ansible/issues/27262 + tags: ['27262'] + block: + - name: ensure output file does not exist + file: + path: '{{ output_dir }}/café.txt' + state: 'absent' + + - name: test templating with unicode in template name + template: + src: 'templates/café.j2' + dest: '{{ output_dir }}/café.txt' + + always: + - name: clean up! + file: + path: '{{ output_dir }}/café.txt' + state: 'absent' + + - name: check strftime resolution in ansible_managed, https://github.com/ansible/ansible/pull/79129 + tags: ['79129'] + block: + - template: + src: "templates/%necho Onii-chan help Im stuck;exit 1%n.j2" + dest: "{{ output_dir }}/strftime.sh" + mode: '0755' + + - shell: "exec {{ output_dir | quote }}/strftime.sh" + + - name: Avoid templating 'injections' via file names + template: + src: !unsafe "templates/completely{{ 1 % 0 }} safe template.j2" + dest: "{{ output_dir }}/jinja.sh" + mode: '0755' + + - shell: "exec {{ output_dir | quote }}/jinja.sh" + register: result + + - assert: + that: + - "'Hello' in result.stdout" + - "'uname' not in lookup('file', output_dir ~ '/strftime.sh')" + - "'uname' not in lookup('file', output_dir ~ '/jinja.sh')" diff --git a/test/integration/targets/template/ansible_managed_79129.yml b/test/integration/targets/template/ansible_managed_79129.yml deleted file mode 100644 index e00ada8c10a..00000000000 --- a/test/integration/targets/template/ansible_managed_79129.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -- hosts: testhost - gather_facts: false - tasks: - - set_fact: - output_dir: "{{ lookup('env', 'OUTPUT_DIR') }}" - - - name: check strftime - block: - - template: - src: "templates/%necho Onii-chan help Im stuck;exit 1%n.j2" - dest: "{{ output_dir }}/79129-strftime.sh" - mode: '0755' - - - shell: "exec {{ output_dir | quote }}/79129-strftime.sh" - - - name: check jinja template - block: - - template: - src: !unsafe "templates/completely{{ 1 % 0 }} safe template.j2" - dest: "{{ output_dir }}/79129-jinja.sh" - mode: '0755' - - - shell: "exec {{ output_dir | quote }}/79129-jinja.sh" - register: result - - - assert: - that: - - "'Hello' in result.stdout" diff --git a/test/integration/targets/template/ansible_managed_templated.cfg b/test/integration/targets/template/ansible_managed_templated.cfg new file mode 100644 index 00000000000..4840045859e --- /dev/null +++ b/test/integration/targets/template/ansible_managed_templated.cfg @@ -0,0 +1,2 @@ +[defaults] +ansible_managed=ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}({{{{q('pipe', 'uname -a')}}}}) diff --git a/test/integration/targets/template/runme.sh b/test/integration/targets/template/runme.sh index d3913d971a2..e8141104bef 100755 --- a/test/integration/targets/template/runme.sh +++ b/test/integration/targets/template/runme.sh @@ -7,11 +7,11 @@ ANSIBLE_ROLES_PATH=../ ansible-playbook template.yml -i ../../inventory -v "$@" # Test for https://github.com/ansible/ansible/pull/35571 ansible testhost -i testhost, -m debug -a 'msg={{ hostvars["localhost"] }}' -e "vars1={{ undef() }}" -e "vars2={{ vars1 }}" -# Test for https://github.com/ansible/ansible/issues/27262 +# ansible_managed tests ANSIBLE_CONFIG=ansible_managed.cfg ansible-playbook ansible_managed.yml -i ../../inventory -v "$@" -# Test for https://github.com/ansible/ansible/pull/79129 -ANSIBLE_CONFIG=ansible_managed.cfg ansible-playbook ansible_managed_79129.yml -i ../../inventory -v "$@" +# same as above but with ansible_managed j2 template +ANSIBLE_CONFIG=ansible_managed_templated.cfg ansible-playbook ansible_managed.yml -i ../../inventory -v "$@" # Test for #42585 ANSIBLE_ROLES_PATH=../ ansible-playbook custom_template.yml -i ../../inventory -v "$@"