Repository: ansible/ansible

Issue:
set_fact ansible_ssh_common_args fails
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
set_fact

##### ANSIBLE VERSION
```
ansible 2.5.0b2 (stable-2.5 980b6a00e2) last updated 2018/02/22 12:15:16 (GMT -400)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/seit31/ansible/lib/ansible
  executable location = /home/seit31/ansible/bin/ansible
  python version = 2.7.5 (default, Nov 20 2015, 02:00:19) [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)]
```

##### CONFIGURATION
ANSIBLE_PIPELINING(/etc/ansible/ansible.cfg) = False
ANSIBLE_SSH_ARGS(/etc/ansible/ansible.cfg) = -C -o ControlMaster=auto -o ControlPersist=600s
ANSIBLE_SSH_CONTROL_PATH(/etc/ansible/ansible.cfg) = /tmp/%%h-%%p-%%r
ANSIBLE_SSH_CONTROL_PATH_DIR(/etc/ansible/ansible.cfg) = /tmp
DEFAULT_FILTER_PLUGIN_PATH(/etc/ansible/ansible.cfg) = [u'/etc/ansible/filter_plugins']
DEFAULT_FORKS(/etc/ansible/ansible.cfg) = 5
DEFAULT_LOG_PATH(/etc/ansible/ansible.cfg) = /var/log/ansible.log
DEFAULT_ROLES_PATH(/etc/ansible/ansible.cfg) = [u'/etc/ansible/roles', u'/usr/share/ansible/roles']
HOST_KEY_CHECKING(/etc/ansible/ansible.cfg) = False
PERSISTENT_CONNECT_TIMEOUT(/etc/ansible/ansible.cfg) = 30
RETRY_FILES_ENABLED(/etc/ansible/ansible.cfg) = False

##### OS / ENVIRONMENT
N/A

##### SUMMARY
Attempting to set ansible_ssh_common_args mid-play using set_fact prints a warning and doesn't save the variable:

[WARNING]: Removed restricted key from module data: ansible_ssh_common_args = -o ProxyComma ... 0.104'

##### STEPS TO REPRODUCE
```yaml
  - name: set ssh jump host args
    set_fact:
      ansible_ssh_common_args: "-o ProxyCommand='ssh -W %h:%p -q root@{{ hostvars[groups['router'][0]]['ansible_host'] }}'"
```

##### EXPECTED RESULTS

##### ACTUAL RESULTS



Discussion:
Files identified in the description:
* [lib/ansible/modules/utilities/logic/set_fact.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/utilities/logic/set_fact.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @dagwieers
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
cc @agaffney 
This appears to be happening as a side effect of the code to prevent malicious overriding of connection vars via facts returned from a compromised host. This happens in the `_execute()` function in `lib/ansible/executor/task_executor.py` when the returned facts are passed through `clean_vars()`.

This could be fixed with an exception for `set_fact` (or maybe even all action plugins) in that code, but I'm not sure if that's the "right" way to do it.
It looks like this may be a regression in 2.5/devel. I cannot reproduce this in 2.4.3, but I can reproduce with `devel` from a few weeks ago. However, with `devel`, I get the warning but it still sets the var.

Resolving patch:
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -593,7 +593,7 @@ def _evaluate_failed_when_result(result):
                     failed_when_result = False
                 return failed_when_result
 
-            if 'ansible_facts' in result:
+            if 'ansible_facts' in result and self._task.action not in ('set_fact', 'include_vars'):
                 vars_copy.update(namespace_facts(result['ansible_facts']))
                 if C.INJECT_FACTS_AS_VARS:
                     vars_copy.update(clean_facts(result['ansible_facts']))
@@ -651,7 +651,7 @@ def _evaluate_failed_when_result(result):
         if self._task.register:
             variables[self._task.register] = wrap_var(result)
 
-        if 'ansible_facts' in result:
+        if 'ansible_facts' in result and self._task.action not in ('set_fact', 'include_vars'):
             variables.update(namespace_facts(result['ansible_facts']))
             if C.INJECT_FACTS_AS_VARS:
                 variables.update(clean_facts(result['ansible_facts']))


Test patch: