diff options
-rw-r--r-- | pyproject.toml | 2 | ||||
-rw-r--r-- | snekbox/api/resources/eval.py | 40 | ||||
-rw-r--r-- | snekbox/nsjail.py | 9 |
3 files changed, 48 insertions, 3 deletions
diff --git a/pyproject.toml b/pyproject.toml index a0ccf8a..a258843 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,5 +70,5 @@ force-exclude = "snekbox/config_pb2.py" line_length = 100 profile = "black" skip_gitignore = true -src_paths = ["snekbox"] +src_paths = ["snekbox", "scripts"] extend_skip = ["snekbox/config_pb2.py"] diff --git a/snekbox/api/resources/eval.py b/snekbox/api/resources/eval.py index 9a53577..30f95ab 100644 --- a/snekbox/api/resources/eval.py +++ b/snekbox/api/resources/eval.py @@ -9,10 +9,13 @@ from snekbox.nsjail import NsJail __all__ = ("EvalResource",) +from scripts.python_version import get_all_versions from snekbox.snekio import FileAttachment, ParsingError log = logging.getLogger(__name__) +_VERSION_DISPLAY_NAMES = [version.display_name for version in get_all_versions()[0]] + class EvalResource: """ @@ -29,6 +32,10 @@ class EvalResource: "properties": { "input": {"type": "string"}, "args": {"type": "array", "items": {"type": "string"}}, + "version": { + "type": "string", + "oneOf": [{"const": name} for name in _VERSION_DISPLAY_NAMES], + }, "files": { "type": "array", "items": { @@ -54,6 +61,29 @@ class EvalResource: def __init__(self, nsjail: NsJail): self.nsjail = nsjail + @validate( + resp_schema={ + "versions": {"type": "array", "items": {"type": "str"}}, + } + ) + def on_get(self, _: falcon.Request, resp: falcon.Response) -> None: + """ + Get information about the server. + + Response format: + >>> { + ... "versions": ["Python 3.9", "Python 3.10", "Python 3.12 Beta 1"] + ... } + + Status codes: + + - 200 + Success. + """ + resp.media = { + "versions": _VERSION_DISPLAY_NAMES, + } + @validate(REQ_SCHEMA) def on_post(self, req: falcon.Request, resp: falcon.Response) -> None: """ @@ -123,10 +153,20 @@ class EvalResource: if "input" in body: body.setdefault("args", ["-c"]) body["args"].append(body["input"]) + + # Parse a version from the request body, or use the default version + all_versions, selected_version = get_all_versions() + if "version" in body: + for version in all_versions: + if version.display_name == body["version"]: + selected_version = version + break + try: result = self.nsjail.python3( py_args=body["args"], files=[FileAttachment.from_dict(file) for file in body.get("files", [])], + version=selected_version, ) except ParsingError as e: raise falcon.HTTPBadRequest(title="Request file is invalid", description=str(e)) diff --git a/snekbox/nsjail.py b/snekbox/nsjail.py index f014850..d3417b4 100644 --- a/snekbox/nsjail.py +++ b/snekbox/nsjail.py @@ -9,6 +9,7 @@ from typing import Iterable, TypeVar from google.protobuf import text_format +from scripts.python_version import Version from snekbox import DEBUG, utils from snekbox.config_pb2 import NsJailConfig from snekbox.filesystem import Size @@ -177,6 +178,7 @@ class NsJail: def python3( self, py_args: Iterable[str], + version: Version, files: Iterable[FileAttachment] = (), nsjail_args: Iterable[str] = (), ) -> EvalResult: @@ -185,6 +187,7 @@ class NsJail: Args: py_args: Arguments to pass to Python. + version: The python version to perform the eval with. files: FileAttachments to write to the sandbox prior to running Python. nsjail_args: Overrides for the NsJail configuration. """ @@ -218,10 +221,12 @@ class NsJail: self.config_path, "--log", nsj_log.name, + "-E", + f"PYTHONPATH=/snekbox/user_base/lib/python{version.version_name}/site-packages", *nsjail_args, "--", - self.config.exec_bin.path, - *self.config.exec_bin.arg, + f"/usr/local/bin/python{version.version_name}", + *["-BSqu"], # Filter out empty strings at start of py_args # (causes issues with python cli) *iter_lstrip(py_args), |