From f5013b27aaaee39eb823c8501ffef24e3ca6312b Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Wed, 1 Feb 2017 14:55:53 +0100 Subject: [PATCH 1/3] Transform lambda tests. Remove an old test which was already covered by the lambda tests. --- .../tests/security_in_syntax.py | 4 - src/RestrictedPython/transformer.py | 2 +- tests/test_transformer.py | 87 ++++++++++++++----- 3 files changed, 68 insertions(+), 25 deletions(-) diff --git a/src/RestrictedPython/tests/security_in_syntax.py b/src/RestrictedPython/tests/security_in_syntax.py index f634485..ee25240 100644 --- a/src/RestrictedPython/tests/security_in_syntax.py +++ b/src/RestrictedPython/tests/security_in_syntax.py @@ -3,10 +3,6 @@ # Each function in this module is compiled using compile_restricted(). -def overrideGuardWithLambda(): - lambda o, _getattr=None: o - - def overrideGuardWithArgument(): def f(_getattr=None): pass diff --git a/src/RestrictedPython/transformer.py b/src/RestrictedPython/transformer.py index 7c5c75c..5ea76cf 100644 --- a/src/RestrictedPython/transformer.py +++ b/src/RestrictedPython/transformer.py @@ -1313,7 +1313,7 @@ def visit_FunctionDef(self, node): return node def visit_Lambda(self, node): - """Checks a lambda definition.""" + """Check a lambda definition.""" self.check_function_argument_names(node) node = self.node_contents_visit(node) diff --git a/tests/test_transformer.py b/tests/test_transformer.py index 4d32941..d2a68c6 100644 --- a/tests/test_transformer.py +++ b/tests/test_transformer.py @@ -851,42 +851,89 @@ def test_transformer__RestrictingNodeTransformer__visit_FunctionDef_2(compile, m _getiter_.reset_mock() -@pytest.mark.parametrize(*compile) -def test_transformer__RestrictingNodeTransformer__visit_Lambda_1(compile): - err_msg = 'Line 1: "_bad" is an invalid variable ' \ - 'name because it starts with "_"' +lambda_err_msg = 'Line 1: "_bad" is an invalid variable ' \ + 'name because it starts with "_"' + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_Lambda__1(compile): + """It prevents arguments starting with `_`.""" code, errors = compile("lambda _bad: None")[:2] + # RestrictedPython.compile.compile_restricted_exec on Python 2 renders + # the error message twice. This is necessary as otherwise *_bad and **_bad + # would be allowed. + assert lambda_err_msg in errors assert code is None - assert errors[0] == err_msg + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_Lambda__2(compile): + """It prevents keyword arguments starting with `_`.""" code, errors = compile("lambda _bad=1: None")[:2] + # RestrictedPython.compile.compile_restricted_exec on Python 2 renders + # the error message twice. This is necessary as otherwise *_bad and **_bad + # would be allowed. + assert lambda_err_msg in errors assert code is None - assert errors[0] == err_msg + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_Lambda__3(compile): + """It prevents * arguments starting with `_`.""" code, errors = compile("lambda *_bad: None")[:2] + assert errors == (lambda_err_msg,) assert code is None - assert errors[0] == err_msg + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_Lambda__4(compile): + """It prevents ** arguments starting with `_`.""" code, errors = compile("lambda **_bad: None")[:2] + assert errors == (lambda_err_msg,) assert code is None - assert errors[0] == err_msg - if IS_PY2: - # The old one did not support tuples at all. - if compile is RestrictedPython.compile.compile_restricted_exec: - code, errors = compile("lambda (a, _bad): None")[:2] - assert code is None - assert errors[0] == err_msg - code, errors = compile("lambda (a, (c, (_bad, c))): None")[:2] - assert code is None - assert errors[0] == err_msg +@pytest.mark.skipif( + IS_PY3, + reason="tuple parameter unpacking is gone in Python 3") +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_Lambda__5(compile): + """It prevents arguments starting with `_` in tuple unpacking.""" + # The old `compile` breaks with tuples in arguments: + if compile is RestrictedPython.compile.compile_restricted_exec: + code, errors = compile("lambda (a, _bad): None")[:2] + # RestrictedPython.compile.compile_restricted_exec on Python 2 renders + # the error message twice. This is necessary as otherwise *_bad and + # **_bad would be allowed. + assert lambda_err_msg in errors + assert code is None - if IS_PY3: - code, errors = compile("lambda good, *, _bad: None")[:2] + +@pytest.mark.skipif( + IS_PY3, + reason="tuple parameter unpacking is gone in Python 3") +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_Lambda__6(compile): + """It prevents arguments starting with `_` in nested tuple unpacking.""" + # The old `compile` breaks with tuples in arguments: + if compile is RestrictedPython.compile.compile_restricted_exec: + code, errors = compile("lambda (a, (c, (_bad, c))): None")[:2] + # RestrictedPython.compile.compile_restricted_exec on Python 2 renders + # the error message twice. This is necessary as otherwise *_bad and + # **_bad would be allowed. + assert lambda_err_msg in errors assert code is None - assert errors[0] == err_msg + + +@pytest.mark.skipif( + IS_PY2, + reason="There is no single `*` argument in Python 2") +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_Lambda__7(compile): + """It prevents arguments starting with `_` together with a single `*`.""" + code, errors = compile("lambda good, *, _bad: None")[:2] + assert errors == (lambda_err_msg,) + assert code is None @pytest.mark.skipif( From bef0f7f89d310d257110d37c129c1a1405da55c9 Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Wed, 1 Feb 2017 15:21:06 +0100 Subject: [PATCH 2/3] Transform `def` tests. Remove an old yes which was already tested using the new test code. --- .../tests/security_in_syntax.py | 5 - tests/test_transformer.py | 96 ++++++++++++++----- 2 files changed, 74 insertions(+), 27 deletions(-) diff --git a/src/RestrictedPython/tests/security_in_syntax.py b/src/RestrictedPython/tests/security_in_syntax.py index ee25240..2b80239 100644 --- a/src/RestrictedPython/tests/security_in_syntax.py +++ b/src/RestrictedPython/tests/security_in_syntax.py @@ -3,11 +3,6 @@ # Each function in this module is compiled using compile_restricted(). -def overrideGuardWithArgument(): - def f(_getattr=None): - pass - - def check_getattr_in_lambda(arg=lambda _getattr=(lambda ob, name: name): _getattr): 42 diff --git a/tests/test_transformer.py b/tests/test_transformer.py index d2a68c6..11ec7c4 100644 --- a/tests/test_transformer.py +++ b/tests/test_transformer.py @@ -326,7 +326,7 @@ def test_transformer__RestrictingNodeTransformer__visit_Attribute__7(compile, mo @pytest.mark.skipif(IS_PY2, reason="exec is a statement in Python 2") @pytest.mark.parametrize(*compile) -def test_transformer__RestrictingNodeTransformer__visit_Call__1(compile): +def test_transformer__RestrictingNodeTransformer__visit_Call__2(compile): """It is an error if the code call the `exec` function.""" code, errors, warnings, used_names = compile(EXEC_FUNCTION) assert ("Line 2: Exec calls are not allowed.",) == errors @@ -339,7 +339,7 @@ def no_eval(): @pytest.mark.parametrize(*compile) -def test_transformer__RestrictingNodeTransformer__visit_Call__2(compile): +def test_transformer__RestrictingNodeTransformer__visit_Call__3(compile): """It is an error if the code call the `eval` function.""" code, errors, warnings, used_names = compile(EVAL_FUNCTION) if compile is RestrictedPython.compile.compile_restricted_exec: @@ -757,42 +757,94 @@ def test_transformer__RestrictingNodeTransformer__visit_Call(compile, mocker): _apply_.reset_mock() -@pytest.mark.parametrize(*compile) -def test_transformer__RestrictingNodeTransformer__visit_FunctionDef_1(compile): - err_msg = 'Line 1: "_bad" is an invalid variable ' \ - 'name because it starts with "_"' +functiondef_err_msg = 'Line 1: "_bad" is an invalid variable ' \ + 'name because it starts with "_"' + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_FunctionDef__1( + compile): + """It prevents function arguments starting with `_`.""" code, errors = compile("def foo(_bad): pass")[:2] + # RestrictedPython.compile.compile_restricted_exec on Python 2 renders + # the error message twice. This is necessary as otherwise *_bad and **_bad + # would be allowed. + assert functiondef_err_msg in errors assert code is None - assert errors[0] == err_msg + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_FunctionDef__2( + compile): + """It prevents function keyword arguments starting with `_`.""" code, errors = compile("def foo(_bad=1): pass")[:2] + # RestrictedPython.compile.compile_restricted_exec on Python 2 renders + # the error message twice. This is necessary as otherwise *_bad and **_bad + # would be allowed. + assert functiondef_err_msg in errors assert code is None - assert errors[0] == err_msg + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_FunctionDef__3( + compile): + """It prevents function * arguments starting with `_`.""" code, errors = compile("def foo(*_bad): pass")[:2] + assert errors == (functiondef_err_msg,) assert code is None - assert errors[0] == err_msg + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_FunctionDef__4( + compile): + """It prevents function ** arguments starting with `_`.""" code, errors = compile("def foo(**_bad): pass")[:2] + assert errors == (functiondef_err_msg,) assert code is None - assert errors[0] == err_msg - if IS_PY2: - code, errors = compile("def foo((a, _bad)): pass")[:2] - assert code is None - assert errors[0] == err_msg - # The old one did not support nested checks. - if compile is RestrictedPython.compile.compile_restricted_exec: - code, errors = compile("def foo(a, (c, (_bad, c))): pass")[:2] - assert code is None - assert errors[0] == err_msg +@pytest.mark.skipif( + IS_PY3, + reason="tuple parameter unpacking is gone in Python 3") +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_FunctionDef__5( + compile): + """It prevents function arguments starting with `_` in tuples.""" + code, errors = compile("def foo((a, _bad)): pass")[:2] + # RestrictedPython.compile.compile_restricted_exec on Python 2 renders + # the error message twice. This is necessary as otherwise *_bad and **_bad + # would be allowed. + assert functiondef_err_msg in errors + assert code is None + - if IS_PY3: - code, errors = compile("def foo(good, *, _bad): pass")[:2] +@pytest.mark.skipif( + IS_PY3, + reason="tuple parameter unpacking is gone in Python 3") +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_FunctionDef__6( + compile): + """It prevents function arguments starting with `_` in tuples.""" + # The old `compile` breaks with tuples in function arguments: + if compile is RestrictedPython.compile.compile_restricted_exec: + code, errors = compile("def foo(a, (c, (_bad, c))): pass")[:2] + # RestrictedPython.compile.compile_restricted_exec on Python 2 renders + # the error message twice. This is necessary as otherwise *_bad and + # **_bad would be allowed. + assert functiondef_err_msg in errors assert code is None - assert errors[0] == err_msg + + +@pytest.mark.skipif( + IS_PY2, + reason="There is no single `*` argument in Python 2") +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_FunctionDef__7( + compile): + """It prevents `_` function arguments together with a single `*`.""" + code, errors = compile("def foo(good, *, _bad): pass")[:2] + assert errors == (functiondef_err_msg,) + assert code is None NESTED_SEQ_UNPACK = """ From f124cf96b681afc390a08ddc57e7aac118a9e0cc Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Wed, 1 Feb 2017 15:30:25 +0100 Subject: [PATCH 3/3] Port weird lambda test. --- src/RestrictedPython/tests/security_in_syntax.py | 5 ----- tests/test_transformer.py | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/RestrictedPython/tests/security_in_syntax.py b/src/RestrictedPython/tests/security_in_syntax.py index 2b80239..d7f905c 100644 --- a/src/RestrictedPython/tests/security_in_syntax.py +++ b/src/RestrictedPython/tests/security_in_syntax.py @@ -3,11 +3,6 @@ # Each function in this module is compiled using compile_restricted(). -def check_getattr_in_lambda(arg=lambda _getattr=(lambda ob, name: name): - _getattr): - 42 - - def except_using_bad_name(): try: foo diff --git a/tests/test_transformer.py b/tests/test_transformer.py index 11ec7c4..bdb90de 100644 --- a/tests/test_transformer.py +++ b/tests/test_transformer.py @@ -988,6 +988,22 @@ def test_transformer__RestrictingNodeTransformer__visit_Lambda__7(compile): assert code is None +BAD_ARG_IN_LAMBDA = """\ +def check_getattr_in_lambda(arg=lambda _bad=(lambda ob, name: name): _bad2): + 42 +""" + + +@pytest.mark.parametrize(*compile) +def test_transformer__RestrictingNodeTransformer__visit_Lambda__8(compile): + """It prevents arguments starting with `_` in weird lambdas.""" + code, errors = compile(BAD_ARG_IN_LAMBDA)[:2] + # RestrictedPython.compile.compile_restricted_exec finds both invalid + # names, while the old implementation seems to abort after the first. + assert lambda_err_msg in errors + assert code is None + + @pytest.mark.skipif( IS_PY3, reason="tuple parameter unpacking is gone in python 3")