feat: Codejail as external service (optional)

Add codejail service settings (endpoint and feature flag).
Add conditional to allow running codejail using a REST API service when flag is enabled.
This commit is contained in:
Eric Herrera
2021-08-01 09:19:23 -05:00
parent 04492c28f8
commit 3a736eefa2
2 changed files with 73 additions and 20 deletions

View File

@@ -2,10 +2,13 @@
import hashlib
import requests
import json
from codejail.safe_exec import SafeExecException, json_safe
from codejail.safe_exec import not_safe_exec as codejail_not_safe_exec
from codejail.safe_exec import safe_exec as codejail_safe_exec
from django.conf import settings
from edx_django_utils.monitoring import function_trace
import six
from six import text_type
@@ -143,28 +146,63 @@ def safe_exec(
# Create the complete code we'll run.
code_prolog = CODE_PROLOG % random_seed
# Decide which code executor to use.
if unsafely:
exec_fn = codejail_not_safe_exec
if settings.FEATURES.get('ENABLE_CODEJAIL_REST_SERVICE', False):
try:
codejail_service_endpoint = "".join([
settings.CODE_JAIL_REST_SERVICE_HOST,
"/api/v0/code-exec"
])
data = {
"code": code_prolog + LAZY_IMPORTS + code,
"globals_dict": globals_dict,
"python_path": python_path,
"limit_overrides_context": limit_overrides_context,
"slug": slug,
"unsafely": unsafely
}
datajson = json.dumps(data)
response = requests.request(
"POST",
codejail_service_endpoint,
files=extra_files,
data={'payload': datajson}
)
response_json = response.json()
emsg = response_json["emsg"]
if emsg:
exception_msg = ". ".join([
emsg,
"For more information check Codejail Service logs."
])
exception = SafeExecException(emsg)
globals_dict.update(response_json["globals_dict"])
except Exception as e:
raise e
emsg = None
else:
exec_fn = codejail_safe_exec
# Decide which code executor to use.
if unsafely:
exec_fn = codejail_not_safe_exec
else:
exec_fn = codejail_safe_exec
# Run the code! Results are side effects in globals_dict.
try:
exec_fn(
code_prolog + LAZY_IMPORTS + code,
globals_dict,
python_path=python_path,
extra_files=extra_files,
limit_overrides_context=limit_overrides_context,
slug=slug,
)
except SafeExecException as e:
# Saving SafeExecException e in exception to be used later.
exception = e
emsg = text_type(e)
else:
emsg = None
# Run the code! Results are side effects in globals_dict.
try:
exec_fn(
code_prolog + LAZY_IMPORTS + code,
globals_dict,
python_path=python_path,
extra_files=extra_files,
limit_overrides_context=limit_overrides_context,
slug=slug,
)
except SafeExecException as e:
# Saving SafeExecException e in exception to be used later.
exception = e
emsg = text_type(e)
else:
emsg = None
# Put the result back in the cache. This is complicated by the fact that
# the globals dict might not be entirely serializable.

View File

@@ -948,6 +948,18 @@ FEATURES = {
# .. toggle_target_removal_date: 2021-10-01
# .. toggle_tickets: 'https://openedx.atlassian.net/browse/MICROBA-1405'
'ENABLE_V2_CERT_DISPLAY_SETTINGS': False,
# .. toggle_name: ENABLE_CODEJAIL_REST_SERVICE
# .. toggle_implementation: DjangoSetting
# .. toggle_default: False
# .. toggle_description: Set this to True if you want to run Codejail code using
# a separate VM or container and communicate with edx-platform using REST API.
# .. toggle_use_cases: tutor
# .. toggle_creation_date: 2021-08-19
# .. toggle_target_removal_date: None
# .. toggle_warnings:
# .. toggle_tickets:
'ENABLE_CODEJAIL_REST_SERVICE': False,
}
# Specifies extra XBlock fields that should available when requested via the Course Blocks API
@@ -1629,6 +1641,9 @@ CODE_JAIL = {
# ]
COURSES_WITH_UNSAFE_CODE = []
# Cojail REST service
CODE_JAIL_REST_SERVICE_HOST = 'http://127.0.0.1:8550'
############################### DJANGO BUILT-INS ###############################
# Change DEBUG in your environment settings files, not here
DEBUG = False