|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# (c) 2015-2016, Toshio Kuratomi <tkuratomi@ansible.com>
|
|
|
|
#
|
|
|
|
# This file is part of Ansible
|
|
|
|
#
|
|
|
|
# Ansible is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# Ansible is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
# Make coding more python3-ish
|
|
|
|
from __future__ import (absolute_import, division)
|
|
|
|
__metaclass__ = type
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import json
|
|
|
|
|
|
|
|
from ansible.compat.tests import unittest
|
|
|
|
from units.mock.procenv import ModuleTestCase
|
|
|
|
from units.mock.generator import add_method
|
|
|
|
|
|
|
|
|
|
|
|
# Strings that should be converted into a typed value
|
|
|
|
VALID_STRINGS = (
|
|
|
|
[("'a'", 'a')],
|
|
|
|
[("'1'", '1')],
|
|
|
|
[("1", 1)],
|
|
|
|
[("True", True)],
|
|
|
|
[("False", False)],
|
|
|
|
[("{}", {})],
|
|
|
|
)
|
|
|
|
|
|
|
|
# Passing things that aren't strings should just return the object
|
|
|
|
NONSTRINGS = (
|
|
|
|
[({'a':1}, {'a':1})],
|
|
|
|
)
|
|
|
|
|
|
|
|
# These strings are not basic types. For security, these should not be
|
|
|
|
# executed. We return the same string and get an exception for some
|
|
|
|
INVALID_STRINGS = (
|
|
|
|
[("a=1", "a=1", SyntaxError)],
|
|
|
|
[("a.foo()", "a.foo()", None)],
|
|
|
|
[("import foo", "import foo", None)],
|
|
|
|
[("__import__('foo')", "__import__('foo')", ValueError)],
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def _check_simple_types(self, code, expected):
|
|
|
|
# test some basic usage for various types
|
|
|
|
self.assertEqual(self.am.safe_eval(code), expected)
|
|
|
|
|
|
|
|
def _check_simple_types_with_exceptions(self, code, expected):
|
|
|
|
# Test simple types with exceptions requested
|
|
|
|
self.assertEqual(self.am.safe_eval(code, include_exceptions=True), (expected, None))
|
|
|
|
|
|
|
|
def _check_invalid_strings(self, code, expected):
|
|
|
|
self.assertEqual(self.am.safe_eval(code), expected)
|
|
|
|
|
|
|
|
def _check_invalid_strings_with_exceptions(self, code, expected, exception):
|
|
|
|
res = self.am.safe_eval("a=1", include_exceptions=True)
|
|
|
|
self.assertEqual(res[0], "a=1")
|
|
|
|
self.assertEqual(type(res[1]), SyntaxError)
|
|
|
|
|
|
|
|
@add_method(_check_simple_types, *VALID_STRINGS)
|
|
|
|
@add_method(_check_simple_types, *NONSTRINGS)
|
|
|
|
@add_method(_check_simple_types_with_exceptions, *VALID_STRINGS)
|
|
|
|
@add_method(_check_simple_types_with_exceptions, *NONSTRINGS)
|
|
|
|
@add_method(_check_invalid_strings, *[[i[0][0:-1]] for i in INVALID_STRINGS])
|
|
|
|
@add_method(_check_invalid_strings_with_exceptions, *INVALID_STRINGS)
|
|
|
|
class TestSafeEval(ModuleTestCase):
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
super(TestSafeEval, self).setUp()
|
|
|
|
|
|
|
|
from ansible.module_utils import basic
|
|
|
|
self.old_ansible_args = basic._ANSIBLE_ARGS
|
|
|
|
|
|
|
|
basic._ANSIBLE_ARGS = None
|
|
|
|
self.am = basic.AnsibleModule(
|
|
|
|
argument_spec=dict(),
|
|
|
|
)
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
super(TestSafeEval, self).tearDown()
|
|
|
|
|
|
|
|
from ansible.module_utils import basic
|
|
|
|
basic._ANSIBLE_ARGS = self.old_ansible_args
|