Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ RestrictedPython
RestrictedPython is a tool that helps to define a subset of the Python language which allows to provide a program input into a trusted environment.
RestrictedPython is not a sandbox system or a secured environment, but it helps to define a trusted environment and execute untrusted code inside of it.

.. warning::

RestrictedPython only supports CPython. It does _not_ support PyPy and other Python implementations as it cannot provide its restrictions there.

For full documentation please see http://restrictedpython.readthedocs.io/ or the local ``docs/index``.

Example
Expand Down
11 changes: 5 additions & 6 deletions docs/CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ Changes
4.0b3 (unreleased)
------------------

- Nothing changed yet.

- Warn when using another Python implementation than CPython as it is not safe to use RestrictedPython with other versions than CPyton.
See https://bitbucket.org/pypy/pypy/issues/2653 for PyPy.

4.0b2 (2017-09-15)
------------------

- Fix regression in ``RestrictionCapableEval`` which broke when using list
comprehensions.
- Fix regression in ``RestrictionCapableEval`` which broke when using list comprehensions.


4.0b1 (2017-09-15)
Expand All @@ -31,8 +30,8 @@ Changes
`SelectCompiler.py`, `MutatingWorker.py`, `RestrictionMutator.py` and
`tests/verify.py`.

- Drop support of PyPy as there currently seems to be no way to restrict the
builtins. See https://bitbucket.org/pypy/pypy/issues/2653.
- Drop support for PyPy as there currently is no way to restrict the builtins.
See https://bitbucket.org/pypy/pypy/issues/2653.

- Remove ``__len__`` method in ``.Guards._write_wrapper`` because it is no
longer reachable by code using the wrapper.
Expand Down
6 changes: 6 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ Welcome to RestrictedPython's documentation!

.. include:: idea.rst

Supported Python versions
=========================

RestrictedPython support CPython 2.7, 3.4, 3.5 and 3.6.
It does _not_ support PyPy or other alternative Python implementations.

Contents
========

Expand Down
3 changes: 3 additions & 0 deletions src/RestrictedPython/_compat.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import platform
import sys


Expand All @@ -11,3 +12,5 @@
basestring = basestring # NOQA: F821 # Python 2 only built-in function
else:
basestring = str

IS_CPYTHON = platform.python_implementation() == 'CPython'
31 changes: 24 additions & 7 deletions src/RestrictedPython/compile.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from collections import namedtuple
from RestrictedPython._compat import IS_CPYTHON
from RestrictedPython._compat import IS_PY2
from RestrictedPython.transformer import RestrictingNodeTransformer

Expand All @@ -11,6 +12,11 @@
syntax_error_template = (
'Line {lineno}: {type}: {msg} in on statement: {statement}')

NOT_CPYTHON_WARNING = (
'RestrictedPython is only supported on CPython: use on other Python '
'implementations may create security issues.'
)


def _compile_restricted_mode(
source,
Expand All @@ -19,9 +25,14 @@ def _compile_restricted_mode(
flags=0,
dont_inherit=False,
policy=RestrictingNodeTransformer):

if not IS_CPYTHON:
warnings.warn_explicit(
NOT_CPYTHON_WARNING, RuntimeWarning, 'RestrictedPython', 0)

byte_code = None
errors = []
warnings = []
collected_errors = []
collected_warnings = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this refactoring have to do with the "not on PyPy" purpose of the PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The warnings variable shadows the warnings module which is now needed some lines after the variable definition. I did not want to change only the name of one variable.

used_names = {}
if policy is None:
# Unrestricted Source Checks
Expand All @@ -43,24 +54,30 @@ def _compile_restricted_mode(
try:
c_ast = ast.parse(source, filename, mode)
except (TypeError, ValueError) as e:
errors.append(str(e))
collected_errors.append(str(e))
except SyntaxError as v:
errors.append(syntax_error_template.format(
collected_errors.append(syntax_error_template.format(
lineno=v.lineno,
type=v.__class__.__name__,
msg=v.msg,
statement=v.text.strip()
))
if c_ast:
policy(errors, warnings, used_names).visit(c_ast)
if not errors:
policy_instance = policy(
collected_errors, collected_warnings, used_names)
policy_instance.visit(c_ast)
if not collected_errors:
byte_code = compile(c_ast, filename, mode=mode # ,
# flags=flags,
# dont_inherit=dont_inherit
)
else:
raise TypeError('Unallowed policy provided for RestrictedPython')
return CompileResult(byte_code, tuple(errors), warnings, used_names)
return CompileResult(
byte_code,
tuple(collected_errors),
collected_warnings,
used_names)


def compile_restricted_exec(
Expand Down
34 changes: 34 additions & 0 deletions tests/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from tests import c_single
from tests import e_eval

import platform
import pytest
import types

Expand Down Expand Up @@ -173,6 +174,9 @@ def test_compile_restricted():
with pytest.warns(SyntaxWarning) as record:
result = compile_restricted(PRINT_EXAMPLE, '<string>', 'exec')
assert isinstance(result, types.CodeType)
# Non-CPython versions have a RuntimeWarning, too.
if len(record) > 2: # pragma: no cover
record.pop()
assert len(record) == 2
assert record[0].message.args[0] == \
'Line 3: Print statement is deprecated ' \
Expand All @@ -193,3 +197,33 @@ def test_compile_restricted_eval():
with pytest.raises(SyntaxError,
message="Line 3: Eval calls are not allowed."):
compile_restricted(EVAL_EXAMPLE, '<string>', 'exec')


def test_compile___compile_restricted_mode__1(recwarn, mocker):
"""It warns when using another Python implementation than CPython."""
if platform.python_implementation() == 'CPython':
# Using CPython we have to fake the check:
mocker.patch('RestrictedPython.compile.IS_CPYTHON', new=False)
compile_restricted('42')
assert len(recwarn) == 1
w = recwarn.pop()
assert w.category == RuntimeWarning
assert str(w.message) == str(
'RestrictedPython is only supported on CPython: use on other Python '
'implementations may create security issues.'
)


@pytest.mark.skipif(
platform.python_implementation() == 'CPython',
reason='Warning only present if not CPython.')
def test_compile_CPython_warning(recwarn, mocker):
"""It warns when using another Python implementation than CPython."""
assert platform.python_implementation() != 'CPython'
with pytest.warns(RuntimeWarning) as record:
compile_restricted('42')
assert len(record) == 1
assert str(record[0].message) == str(
'RestrictedPython is only supported on CPython: use on other Python '
'implementations may create security issues.'
)