def test_type_bases(): from sys import version_info if version_info < (2, 6): raise SkipTest("tests disabled on Python < 2.6") def test(): class A(object): pass class B(object): pass class X(A): pass X.__bases__ = (B, ) if not issubclass(X, B): raise SandboxError("yep") def sandbox_test(): try: test() except SandboxError: pass else: assert False createSandbox().call(sandbox_test) test()
def test_builtins_init(): import warnings code = unindent(''' def check_init(): __builtins__.__init__({}) def check_dict_init(): try: dict.__init__(__builtins__, {}) except ImportError as err: assert str(err) == 'Import "_warnings" blocked by the sandbox' except DeprecationWarning as err: assert str(err) == 'object.__init__() takes no parameters' else: assert False ''') unsafe_code = code + unindent(''' check_init() ''') try: createSandbox().execute(unsafe_code) except SandboxError as err: assert str(err) == "Read only object", str(err) else: assert False
def test_sytem_exit(): def system_exit_denied(): try: raise SystemExit() except NameError as err: assert str(err) == "global name 'SystemExit' is not defined" except: assert False createSandbox().call(system_exit_denied) config = createSandboxConfig("exit") def system_exit_allowed(): try: raise SystemExit() except SystemExit: pass else: assert False Sandbox(config).call(system_exit_allowed) try: raise SystemExit() except SystemExit: pass else: assert False
def test_type_bases(): from sys import version_info if version_info < (2, 6): raise SkipTest("tests disabled on Python < 2.6") code = unindent(''' def test(): class A(object): pass class B(object): pass class X(A): pass X.__bases__ = (B,) if not issubclass(X, B): raise AttributeError("__bases__ error") ''') unsafe_code = code + unindent(''' try: test() except AttributeError, err: assert str(err) == "__bases__ error" else: assert False ''') createSandbox().execute(unsafe_code) safe_code = code + unindent(''' test() ''') execute_code(safe_code)
def test_exit(): def exit_noarg(): try: exit() except SandboxError as err: assert str(err) == "exit() function blocked by the sandbox" else: assert False createSandbox().call(exit_noarg) config = createSandboxConfig("exit") def exit_1(): try: exit(1) except SystemExit as err: assert err.args[0] == 1 else: assert False import sys try: sys.exit("bye") except SystemExit as err: assert err.args[0] == "bye" else: assert False Sandbox(config).call(exit_1)
def test_func_globals(): code = unindent(''' SECRET = 42 def get_secret_from_func_globals(): def mysum(a, b): return a+b try: func_globals = mysum.func_globals except AttributeError: # Python 2.6+ func_globals = mysum.__globals__ return func_globals['SECRET'] ''') unsafe_code = code + unindent(''' try: get_secret_from_func_globals() except AttributeError, err: assert str(err) == "'function' object has no attribute '__globals__'" else: assert False ''') createSandbox().execute(unsafe_code) safe_code = code + unindent(""" assert get_secret_from_func_globals() == 42 """) execute_code(safe_code)
def test_builtins_init(): import warnings code = unindent(''' def check_init(): __builtins__.__init__({}) def check_dict_init(): try: dict.__init__(__builtins__, {}) except ImportError, err: assert str(err) == 'Import "_warnings" blocked by the sandbox' except DeprecationWarning, err: assert str(err) == 'object.__init__() takes no parameters' else: assert False ''') unsafe_code = code + unindent(''' check_init() ''') try: createSandbox().execute(unsafe_code) except SandboxError, err: assert str(err) == "Read only object", str(err)
def test_func_locals(): # FIXME: rewrite test with a simpler trace, without safe_import def get_import_from_func_locals(safe_import, exc_info): try: safe_import("os") except ImportError: # import os always raise an error err_value, err_type, try_traceback = exc_info() safe_import_traceback = try_traceback.tb_next safe_import_frame = safe_import_traceback.tb_frame return safe_import_frame.f_locals['__import__'] import sys def frame_locals_denied(): try: get_import_from_func_locals(__import__, sys.exc_info) except AttributeError as err: assert str(err) == "'frame' object has no attribute 'f_locals'" else: assert False # FIXME: use sandbox.execute() createSandbox().call(frame_locals_denied) builtin_import = __import__ from sandbox.safe_import import _safe_import safe_import = _safe_import(builtin_import, {}) myimport = get_import_from_func_locals(safe_import, sys.exc_info) assert myimport is builtin_import
def test_builtins_setitem(): code = unindent(''' def builtins_superglobal(): if isinstance(__builtins__, dict): __builtins__['SUPERGLOBAL'] = 42 assert SUPERGLOBAL == 42 del __builtins__['SUPERGLOBAL'] else: __builtins__.SUPERGLOBAL = 42 assert SUPERGLOBAL == 42 del __builtins__.SUPERGLOBAL ''') unsafe_code = code + unindent(''' try: builtins_superglobal() except SandboxError as err: assert str(err) == "Read only object" else: assert False ''') createSandbox().execute(unsafe_code) safe_code = code + unindent(''' builtins_superglobal() ''') execute_code(safe_code)
def test_builtins_setitem(): code = unindent(''' def builtins_superglobal(): if isinstance(__builtins__, dict): __builtins__['SUPERGLOBAL'] = 42 assert SUPERGLOBAL == 42 del __builtins__['SUPERGLOBAL'] else: __builtins__.SUPERGLOBAL = 42 assert SUPERGLOBAL == 42 del __builtins__.SUPERGLOBAL ''') unsafe_code = code + unindent(''' try: builtins_superglobal() except SandboxError, err: assert str(err) == "Read only object" else: assert False ''') createSandbox().execute(unsafe_code) safe_code = code + unindent(''' builtins_superglobal() ''') execute_code(safe_code)
def test_type_bases(): from sys import version_info if version_info < (2, 6): raise SkipTest("tests disabled on Python < 2.6") def test(): class A(object): pass class B(object): pass class X(A): pass X.__bases__ = (B,) if not issubclass(X, B): raise SandboxError("yep") def sandbox_test(): try: test() except SandboxError: pass else: assert False createSandbox().call(sandbox_test) test()
def test_import(): def import_blocked(): try: import os except ImportError as err: assert str(err) == 'Import "os" blocked by the sandbox' else: assert False createSandbox().call(import_blocked) # import is allowed outside the sandbox import os
def test_object_proxy_read(): class Person: __doc__ = 'Person doc' def __str__(self): "Convert to string" return "str" def __repr__(self): return "repr" def __hash__(self): return 42 person = Person() def testPerson(person): assert person.__doc__ == 'Person doc' assert person.__str__() == "str" assert person.__repr__() == "repr" assert person.__hash__() == 42 assert person.__str__.__name__ == "__str__" assert person.__str__.__doc__ == "Convert to string" testPerson(person) sandbox = createSandbox() sandbox.call(testPerson, person)
def test_open_denied(): from errno import EACCES def access_denied(): try: read_first_line(open) except IOError as err: if err.errno == EACCES: # safe_open() error assert err.args[1].startswith('Sandbox deny access to the file ') else: # restricted python error assert str(err) == 'file() constructor not accessible in restricted mode' else: assert False createSandbox().call(access_denied) read_first_line(open)
def test_modify_builtins_dict(): code = unindent(''' def builtins_dict_superglobal(): __builtins__['SUPERGLOBAL'] = 42 assert SUPERGLOBAL == 42 del __builtins__['SUPERGLOBAL'] ''') unsafe_code = code + unindent(''' try: builtins_dict_superglobal() except AttributeError, err: assert str(err) == "type object 'dict' has no attribute '__setitem__'" else: assert False ''') try: createSandbox().execute(unsafe_code) except SandboxError, err: assert str(err) == "Read only object"
def test_object_proxy_delattr(): # Delete attribute def delAttr(person): del person.name person = Person("haypo") sandbox = createSandbox() try: sandbox.call(delAttr, person) except SandboxError, err: assert str(err) == 'Read only object'
def test_modify_builtins_dict(): code = unindent(''' def builtins_dict_superglobal(): __builtins__['SUPERGLOBAL'] = 42 assert SUPERGLOBAL == 42 del __builtins__['SUPERGLOBAL'] ''') unsafe_code = code + unindent(''' try: builtins_dict_superglobal() except AttributeError as err: assert str(err) == "type object 'dict' has no attribute '__setitem__'" else: assert False ''') try: createSandbox().execute(unsafe_code) except SandboxError as err: assert str(err) == "Read only object"
def test_object_proxy_setattr(): # Attribute def setAttr(person): person.name = "victor" person = Person("haypo") sandbox = createSandbox() try: sandbox.call(setAttr, person) except SandboxError, err: assert str(err) == 'Read only object'
def test_subclasses(): if version_info >= (3, 0): raise SkipTest("Python 3 has not file type") def get_file_type_from_subclasses(): for subtype in object.__subclasses__(): if subtype.__name__ == "file": return subtype raise ValueError("Unable to get file type") def subclasses_denied(): try: get_file_type_from_subclasses() except AttributeError as err: assert str(err) == "type object 'object' has no attribute '__subclasses__'" else: assert False createSandbox().call(subclasses_denied) file_type = get_file_type_from_subclasses() read_first_line(file_type)
def test_write_file(): from tempfile import mktemp def write_file(filename): with open(filename, "w") as fp: fp.write("test") filename = mktemp() def write_denied(filename): try: write_file(filename) except ValueError as err: assert str(err) == "Only read modes are allowed." except IOError as err: assert str(err) == "file() constructor not accessible in restricted mode" else: assert False, "writing to a file is not blocked" createSandbox().call(write_denied, filename) filename = mktemp() write_file(filename) os.unlink(filename)
def test_object_proxy_dict(): if not HAVE_CSANDBOX: # restricted python blocks access to instance.__dict__ raise SkipTest("require _sandbox") # Dictionary def setDict(person): person.__dict__['name'] = "victor" person = Person("haypo") sandbox = createSandbox() try: sandbox.call(setDict, person) except SandboxError, err: assert str(err) == 'Read only object'
def test_closure(): code = unindent(''' def read_closure_secret(): def createClosure(secret): def closure(): return secret return closure func = createClosure(42) try: cell = func.func_closure[0] except AttributeError: # Python 2.6+ cell = func.__closure__[0] # Does Python < 2.5 have the cell_contents attribute? See this recipe, # get_cell_value(), for version without the attribute: # http://code.activestate.com/recipes/439096/ secret = cell.cell_contents assert secret == 42 ''') # Begin by a test outside the sandbox to fill the type cache unsafe_code = code + unindent(''' try: read_closure_secret() except AttributeError, err: assert str(err) == "'function' object has no attribute '__closure__'" else: assert False, "func_closure is present" ''') createSandbox().execute(unsafe_code) # Repeat the test to ensure that the attribute cache is cleared correctly safe_code = code + unindent(''' read_closure_secret() ''') execute_code(safe_code)
def test_regex(): def check_regex(): import re assert re.escape('+') == '\\+' assert re.match('a+', 'aaaa').group(0) == 'aaaa' # FIXME: Remove this workaround: list(...) assert list(re.findall('.', 'abc')) == ['a', 'b', 'c'] assert re.search('a+', 'aaaa').group(0) == 'aaaa' # FIXME: Remove this workaround: list(...) assert list(re.split(' +', 'a b c')) == ['a', 'b', 'c'] assert re.sub('a+', '#', 'a b aa c') == '# b # c' sandbox = createSandbox('regex') sandbox.call(check_regex) check_regex()
def test_regex(): def check_regex(): import re assert re.escape("+") == "\\+" assert re.match("a+", "aaaa").group(0) == "aaaa" # FIXME: Remove this workaround: list(...) assert list(re.findall(".", "abc")) == ["a", "b", "c"] assert re.search("a+", "aaaa").group(0) == "aaaa" # FIXME: Remove this workaround: list(...) assert list(re.split(" +", "a b c")) == ["a", "b", "c"] assert re.sub("a+", "#", "a b aa c") == "# b # c" sandbox = createSandbox("regex") sandbox.call(check_regex) check_regex()
def test_func_defaults(): from sys import version_info if version_info < (2, 6): raise SkipTest("tests disabled on Python < 2.6") unsafe_code = unindent(''' try: open.__defaults__ except AttributeError, err: assert str(err) in ( # open is safe_open() "'function' object has no attribute '__defaults__'", # builtin open() in restricted mode "'builtin_function_or_method' object has no attribute '__defaults__'", ) else: assert False ''') if version_info < (3, 0): unsafe_code += unindent(''' try: open.func_defaults except AttributeError, err: assert str(err) in ( # open is safe_open() "'function' object has no attribute 'func_defaults'", # builtin open() in restricted mode "'builtin_function_or_method' object has no attribute 'func_defaults'", ) else: assert False ''') sandbox = createSandbox() sandbox.execute(unsafe_code)
from sandbox import Sandbox, SandboxError from sandbox.test import createSandbox, createSandboxConfig def test_import(): def import_blocked(): try: import os except ImportError, err: assert str(err) == 'Import "os" blocked by the sandbox' else: assert False createSandbox().call(import_blocked) # import is allowed outside the sandbox import os def test_import_whitelist(): # sys.version is allowed by the sandbox import sys sys_version = sys.version del sys config = createSandboxConfig() config.allowModule('sys', 'version') def import_sys(): import sys assert sys.__name__ == 'sys' assert sys.version == sys_version Sandbox(config).call(import_sys) def test_readonly_import():
try: read_first_line(open) except IOError, err: if err.errno == EACCES: # safe_open() error assert err.args[1].startswith( 'Sandbox deny access to the file ') else: # restricted python error assert str( err ) == 'file() constructor not accessible in restricted mode' else: assert False createSandbox().call(access_denied) read_first_line(open) def test_open_whitelist(): if not HAVE_CSANDBOX: # restricted python denies access to all files raise SkipTest("require _sandbox") config = createSandboxConfig() config.allowPath(READ_FILENAME) Sandbox(config).call(read_first_line, open) def test_write_file():
def valid_code(): assert 1 + 2 == 3 createSandbox().call(valid_code) def test_exit(): def exit_noarg(): try: exit() except SandboxError, err: assert str(err) == "exit() function blocked by the sandbox" else: assert False createSandbox().call(exit_noarg) config = createSandboxConfig("exit") def exit_1(): try: exit(1) except SystemExit, err: assert err.args[0] == 1 else: assert False import sys try: sys.exit("bye")
assert SUPERGLOBAL == 42 del __builtins__['SUPERGLOBAL'] else: __builtins__.SUPERGLOBAL = 42 assert SUPERGLOBAL == 42 del __builtins__.SUPERGLOBAL def readonly_builtins(): try: builtins_superglobal() except SandboxError, err: assert str(err) == "Read only object" else: assert False createSandbox().call(readonly_builtins) builtins_superglobal() def test_builtins_init(): import warnings def check_init(): __builtins__.__init__({}) def check_dict_init(): try: dict.__init__(__builtins__, {}) except ImportError, err: assert str(err) == 'Import "_warnings" blocked by the sandbox'
def test_valid_code(): def valid_code(): assert 1 + 2 == 3 createSandbox().call(valid_code)
err_value, err_type, try_traceback = exc_info() safe_import_traceback = try_traceback.tb_next safe_import_frame = safe_import_traceback.tb_frame return safe_import_frame.f_locals['__import__'] import sys def frame_locals_denied(): try: get_import_from_func_locals(__import__, sys.exc_info) except AttributeError, err: assert str(err) == "'frame' object has no attribute 'f_locals'" else: assert False # FIXME: use sandbox.execute() createSandbox().call(frame_locals_denied) builtin_import = __import__ from sandbox.safe_import import _safe_import safe_import = _safe_import(builtin_import, {}) myimport = get_import_from_func_locals(safe_import, sys.exc_info) assert myimport is builtin_import def test_func_defaults(): from sys import version_info if version_info < (2, 6): raise SkipTest("tests disabled on Python < 2.6") unsafe_code = unindent(''' try:
def valid_code(): assert 1 + 2 == 3 createSandbox().call(valid_code) def test_exit(): def exit_noarg(): try: exit() except SandboxError, err: assert str(err) == "exit() function blocked by the sandbox" else: assert False createSandbox().call(exit_noarg) config = createSandboxConfig("exit") def exit_1(): try: exit(1) except SystemExit, err: assert err.args[0] == 1 else: assert False import sys try: sys.exit("bye") except SystemExit, err:
__builtins__['SUPERGLOBAL'] = 42 assert SUPERGLOBAL == 42 del __builtins__['SUPERGLOBAL'] else: __builtins__.SUPERGLOBAL = 42 assert SUPERGLOBAL == 42 del __builtins__.SUPERGLOBAL def readonly_builtins(): try: builtins_superglobal() except SandboxError, err: assert str(err) == "Read only object" else: assert False createSandbox().call(readonly_builtins) builtins_superglobal() def test_builtins_init(): import warnings def check_init(): try: __builtins__.__init__({}) except SandboxError, err: assert str(err) == "Read only object" else: assert False def check_dict_init():
def test_func_code(): sandbox = createSandbox() try: sandbox.call(replace_func_code) except AttributeError, err: assert str(err) == "'function' object has no attribute '__code__'"
# get_cell_value(), for version without the attribute: # http://code.activestate.com/recipes/439096/ secret = cell.cell_contents assert secret == 42 def check_closure(): try: read_closure_secret() except AttributeError, err: assert str(err) == "'function' object has no attribute '__closure__'" else: assert False, "func_closure is present" # Begin by a test outside the sandbox to fill the type cache read_closure_secret() createSandbox().call(check_closure) # Repeat the test to ensure that the attribute cache is cleared correctly read_closure_secret() createSandbox().call(check_closure) def test_func_globals(): def func_globals_denied(): try: get_secret_from_func_globals() except AttributeError, err: assert str(err) == "'function' object has no attribute '__globals__'" else: assert False createSandbox().call(func_globals_denied)
# http://code.activestate.com/recipes/439096/ secret = cell.cell_contents assert secret == 42 def check_closure(): try: read_closure_secret() except AttributeError, err: assert str( err) == "'function' object has no attribute '__closure__'" else: assert False, "func_closure is present" # Begin by a test outside the sandbox to fill the type cache read_closure_secret() createSandbox().call(check_closure) # Repeat the test to ensure that the attribute cache is cleared correctly read_closure_secret() createSandbox().call(check_closure) def test_func_globals(): def func_globals_denied(): try: get_secret_from_func_globals() except AttributeError, err: assert str( err) == "'function' object has no attribute '__globals__'" else: assert False
from errno import EACCES def access_denied(): try: read_first_line(open) except IOError, err: if err.errno == EACCES: # safe_open() error assert err.args[1].startswith("Sandbox deny access to the file ") else: # restricted python error assert str(err) == "file() constructor not accessible in restricted mode" else: assert False createSandbox().call(access_denied) read_first_line(open) def test_open_whitelist(): config = createSandboxConfig() if config.cpython_restricted: # the CPython restricted mode denies to open any file raise SkipTest("require _sandbox") config.allowPath(READ_FILENAME) Sandbox(config).call(read_first_line, open) def test_write_file(): def write_file(filename):