diff --git a/changelogs/fragments/run-command-expand-shell.yaml b/changelogs/fragments/run-command-expand-shell.yaml new file mode 100644 index 0000000000..44f50779e6 --- /dev/null +++ b/changelogs/fragments/run-command-expand-shell.yaml @@ -0,0 +1,5 @@ +minor_changes: +- run_command - Add a new keyword argument expand_user_and_vars, which defaults to True, + allowing the module author to decide whether or paths and variables + are expanded before running the command when use_unsafe_shell=False + (https://github.com/ansible/ansible/issues/45418) diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py index 85468515c3..9f5ec5bf20 100644 --- a/lib/ansible/module_utils/basic.py +++ b/lib/ansible/module_utils/basic.py @@ -2680,7 +2680,8 @@ class AnsibleModule(object): return self._clean def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None, - use_unsafe_shell=False, prompt_regex=None, environ_update=None, umask=None, encoding='utf-8', errors='surrogate_or_strict'): + use_unsafe_shell=False, prompt_regex=None, environ_update=None, umask=None, encoding='utf-8', errors='surrogate_or_strict', + expand_user_and_vars=True): ''' Execute a command, returns rc, stdout, and stderr. @@ -2718,6 +2719,11 @@ class AnsibleModule(object): python3 versions we support) otherwise a UnicodeError traceback will be raised. This does not affect transformations of strings given as args. + :kw expand_user_and_vars: When ``use_unsafe_shell=False`` this argument + dictates whether ``~`` is expanded in paths and environment variables + are expanded before running the command. When ``True`` a string such as + ``$SHELL`` will be expanded regardless of escaping. When ``False`` and + ``use_unsafe_shell=False`` no path or variable expansion will be done. :returns: A 3-tuple of return code (integer), stdout (native string), and stderr (native string). On python2, stdout and stderr are both byte strings. On python3, stdout and stderr are text strings converted @@ -2756,8 +2762,11 @@ class AnsibleModule(object): args = to_text(args, errors='surrogateescape') args = shlex.split(args) - # expand shellisms - args = [os.path.expanduser(os.path.expandvars(x)) for x in args if x is not None] + # expand ``~`` in paths, and all environment vars + if expand_user_and_vars: + args = [os.path.expanduser(os.path.expandvars(x)) for x in args if x is not None] + else: + args = [x for x in args if x is not None] prompt_re = None if prompt_regex: