Commit 943acf7e authored by Mike Hommey's avatar Mike Hommey
Browse files

Bug 1259351 - Properly sandbox functions that are decorated with templates. r=nalexander

parent edcd74a9
Loading
Loading
Loading
Loading
+27 −3
Original line number Diff line number Diff line
@@ -234,7 +234,7 @@ class ConfigureSandbox(dict):

        if (not isinstance(value, DependsFunction) and
                value not in self._templates and
                not issubclass(value, Exception)):
                not (inspect.isclass(value) and issubclass(value, Exception))):
            raise KeyError('Cannot assign `%s` because it is neither a '
                           '@depends nor a @template' % key)

@@ -393,8 +393,32 @@ class ConfigureSandbox(dict):
            (k[:-len('_impl')], getattr(self, k))
            for k in dir(self) if k.endswith('_impl') and k != 'template_impl'
        )
        self._templates.add(template)
        return template

        # Any function argument to the template must be prepared to be sandboxed.
        # If the template itself returns a function (in which case, it's very
        # likely a decorator), that function must be prepared to be sandboxed as
        # well.
        def wrap_template(template):
            @wraps(template)
            def wrapper(*args, **kwargs):
                def maybe_prepare_function(obj):
                    if inspect.isfunction(obj):
                        func, _ = self._prepare_function(obj)
                        return func
                    return obj

                args = [maybe_prepare_function(arg) for arg in args]
                kwargs = {k: maybe_prepare_function(v)
                          for k, v in kwargs.iteritems()}
                ret = template(*args, **kwargs)
                if inspect.isfunction(ret):
                    return wrap_template(ret)
                return ret
            return wrapper

        wrapper = wrap_template(template)
        self._templates.add(wrapper)
        return wrapper

    def advanced_impl(self, func):
        '''Implementation of @advanced.
+44 −0
Original line number Diff line number Diff line
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

@template
def simple_decorator(func):
    return func

@template
def wrapper_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@template
def function_decorator(*args, **kwargs):
    # We could return wrapper_decorator from above here, but then we wouldn't
    # know if this works as expected because wrapper_decorator itself was
    # modified or because the right thing happened here.
    def wrapper_decorator(func):
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
    return wrapper_decorator

@depends('--help')
@simple_decorator
def foo(help):
    global FOO
    FOO = 1

@depends('--help')
@wrapper_decorator
def bar(help):
    global BAR
    BAR = 1

@depends('--help')
@function_decorator('a', 'b', 'c')
def qux(help):
    global QUX
    QUX = 1
+11 −0
Original line number Diff line number Diff line
@@ -259,6 +259,17 @@ class TestConfigure(unittest.TestCase):
        self.assertIn('PLATFORM', config)
        self.assertEquals(config['PLATFORM'], sys.platform)

    def test_decorators(self):
        config = {}
        out = StringIO()
        sandbox = ConfigureSandbox(config, {}, [], out, out)

        sandbox.exec_file(mozpath.join(test_data_path, 'decorators.configure'))

        self.assertNotIn('FOO', sandbox)
        self.assertNotIn('BAR', sandbox)
        self.assertNotIn('QUX', sandbox)

    def test_set_config(self):
        def get_config(*args):
            return self.get_config(*args, configure='set_config.configure')