diff options
author | 2023-03-10 02:03:01 +0200 | |
---|---|---|
committer | 2023-03-10 02:03:01 +0200 | |
commit | 8a85b86174067618891e2530dd56b5025fd2f28b (patch) | |
tree | cc85ad898f492c0b799917cda05537c88bea83c6 /tests/api/test_eval.py | |
parent | Merge pull request #167 from python-discord/deployment-update (diff) | |
parent | Merge branch 'main' into bytes-output (diff) |
Merge pull request #159 from python-discord/bytes-output
File system and Binary file sending
Diffstat (limited to 'tests/api/test_eval.py')
-rw-r--r-- | tests/api/test_eval.py | 106 |
1 files changed, 93 insertions, 13 deletions
diff --git a/tests/api/test_eval.py b/tests/api/test_eval.py index 976970e..37f90e7 100644 --- a/tests/api/test_eval.py +++ b/tests/api/test_eval.py @@ -5,12 +5,19 @@ class TestEvalResource(SnekAPITestCase): PATH = "/eval" def test_post_valid_200(self): - body = {"input": "foo"} - 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')"}, + {"input": "print('hello')", "args": ["-c"]}, + {"input": "print('hello')", "args": [""]}, + {"input": "pass", "args": ["-m", "timeit"]}, + ] + 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,27 +27,100 @@ class TestEvalResource(SnekAPITestCase): expected = { "title": "Request data failed validation", - "description": "'input' is a required property", + "description": "{'stuff': 'foo'} is not valid under any of the given schemas", } self.assertEqual(expected, result.json) def test_post_invalid_data_400(self): - bodies = ({"input": 400}, {"input": "", "args": [400]}) - - for body in bodies: + bodies = ({"args": 400}, {"args": [], "files": [215]}) + expects = ["400 is not of type 'array'", "215 is not of type 'object'"] + for body, expected in zip(bodies, expects): with self.subTest(): result = self.simulate_post(self.PATH, json=body) self.assertEqual(result.status_code, 400) - expected = { + expected_json = { "title": "Request data failed validation", - "description": "400 is not of type 'string'", + "description": expected, + } + self.assertEqual(expected_json, result.json) + + def test_files_path(self): + """Normal paths should work with 200.""" + test_paths = [ + "file.txt", + "./0.jpg", + "path/to/file", + "folder/../hm", + "folder/./to/./somewhere", + "traversal/but/../not/beyond/../root", + r"backslash\\okay", + r"backslash\okay", + "numbers/0123456789", + ] + for path in test_paths: + with self.subTest(path=path): + body = {"args": ["test.py"], "files": [{"path": path}]} + 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_files_illegal_path_traversal(self): + """Traversal beyond root should be denied with 400 error.""" + test_paths = [ + "../secrets", + "../../dir", + "dir/../../secrets", + "dir/var/../../../file", + ] + for path in test_paths: + with self.subTest(path=path): + body = {"args": ["test.py"], "files": [{"path": path}]} + result = self.simulate_post(self.PATH, json=body) + self.assertEqual(result.status_code, 400) + expected = { + "title": "Request file is invalid", + "description": f"File path '{path}' may not traverse beyond root", } - self.assertEqual(expected, result.json) + def test_files_illegal_path_absolute(self): + """Absolute file paths should 400-error at json schema validation stage.""" + test_paths = [ + "/", + "/etc", + "/etc/vars/secrets", + "/absolute", + "/file.bin", + ] + for path in test_paths: + with self.subTest(path=path): + body = {"args": ["test.py"], "files": [{"path": path}]} + result = self.simulate_post(self.PATH, json=body) + self.assertEqual(result.status_code, 400) + self.assertEqual("Request data failed validation", result.json["title"]) + self.assertIn("does not match", result.json["description"]) + + def test_files_illegal_path_null_byte(self): + """Paths containing \0 should 400-error at json schema validation stage.""" + test_paths = [ + r"etc/passwd\0", + r"a\0b", + r"\0", + r"\\0", + r"var/\0/path", + ] + for path in test_paths: + with self.subTest(path=path): + body = {"args": ["test.py"], "files": [{"path": path}]} + result = self.simulate_post(self.PATH, json=body) + self.assertEqual(result.status_code, 400) + self.assertEqual("Request data failed validation", result.json["title"]) + self.assertIn("does not match", result.json["description"]) + def test_post_invalid_content_type_415(self): body = "{'input': 'foo'}" headers = {"Content-Type": "application/xml"} |