aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--snekbox/api/resources/eval.py23
-rw-r--r--tests/api/test_eval.py18
2 files changed, 31 insertions, 10 deletions
diff --git a/snekbox/api/resources/eval.py b/snekbox/api/resources/eval.py
index de54564..c3e553a 100644
--- a/snekbox/api/resources/eval.py
+++ b/snekbox/api/resources/eval.py
@@ -27,6 +27,7 @@ class EvalResource:
REQ_SCHEMA = {
"type": "object",
"properties": {
+ "input": {"type": "string"},
"args": {"type": "array", "items": {"type": "string"}},
"files": {
"type": "array",
@@ -44,7 +45,10 @@ class EvalResource:
},
},
},
- "required": ["args"],
+ "anyOf": [
+ {"required": ["input"]},
+ {"required": ["args"]},
+ ],
}
def __init__(self, nsjail: NsJail):
@@ -57,6 +61,11 @@ class EvalResource:
A list of arguments for the Python subprocess can be specified as `args`.
+ If `input` is specified, it will be appended as the last argument to `args`,
+ and `args` will have a default argument of `"-c"`.
+
+ Either `input` or `args` must be specified.
+
The return codes mostly resemble those of a Unix shell. Some noteworthy cases:
- None
@@ -69,6 +78,10 @@ class EvalResource:
Request body:
>>> {
+ ... "input": "print('Hello')"
+ ... }
+
+ >>> {
... "args": ["-c", "print('Hello')"]
... }
@@ -105,10 +118,14 @@ class EvalResource:
- 415
Unsupported content type; only application/JSON is supported
"""
+ body: dict[str, str | list[str] | list[dict[str, str]]] = req.media
+ # If `input` is supplied, default `args` to `-c`
+ if "input" in body:
+ body.setdefault("args", ["-c"])
try:
result = self.nsjail.python3(
- py_args=req.media["args"],
- files=[FileAttachment.from_dict(file) for file in req.media.get("files", [])],
+ py_args=body["args"],
+ files=[FileAttachment.from_dict(file) for file in body.get("files", [])],
)
except ParsingError as e:
raise falcon.HTTPBadRequest(title="Request file is invalid", description=str(e))
diff --git a/tests/api/test_eval.py b/tests/api/test_eval.py
index 64d7ba6..26ac38a 100644
--- a/tests/api/test_eval.py
+++ b/tests/api/test_eval.py
@@ -5,12 +5,16 @@ class TestEvalResource(SnekAPITestCase):
PATH = "/eval"
def test_post_valid_200(self):
- body = {"args": ["-c", "print('output')"]}
- result = self.simulate_post(self.PATH, json=body)
-
- self.assertEqual(result.status_code, 200)
- self.assertEqual("output", result.json["stdout"])
- self.assertEqual(0, result.json["returncode"])
+ cases = [
+ {"args": ["-c", "print('output')"]},
+ {"input": "print('hello')"},
+ ]
+ for body in cases:
+ with self.subTest():
+ result = self.simulate_post(self.PATH, json=body)
+ self.assertEqual(result.status_code, 200)
+ self.assertEqual("output", result.json["stdout"])
+ self.assertEqual(0, result.json["returncode"])
def test_post_invalid_schema_400(self):
body = {"stuff": "foo"}
@@ -20,7 +24,7 @@ class TestEvalResource(SnekAPITestCase):
expected = {
"title": "Request data failed validation",
- "description": "'args' is a required property",
+ "description": "{'stuff': 'foo'} is not valid under any of the given schemas",
}
self.assertEqual(expected, result.json)