Commit 9d48ad3f by Ned Batchelder

Updates to use the latest refactoring with edx-platform

* Python 2.x is called "python" again

* Provide "configure_python" so that edx-platform can get convenient
  configuration.
parent c62051af
...@@ -3,8 +3,12 @@ Integrate with application settings files. ...@@ -3,8 +3,12 @@ Integrate with application settings files.
""" """
from __future__ import absolute_import from __future__ import absolute_import
import os.path
from . import jail from . import jail
from . import limits from . import limits
from .util import sibling_sandbox_venv
def configure_from_settings(settings): def configure_from_settings(settings):
...@@ -57,12 +61,29 @@ def legacy_configure_from_settings(settings): ...@@ -57,12 +61,29 @@ def legacy_configure_from_settings(settings):
"user": "sandbox", "user": "sandbox",
"limits": {"CPU": 1}, "limits": {"CPU": 1},
} }
The virtualenv used depends on the 'python_bin' setting:
* If 'python_bin' is specified, it is the sandbox virtualenv to use.
* If 'python_bin' is specified as None, then code will run unsafely.
* If 'python_bin' isn't specified, then a virtualenv alongside the current
one, with a suffix of '-sandbox' will be used.
""" """
python_bin = None
if 'python_bin' in settings.CODE_JAIL:
python_bin = settings.CODE_JAIL['python_bin']
else:
venv = sibling_sandbox_venv()
if venv:
python_bin = os.path.join(venv, "bin/python")
python_bin = settings.CODE_JAIL.get('python_bin')
if python_bin: if python_bin:
user = settings.CODE_JAIL['user'] user = settings.CODE_JAIL['user']
jail.configure("python", python_bin, user=user) jail.configure("python", python_bin, user=user)
requested_limits = settings.CODE_JAIL.get('limits', {}) requested_limits = settings.CODE_JAIL.get('limits', {})
for name, value in requested_limits.items(): for name, value in requested_limits.items():
limits.set_limit(name, value) limits.set_limit(name, value)
...@@ -34,7 +34,7 @@ other = Language( ...@@ -34,7 +34,7 @@ other = Language(
) )
python2 = Language( python2 = Language(
name='python2', name='python',
argv=[ argv=[
'-E', # Ignore the environment variables PYTHON* '-E', # Ignore the environment variables PYTHON*
'-B', # Don't write .pyc files. '-B', # Don't write .pyc files.
......
...@@ -5,9 +5,10 @@ import os.path ...@@ -5,9 +5,10 @@ import os.path
import shutil import shutil
import sys import sys
from .exceptions import SafeExecException from . import languages
from .jail import get_codejail, is_configured from .exceptions import JailError, SafeExecException
from .util import temp_directory, change_directory, json_safe from .jail import configure, get_codejail, is_configured
from .util import temp_directory, change_directory, json_safe, sibling_sandbox_venv
log = logging.getLogger("codejail") log = logging.getLogger("codejail")
...@@ -94,16 +95,31 @@ def not_safe_exec( ...@@ -94,16 +95,31 @@ def not_safe_exec(
globals_dict.update(json_safe(g_dict)) globals_dict.update(json_safe(g_dict))
if ALWAYS_BE_UNSAFE: # pragma: no cover def configure_python():
# Make safe_exec actually call not_safe_exec, but log that we're doing so. """If "python" isn't configured, configure it to point to a sibling venv.
Raises JailError if it couldn't find a virtualenv to use.
"""
if not is_configured("python"):
venv = sibling_sandbox_venv()
if not venv:
raise JailError("Couldn't find sandbox virtualenv")
configure("python", os.path.join(venv, "bin/python"), user="sandbox", lang=languages.python2)
def safe_exec(*args, **kwargs): # pylint: disable=E0102
"""An actually-unsafe safe_exec, that warns it's being used."""
# Because it would be bad if this function were used in production, def fake_safe_exec(*args, **kwargs): # pylint: disable=E0102
# let's log a warning when it is used. Developers can live with """An actually-unsafe safe_exec, that warns it's being used."""
# one more log line.
slug = kwargs.get('slug', None)
log.warning("Using codejail/safe_exec.py:not_safe_exec for %s", slug)
return not_safe_exec(*args, **kwargs) # Because it would be bad if this function were used in production,
# let's log a warning when it is used. Developers can live with
# one more log line.
slug = kwargs.get('slug', None)
log.warning("Using codejail/safe_exec.py:not_safe_exec for %s", slug)
return not_safe_exec(*args, **kwargs)
if ALWAYS_BE_UNSAFE: # pragma: no cover
# Make safe_exec actually call not_safe_exec, but log that we're doing so.
safe_exec = fake_safe_exec
...@@ -7,8 +7,8 @@ import os.path ...@@ -7,8 +7,8 @@ import os.path
import sys import sys
from unittest import TestCase from unittest import TestCase
from codejail import jail from codejail import jail, languages
from codejail import languages from codejail.util import sibling_sandbox_venv
SAME = object() SAME = object()
...@@ -53,24 +53,15 @@ class JailMixin(TestCase): ...@@ -53,24 +53,15 @@ class JailMixin(TestCase):
super(JailMixin, self).setUp() super(JailMixin, self).setUp()
if not jail.is_configured("python"): if not jail.is_configured("python"):
if not self._codejail_venv: if not self._codejail_venv:
self._codejail_venv = self._autoconfigure_codejail_venv() self._codejail_venv = sibling_sandbox_venv()
if not self._codejail_venv:
self.fail("No virtualenv found for codejail")
if not self._codejail_user: if not self._codejail_user:
# User explicitly requested no su user via environment variable # User explicitly requested no su user via environment variable
self._codejail_user = None self._codejail_user = None
bin_path = os.path.join(self._codejail_venv, 'bin/python2') bin_path = os.path.join(self._codejail_venv, 'bin/python')
jail.configure("python", bin_path, user=self._codejail_user, lang=languages.python2) jail.configure("python", bin_path, user=self._codejail_user, lang=languages.python2)
def _autoconfigure_codejail_venv(self):
"""
For the purposes of tests, look for a sandbox alongside the currently
running python.
"""
codejail_venv = '{}-sandbox'.format(sys.prefix)
if os.path.isdir(codejail_venv):
return codejail_venv
else:
self.fail("No virtualenv found for codejail")
class Python3Mixin(object): class Python3Mixin(object):
""" """
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import contextlib import contextlib
import os import os
import shutil import shutil
import sys
import tempfile import tempfile
try: try:
...@@ -67,3 +68,19 @@ def json_safe(input_dict): ...@@ -67,3 +68,19 @@ def json_safe(input_dict):
else: else:
json_dict[key] = value json_dict[key] = value
return json.loads(json.dumps(json_dict)) return json.loads(json.dumps(json_dict))
def sibling_sandbox_venv():
"""
Find a virtualenv next to ours, with a "-sandbox" suffix.
Returns the virtualenv directory name, or None if one couldn't be found.
"""
sandbox_venv = '{}-sandbox'.format(sys.prefix)
if os.path.isdir(sandbox_venv):
python_bin = os.path.join(sandbox_venv, "bin/python")
if os.path.exists(python_bin):
return sandbox_venv
return None
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment