Commit 5a5b9f21 by James Cammarata

Validate variable names when loading 'vars:' blocks

TODO: add this to VariableManager to validate vars loaded from files too

Fixes #12022
parent 266a069a
...@@ -37,7 +37,7 @@ from ansible.playbook.attribute import Attribute, FieldAttribute ...@@ -37,7 +37,7 @@ from ansible.playbook.attribute import Attribute, FieldAttribute
from ansible.template import Templar from ansible.template import Templar
from ansible.utils.boolean import boolean from ansible.utils.boolean import boolean
from ansible.utils.debug import debug from ansible.utils.debug import debug
from ansible.utils.vars import combine_vars from ansible.utils.vars import combine_vars, isidentifier
from ansible.template import template from ansible.template import template
class Base: class Base:
...@@ -379,14 +379,21 @@ class Base: ...@@ -379,14 +379,21 @@ class Base:
list into a single dictionary. list into a single dictionary.
''' '''
def _validate_variable_keys(ds):
for key in ds:
if not isidentifier(key):
raise TypeError("%s is not a valid variable name" % key)
try: try:
if isinstance(ds, dict): if isinstance(ds, dict):
_validate_variable_keys(ds)
return ds return ds
elif isinstance(ds, list): elif isinstance(ds, list):
all_vars = dict() all_vars = dict()
for item in ds: for item in ds:
if not isinstance(item, dict): if not isinstance(item, dict):
raise ValueError raise ValueError
_validate_variable_keys(item)
all_vars = combine_vars(all_vars, item) all_vars = combine_vars(all_vars, item)
return all_vars return all_vars
elif ds is None: elif ds is None:
...@@ -395,6 +402,8 @@ class Base: ...@@ -395,6 +402,8 @@ class Base:
raise ValueError raise ValueError
except ValueError: except ValueError:
raise AnsibleParserError("Vars in a %s must be specified as a dictionary, or a list of dictionaries" % self.__class__.__name__, obj=ds) raise AnsibleParserError("Vars in a %s must be specified as a dictionary, or a list of dictionaries" % self.__class__.__name__, obj=ds)
except TypeError, e:
raise AnsibleParserError("Invalid variable name in vars specified for %s: %s" % (self.__class__.__name__, e), obj=ds)
def _extend_value(self, value, new_value): def _extend_value(self, value, new_value):
''' '''
......
...@@ -14,47 +14,16 @@ ...@@ -14,47 +14,16 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
import ast
from six import string_types
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
from ansible.plugins.action import ActionBase from ansible.plugins.action import ActionBase
from ansible.utils.boolean import boolean from ansible.utils.boolean import boolean
from ansible.utils.vars import isidentifier
def isidentifier(ident):
"""
Determines, if string is valid Python identifier using the ast module.
Orignally posted at: http://stackoverflow.com/a/29586366
"""
if not isinstance(ident, string_types):
return False
try:
root = ast.parse(ident)
except SyntaxError:
return False
if not isinstance(root, ast.Module):
return False
if len(root.body) != 1:
return False
if not isinstance(root.body[0], ast.Expr):
return False
if not isinstance(root.body[0].value, ast.Name):
return False
if root.body[0].value.id != ident:
return False
return True
class ActionModule(ActionBase): class ActionModule(ActionBase):
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
import ast
from six import string_types
from ansible import constants as C from ansible import constants as C
from ansible.parsing.splitter import parse_kv from ansible.parsing.splitter import parse_kv
...@@ -66,3 +69,35 @@ def load_extra_vars(loader, options): ...@@ -66,3 +69,35 @@ def load_extra_vars(loader, options):
data = parse_kv(extra_vars_opt) data = parse_kv(extra_vars_opt)
extra_vars = combine_vars(extra_vars, data) extra_vars = combine_vars(extra_vars, data)
return extra_vars return extra_vars
def isidentifier(ident):
"""
Determines, if string is valid Python identifier using the ast module.
Orignally posted at: http://stackoverflow.com/a/29586366
"""
if not isinstance(ident, string_types):
return False
try:
root = ast.parse(ident)
except SyntaxError:
return False
if not isinstance(root, ast.Module):
return False
if len(root.body) != 1:
return False
if not isinstance(root.body[0], ast.Expr):
return False
if not isinstance(root.body[0].value, ast.Name):
return False
if root.body[0].value.id != ident:
return False
return True
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment