aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar MarkKoz <[email protected]>2020-02-22 21:37:47 -0800
committerGravatar MarkKoz <[email protected]>2020-02-22 21:37:47 -0800
commit782c5fc6c2e60e8e460f17d39cfad39cae7f30e0 (patch)
treef8f44bbd9e7115458a2a259668167853ab53fa93
parentTest lint only (diff)
parentMerge pull request #62 from python-discord/bug/ci/61/python-symlink-not-resol... (diff)
Merge remote-tracking branch 'origin/master' into research
-rw-r--r--.dockerignore2
-rw-r--r--.flake86
-rw-r--r--.github/CODEOWNERS1
-rw-r--r--Pipfile19
-rw-r--r--Pipfile.lock446
-rw-r--r--README.md16
-rw-r--r--docker-compose.yml1
-rw-r--r--docker/base.Dockerfile47
-rw-r--r--docker/venv.Dockerfile15
-rw-r--r--scripts/.profile15
-rwxr-xr-xscripts/dev.sh11
-rw-r--r--snekbox.cfg118
-rw-r--r--snekbox/__init__.py3
-rw-r--r--snekbox/api/resources/eval.py2
-rw-r--r--snekbox/nsjail.py28
-rw-r--r--tests/test_nsjail.py68
16 files changed, 631 insertions, 167 deletions
diff --git a/.dockerignore b/.dockerignore
index afc786a..4f43e08 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,8 +2,8 @@
*
# Make exceptions for what's needed
-!docker/.profile
!snekbox
+!snekbox.cfg
!tests
!Pipfile
!Pipfile.lock
diff --git a/.flake8 b/.flake8
index 4089dfe..efc7b3d 100644
--- a/.flake8
+++ b/.flake8
@@ -11,10 +11,12 @@ ignore=
# Docstring Quotes
D301,D302,
# Docstring Content
- D400,D401,D402,D404,D405,D406,D407,D408,D409,D410,D411,D412,D413,D414,D416,D417
+ D400,D401,D402,D404,D405,D406,D407,D408,D409,D410,D411,D412,D413,D414,D416,D417,
+ # Type Annotations
+ TYP002,TYP003,TYP101,TYP102,TYP204,TYP206
exclude=
__pycache__,.cache,
venv,.venv
-per-file-ignores=tests/*:D1
+per-file-ignores=tests/*:D1,TYP
import-order-style=pycharm
inline-quotes="
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..cf5f159
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @python-discord/core-developers
diff --git a/Pipfile b/Pipfile
index dd17306..afda418 100644
--- a/Pipfile
+++ b/Pipfile
@@ -7,12 +7,29 @@ name = "pypi"
falcon = "~= 2.0.0"
gunicorn = "~= 19.9"
jsonschema = "~= 3.0"
+numpy = "~= 1.17"
+scipy = "~= 1.3"
+pandas = "~= 0.25"
+sympy = "~= 1.5"
+fuzzywuzzy = "~= 0.17"
+python-dateutil = "~= 2.8"
+pendulum = "~= 2.0"
+arrow = "~= 0.15"
+yarl = "~= 1.4"
+attrs = "~= 19.3"
+forbiddenfruit = "~= 0.1"
+more-itertools = "~= 8.0"
+networkx = "~= 2.4"
+beautifulsoup4 = "~= 4.8"
+pyyaml = "~= 5.2"
+toml = "~= 0.10"
[dev-packages]
coverage = ">= 4.4.2, == 4.*"
pre-commit = "~= 1.18"
pydocstyle = "~= 4.0"
flake8 = "~= 3.7.8"
+flake8-annotations = ">= 1.1.1, == 1.*"
flake8-docstrings = "~=1.4"
flake8-bugbear = "~= 19.3"
flake8-import-order = "~= 0.18.1"
@@ -24,7 +41,7 @@ flake8-quotes = "~= 2.1"
unittest-xml-reporting = ">= 2.5.1, == 2.*"
[requires]
-python_version = "3.7"
+python_version = "3.8"
[scripts]
lint = "flake8"
diff --git a/Pipfile.lock b/Pipfile.lock
index b541730..04765b6 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,11 +1,11 @@
{
"_meta": {
"hash": {
- "sha256": "fa4ef446ed6cd8618914fd2b509e1d437f71cd70140bba4b5b95a4eaf6e53933"
+ "sha256": "4a760f24a649010040635541114b17cadfd785956cfd9216a6f8c9590a69cca1"
},
"pipfile-spec": 6,
"requires": {
- "python_version": "3.7"
+ "python_version": "3.8"
},
"sources": [
{
@@ -16,12 +16,37 @@
]
},
"default": {
+ "arrow": {
+ "hashes": [
+ "sha256:5390e464e2c5f76971b60ffa7ee29c598c7501a294bc9f5e6dadcb251a5d027b",
+ "sha256:70729bcc831da496ca3cb4b7e89472c8e2d27d398908155e0796179f6d2d41ee"
+ ],
+ "index": "pypi",
+ "version": "==0.15.5"
+ },
"attrs": {
"hashes": [
- "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
- "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
+ "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
+ "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
+ ],
+ "index": "pypi",
+ "version": "==19.3.0"
+ },
+ "beautifulsoup4": {
+ "hashes": [
+ "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a",
+ "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887",
+ "sha256:e1505eeed31b0f4ce2dbb3bc8eb256c04cc2b3b72af7d551a4ab6efd5cbe5dae"
],
- "version": "==19.1.0"
+ "index": "pypi",
+ "version": "==4.8.2"
+ },
+ "decorator": {
+ "hashes": [
+ "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce",
+ "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d"
+ ],
+ "version": "==4.4.1"
},
"falcon": {
"hashes": [
@@ -43,37 +68,286 @@
"index": "pypi",
"version": "==2.0.0"
},
+ "forbiddenfruit": {
+ "hashes": [
+ "sha256:1188a07cc24a9bd2c529dad06490b80a6fc88cde968af4d7861da81686b2cc8c"
+ ],
+ "index": "pypi",
+ "version": "==0.1.3"
+ },
+ "fuzzywuzzy": {
+ "hashes": [
+ "sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8",
+ "sha256:928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993"
+ ],
+ "index": "pypi",
+ "version": "==0.18.0"
+ },
"gunicorn": {
"hashes": [
- "sha256:aa8e0b40b4157b36a5df5e599f45c9c76d6af43845ba3b3b0efe2c70473c2471",
- "sha256:fa2662097c66f920f53f70621c6c58ca4a3c4d3434205e608e121b5b3b71f4f3"
+ "sha256:c3930fe8de6778ab5ea716cab432ae6335fa9f03b3f2c3e02529214c476f4bcb",
+ "sha256:f9de24e358b841567063629cd0a656b26792a41e23a24d0dcb40224fc3940081"
],
"index": "pypi",
- "version": "==19.9.0"
+ "version": "==19.10.0"
+ },
+ "idna": {
+ "hashes": [
+ "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb",
+ "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"
+ ],
+ "version": "==2.9"
},
"jsonschema": {
"hashes": [
- "sha256:5f9c0a719ca2ce14c5de2fd350a64fd2d13e8539db29836a86adc990bb1a068f",
- "sha256:8d4a2b7b6c2237e0199c8ea1a6d3e05bf118e289ae2b9d7ba444182a2959560d"
+ "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163",
+ "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"
+ ],
+ "index": "pypi",
+ "version": "==3.2.0"
+ },
+ "more-itertools": {
+ "hashes": [
+ "sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c",
+ "sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507"
],
"index": "pypi",
- "version": "==3.0.2"
+ "version": "==8.2.0"
+ },
+ "mpmath": {
+ "hashes": [
+ "sha256:fc17abe05fbab3382b61a123c398508183406fa132e0223874578e20946499f6"
+ ],
+ "version": "==1.1.0"
+ },
+ "multidict": {
+ "hashes": [
+ "sha256:317f96bc0950d249e96d8d29ab556d01dd38888fbe68324f46fd834b430169f1",
+ "sha256:42f56542166040b4474c0c608ed051732033cd821126493cf25b6c276df7dd35",
+ "sha256:4b7df040fb5fe826d689204f9b544af469593fb3ff3a069a6ad3409f742f5928",
+ "sha256:544fae9261232a97102e27a926019100a9db75bec7b37feedd74b3aa82f29969",
+ "sha256:620b37c3fea181dab09267cd5a84b0f23fa043beb8bc50d8474dd9694de1fa6e",
+ "sha256:6e6fef114741c4d7ca46da8449038ec8b1e880bbe68674c01ceeb1ac8a648e78",
+ "sha256:7774e9f6c9af3f12f296131453f7b81dabb7ebdb948483362f5afcaac8a826f1",
+ "sha256:85cb26c38c96f76b7ff38b86c9d560dea10cf3459bb5f4caf72fc1bb932c7136",
+ "sha256:a326f4240123a2ac66bb163eeba99578e9d63a8654a59f4688a79198f9aa10f8",
+ "sha256:ae402f43604e3b2bc41e8ea8b8526c7fa7139ed76b0d64fc48e28125925275b2",
+ "sha256:aee283c49601fa4c13adc64c09c978838a7e812f85377ae130a24d7198c0331e",
+ "sha256:b51249fdd2923739cd3efc95a3d6c363b67bbf779208e9f37fd5e68540d1a4d4",
+ "sha256:bb519becc46275c594410c6c28a8a0adc66fe24fef154a9addea54c1adb006f5",
+ "sha256:c2c37185fb0af79d5c117b8d2764f4321eeb12ba8c141a95d0aa8c2c1d0a11dd",
+ "sha256:dc561313279f9d05a3d0ffa89cd15ae477528ea37aa9795c4654588a3287a9ab",
+ "sha256:e439c9a10a95cb32abd708bb8be83b2134fa93790a4fb0535ca36db3dda94d20",
+ "sha256:fc3b4adc2ee8474cb3cd2a155305d5f8eda0a9c91320f83e55748e1fcb68f8e3"
+ ],
+ "version": "==4.7.5"
+ },
+ "networkx": {
+ "hashes": [
+ "sha256:cdfbf698749a5014bf2ed9db4a07a5295df1d3a53bf80bf3cbd61edf9df05fa1",
+ "sha256:f8f4ff0b6f96e4f9b16af6b84622597b5334bf9cae8cf9b2e42e7985d5c95c64"
+ ],
+ "index": "pypi",
+ "version": "==2.4"
+ },
+ "numpy": {
+ "hashes": [
+ "sha256:1786a08236f2c92ae0e70423c45e1e62788ed33028f94ca99c4df03f5be6b3c6",
+ "sha256:17aa7a81fe7599a10f2b7d95856dc5cf84a4eefa45bc96123cbbc3ebc568994e",
+ "sha256:20b26aaa5b3da029942cdcce719b363dbe58696ad182aff0e5dcb1687ec946dc",
+ "sha256:2d75908ab3ced4223ccba595b48e538afa5ecc37405923d1fea6906d7c3a50bc",
+ "sha256:39d2c685af15d3ce682c99ce5925cc66efc824652e10990d2462dfe9b8918c6a",
+ "sha256:56bc8ded6fcd9adea90f65377438f9fea8c05fcf7c5ba766bef258d0da1554aa",
+ "sha256:590355aeade1a2eaba17617c19edccb7db8d78760175256e3cf94590a1a964f3",
+ "sha256:70a840a26f4e61defa7bdf811d7498a284ced303dfbc35acb7be12a39b2aa121",
+ "sha256:77c3bfe65d8560487052ad55c6998a04b654c2fbc36d546aef2b2e511e760971",
+ "sha256:9537eecf179f566fd1c160a2e912ca0b8e02d773af0a7a1120ad4f7507cd0d26",
+ "sha256:9acdf933c1fd263c513a2df3dceecea6f3ff4419d80bf238510976bf9bcb26cd",
+ "sha256:ae0975f42ab1f28364dcda3dde3cf6c1ddab3e1d4b2909da0cb0191fa9ca0480",
+ "sha256:b3af02ecc999c8003e538e60c89a2b37646b39b688d4e44d7373e11c2debabec",
+ "sha256:b6ff59cee96b454516e47e7721098e6ceebef435e3e21ac2d6c3b8b02628eb77",
+ "sha256:b765ed3930b92812aa698a455847141869ef755a87e099fddd4ccf9d81fffb57",
+ "sha256:c98c5ffd7d41611407a1103ae11c8b634ad6a43606eca3e2a5a269e5d6e8eb07",
+ "sha256:cf7eb6b1025d3e169989416b1adcd676624c2dbed9e3bcb7137f51bfc8cc2572",
+ "sha256:d92350c22b150c1cae7ebb0ee8b5670cc84848f6359cf6b5d8f86617098a9b73",
+ "sha256:e422c3152921cece8b6a2fb6b0b4d73b6579bd20ae075e7d15143e711f3ca2ca",
+ "sha256:e840f552a509e3380b0f0ec977e8124d0dc34dc0e68289ca28f4d7c1d0d79474",
+ "sha256:f3d0a94ad151870978fb93538e95411c83899c9dc63e6fb65542f769568ecfa5"
+ ],
+ "index": "pypi",
+ "version": "==1.18.1"
+ },
+ "pandas": {
+ "hashes": [
+ "sha256:00dff3a8e337f5ed7ad295d98a31821d3d0fe7792da82d78d7fd79b89c03ea9d",
+ "sha256:22361b1597c8c2ffd697aa9bf85423afa9e1fcfa6b1ea821054a244d5f24d75e",
+ "sha256:255920e63850dc512ce356233081098554d641ba99c3767dde9e9f35630f994b",
+ "sha256:26382aab9c119735908d94d2c5c08020a4a0a82969b7e5eefb92f902b3b30ad7",
+ "sha256:33970f4cacdd9a0ddb8f21e151bfb9f178afb7c36eb7c25b9094c02876f385c2",
+ "sha256:4545467a637e0e1393f7d05d61dace89689ad6d6f66f267f86fff737b702cce9",
+ "sha256:52da74df8a9c9a103af0a72c9d5fdc8e0183a90884278db7f386b5692a2220a4",
+ "sha256:61741f5aeb252f39c3031d11405305b6d10ce663c53bc3112705d7ad66c013d0",
+ "sha256:6a3ac2c87e4e32a969921d1428525f09462770c349147aa8e9ab95f88c71ec71",
+ "sha256:7458c48e3d15b8aaa7d575be60e1e4dd70348efcd9376656b72fecd55c59a4c3",
+ "sha256:78bf638993219311377ce9836b3dc05f627a666d0dbc8cec37c0ff3c9ada673b",
+ "sha256:8153705d6545fd9eb6dd2bc79301bff08825d2e2f716d5dced48daafc2d0b81f",
+ "sha256:975c461accd14e89d71772e89108a050fa824c0b87a67d34cedf245f6681fc17",
+ "sha256:9962957a27bfb70ab64103d0a7b42fa59c642fb4ed4cb75d0227b7bb9228535d",
+ "sha256:adc3d3a3f9e59a38d923e90e20c4922fc62d1e5a03d083440468c6d8f3f1ae0a",
+ "sha256:bbe3eb765a0b1e578833d243e2814b60c825b7fdbf4cdfe8e8aae8a08ed56ecf",
+ "sha256:df8864824b1fe488cf778c3650ee59c3a0d8f42e53707de167ba6b4f7d35f133",
+ "sha256:e45055c30a608076e31a9fcd780a956ed3b1fa20db61561b8d88b79259f526f7",
+ "sha256:ee50c2142cdcf41995655d499a157d0a812fce55c97d9aad13bc1eef837ed36c"
+ ],
+ "index": "pypi",
+ "version": "==0.25.3"
+ },
+ "pendulum": {
+ "hashes": [
+ "sha256:1cde6e3c6310fb882c98f373795f807cb2bd6af01f34d2857e6e283b5ee91e09",
+ "sha256:485aef2089defee88607d37d5bc238934d0b90993d7bf9ceb36e481af41e9c66",
+ "sha256:57801754e05f30e8a7e4d24734c9fad82c6c3ec489151555f0fc66bb32ba6d6d",
+ "sha256:7ee344bc87cb425b04717b90d14ffde14c1dd64eaa73060b3772edcf57f3e866",
+ "sha256:c460f4d8dc41ec3c4377ac1807678cd72fe5e973cc2943c104ffdeaac32dacb7",
+ "sha256:d3078e007315a959989c41cee5cfd63cfeeca21dd3d8295f4bc24199489e9b6c"
+ ],
+ "index": "pypi",
+ "version": "==2.0.5"
},
"pyrsistent": {
"hashes": [
- "sha256:34b47fa169d6006b32e99d4b3c4031f155e6e68ebcc107d6454852e8e0ee6533"
+ "sha256:cdc7b5e3ed77bed61270a47d35434a30617b9becdf2478af76ad2c6ade307280"
+ ],
+ "version": "==0.15.7"
+ },
+ "python-dateutil": {
+ "hashes": [
+ "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c",
+ "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"
+ ],
+ "index": "pypi",
+ "version": "==2.8.1"
+ },
+ "pytz": {
+ "hashes": [
+ "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
+ "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
+ ],
+ "version": "==2019.3"
+ },
+ "pytzdata": {
+ "hashes": [
+ "sha256:84c52b9a47d097fcd483f047a544979de6c3a86e94c845e3569e9f8acd0fa071",
+ "sha256:fac06f7cdfa903188dc4848c655e4adaee67ee0f2fe08e7daf815cf2a761ee5e"
+ ],
+ "version": "==2019.3"
+ },
+ "pyyaml": {
+ "hashes": [
+ "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6",
+ "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf",
+ "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5",
+ "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e",
+ "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811",
+ "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e",
+ "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d",
+ "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20",
+ "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689",
+ "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994",
+ "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615"
+ ],
+ "index": "pypi",
+ "version": "==5.3"
+ },
+ "scipy": {
+ "hashes": [
+ "sha256:00af72998a46c25bdb5824d2b729e7dabec0c765f9deb0b504f928591f5ff9d4",
+ "sha256:0902a620a381f101e184a958459b36d3ee50f5effd186db76e131cbefcbb96f7",
+ "sha256:1e3190466d669d658233e8a583b854f6386dd62d655539b77b3fa25bfb2abb70",
+ "sha256:2cce3f9847a1a51019e8c5b47620da93950e58ebc611f13e0d11f4980ca5fecb",
+ "sha256:3092857f36b690a321a662fe5496cb816a7f4eecd875e1d36793d92d3f884073",
+ "sha256:386086e2972ed2db17cebf88610aab7d7f6e2c0ca30042dc9a89cf18dcc363fa",
+ "sha256:71eb180f22c49066f25d6df16f8709f215723317cc951d99e54dc88020ea57be",
+ "sha256:770254a280d741dd3436919d47e35712fb081a6ff8bafc0f319382b954b77802",
+ "sha256:787cc50cab3020a865640aba3485e9fbd161d4d3b0d03a967df1a2881320512d",
+ "sha256:8a07760d5c7f3a92e440ad3aedcc98891e915ce857664282ae3c0220f3301eb6",
+ "sha256:8d3bc3993b8e4be7eade6dcc6fd59a412d96d3a33fa42b0fa45dc9e24495ede9",
+ "sha256:9508a7c628a165c2c835f2497837bf6ac80eb25291055f56c129df3c943cbaf8",
+ "sha256:a144811318853a23d32a07bc7fd5561ff0cac5da643d96ed94a4ffe967d89672",
+ "sha256:a1aae70d52d0b074d8121333bc807a485f9f1e6a69742010b33780df2e60cfe0",
+ "sha256:a2d6df9eb074af7f08866598e4ef068a2b310d98f87dc23bd1b90ec7bdcec802",
+ "sha256:bb517872058a1f087c4528e7429b4a44533a902644987e7b2fe35ecc223bc408",
+ "sha256:c5cac0c0387272ee0e789e94a570ac51deb01c796b37fb2aad1fb13f85e2f97d",
+ "sha256:cc971a82ea1170e677443108703a2ec9ff0f70752258d0e9f5433d00dda01f59",
+ "sha256:dba8306f6da99e37ea08c08fef6e274b5bf8567bb094d1dbe86a20e532aca088",
+ "sha256:dc60bb302f48acf6da8ca4444cfa17d52c63c5415302a9ee77b3b21618090521",
+ "sha256:dee1bbf3a6c8f73b6b218cb28eed8dd13347ea2f87d572ce19b289d6fd3fbc59"
],
- "version": "==0.15.4"
+ "index": "pypi",
+ "version": "==1.4.1"
},
"six": {
"hashes": [
- "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
- "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
+ "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
+ "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
+ ],
+ "version": "==1.14.0"
+ },
+ "soupsieve": {
+ "hashes": [
+ "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5",
+ "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"
+ ],
+ "version": "==1.9.5"
+ },
+ "sympy": {
+ "hashes": [
+ "sha256:4880d3a351558063bd89febda302f220dc4b88de393bba81fa6539a3966f03fa",
+ "sha256:d77901d748287d15281f5ffe5b0fef62dd38f357c2b827c44ff07f35695f4e7e"
],
- "version": "==1.12.0"
+ "index": "pypi",
+ "version": "==1.5.1"
+ },
+ "toml": {
+ "hashes": [
+ "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
+ "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"
+ ],
+ "index": "pypi",
+ "version": "==0.10.0"
+ },
+ "yarl": {
+ "hashes": [
+ "sha256:0c2ab325d33f1b824734b3ef51d4d54a54e0e7a23d13b86974507602334c2cce",
+ "sha256:0ca2f395591bbd85ddd50a82eb1fde9c1066fafe888c5c7cc1d810cf03fd3cc6",
+ "sha256:2098a4b4b9d75ee352807a95cdf5f10180db903bc5b7270715c6bbe2551f64ce",
+ "sha256:25e66e5e2007c7a39541ca13b559cd8ebc2ad8fe00ea94a2aad28a9b1e44e5ae",
+ "sha256:26d7c90cb04dee1665282a5d1a998defc1a9e012fdca0f33396f81508f49696d",
+ "sha256:308b98b0c8cd1dfef1a0311dc5e38ae8f9b58349226aa0533f15a16717ad702f",
+ "sha256:3ce3d4f7c6b69c4e4f0704b32eca8123b9c58ae91af740481aa57d7857b5e41b",
+ "sha256:58cd9c469eced558cd81aa3f484b2924e8897049e06889e8ff2510435b7ef74b",
+ "sha256:5b10eb0e7f044cf0b035112446b26a3a2946bca9d7d7edb5e54a2ad2f6652abb",
+ "sha256:6faa19d3824c21bcbfdfce5171e193c8b4ddafdf0ac3f129ccf0cdfcb083e462",
+ "sha256:944494be42fa630134bf907714d40207e646fd5a94423c90d5b514f7b0713fea",
+ "sha256:a161de7e50224e8e3de6e184707476b5a989037dcb24292b391a3d66ff158e70",
+ "sha256:a4844ebb2be14768f7994f2017f70aca39d658a96c786211be5ddbe1c68794c1",
+ "sha256:c2b509ac3d4b988ae8769901c66345425e361d518aecbe4acbfc2567e416626a",
+ "sha256:c9959d49a77b0e07559e579f38b2f3711c2b8716b8410b320bf9713013215a1b",
+ "sha256:d8cdee92bc930d8b09d8bd2043cedd544d9c8bd7436a77678dd602467a993080",
+ "sha256:e15199cdb423316e15f108f51249e44eb156ae5dba232cb73be555324a1d49c2"
+ ],
+ "index": "pypi",
+ "version": "==1.4.2"
}
},
"develop": {
+ "appdirs": {
+ "hashes": [
+ "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92",
+ "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"
+ ],
+ "version": "==1.4.3"
+ },
"aspy.yaml": {
"hashes": [
"sha256:463372c043f70160a9ec950c3f1e4c3a82db5fca01d334b6bc89c7164d744bdc",
@@ -83,17 +357,18 @@
},
"attrs": {
"hashes": [
- "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
- "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
+ "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
+ "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
],
- "version": "==19.1.0"
+ "index": "pypi",
+ "version": "==19.3.0"
},
"cfgv": {
"hashes": [
- "sha256:edb387943b665bf9c434f717bf630fa78aecd53d5900d2e05da6ad6048553144",
- "sha256:fbd93c9ab0a523bf7daec408f3be2ed99a980e20b2d19b50fc184ca6b820d289"
+ "sha256:04b093b14ddf9fd4d17c53ebfd55582d27b76ed30050193c14e560770c5360eb",
+ "sha256:f22b426ed59cd2ab2b54ff96608d846c33dfb8766a67f0b4a6ce130ce244414f"
],
- "version": "==2.0.1"
+ "version": "==3.0.0"
},
"coverage": {
"hashes": [
@@ -133,6 +408,12 @@
"index": "pypi",
"version": "==4.5.4"
},
+ "distlib": {
+ "hashes": [
+ "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21"
+ ],
+ "version": "==0.3.0"
+ },
"entrypoints": {
"hashes": [
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
@@ -140,13 +421,28 @@
],
"version": "==0.3"
},
+ "filelock": {
+ "hashes": [
+ "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
+ "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"
+ ],
+ "version": "==3.0.12"
+ },
"flake8": {
"hashes": [
- "sha256:19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548",
- "sha256:8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"
+ "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb",
+ "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"
],
"index": "pypi",
- "version": "==3.7.8"
+ "version": "==3.7.9"
+ },
+ "flake8-annotations": {
+ "hashes": [
+ "sha256:47705be09c6e56e9e3ac1656e8f5ed70862a4657116dc472f5a56c1bdc5172b1",
+ "sha256:564702ace354e1059252755be79d082a70ae1851c86044ae1a96d0f5453280e9"
+ ],
+ "index": "pypi",
+ "version": "==1.2.0"
},
"flake8-bugbear": {
"hashes": [
@@ -158,11 +454,11 @@
},
"flake8-docstrings": {
"hashes": [
- "sha256:1666dd069c9c457ee57e80af3c1a6b37b00cc1801c6fde88e455131bb2e186cd",
- "sha256:9c0db5a79a1affd70fdf53b8765c8a26bf968e59e0252d7f2fc546b41c0cda06"
+ "sha256:3d5a31c7ec6b7367ea6506a87ec293b94a0a46c0bce2bb4975b7f1d09b6f3717",
+ "sha256:a256ba91bc52307bef1de59e2a009c3cf61c3d0952dbe035d6ff7208940c2edc"
],
"index": "pypi",
- "version": "==1.4.0"
+ "version": "==1.5.0"
},
"flake8-formatter-junit-xml": {
"hashes": [
@@ -182,10 +478,10 @@
},
"flake8-quotes": {
"hashes": [
- "sha256:5dbaf668887873f28346fb87943d6da2e4b9f77ce9f2169cff21764a0a4934ed"
+ "sha256:11a15d30c92ca5f04c2791bd7019cf62b6f9d3053eb050d02a135557eb118bfc"
],
"index": "pypi",
- "version": "==2.1.0"
+ "version": "==2.1.1"
},
"flake8-string-format": {
"hashes": [
@@ -212,17 +508,10 @@
},
"identify": {
"hashes": [
- "sha256:4f1fe9a59df4e80fcb0213086fcf502bc1765a01ea4fe8be48da3b65afd2a017",
- "sha256:d8919589bd2a5f99c66302fec0ef9027b12ae150b0b0213999ad3f695fc7296e"
+ "sha256:1222b648251bdcb8deb240b294f450fbf704c7984e08baa92507e4ea10b436d5",
+ "sha256:d824ebe21f38325c771c41b08a95a761db1982f1fc0eee37c6c97df3f1636b96"
],
- "version": "==1.4.7"
- },
- "importlib-metadata": {
- "hashes": [
- "sha256:9ff1b1c5a354142de080b8a4e9803e5d0d59283c93aed808617c787d16768375",
- "sha256:b7143592e374e50584564794fcb8aaf00a23025f9db866627f89a21491847a8d"
- ],
- "version": "==0.20"
+ "version": "==1.4.11"
},
"junit-xml": {
"hashes": [
@@ -237,26 +526,19 @@
],
"version": "==0.6.1"
},
- "more-itertools": {
- "hashes": [
- "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832",
- "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"
- ],
- "version": "==7.2.0"
- },
"nodeenv": {
"hashes": [
- "sha256:ad8259494cf1c9034539f6cced78a1da4840a4b157e23640bc4a0c0546b0cb7a"
+ "sha256:5b2438f2e42af54ca968dd1b374d14a1194848955187b0e5e4be1f73813a5212"
],
- "version": "==1.3.3"
+ "version": "==1.3.5"
},
"pre-commit": {
"hashes": [
- "sha256:1d3c0587bda7c4e537a46c27f2c84aa006acc18facf9970bf947df596ce91f3f",
- "sha256:fa78ff96e8e9ac94c748388597693f18b041a181c94a4f039ad20f45287ba44a"
+ "sha256:8f48d8637bdae6fa70cc97db9c1dd5aa7c5c8bf71968932a380628c25978b850",
+ "sha256:f92a359477f3252452ae2e8d3029de77aec59415c16ae4189bcfba40b757e029"
],
"index": "pypi",
- "version": "==1.18.3"
+ "version": "==1.21.0"
},
"pycodestyle": {
"hashes": [
@@ -282,63 +564,57 @@
},
"pyyaml": {
"hashes": [
- "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9",
- "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4",
- "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8",
- "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696",
- "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34",
- "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9",
- "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73",
- "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299",
- "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b",
- "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae",
- "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681",
- "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41",
- "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8"
- ],
- "version": "==5.1.2"
+ "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6",
+ "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf",
+ "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5",
+ "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e",
+ "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811",
+ "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e",
+ "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d",
+ "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20",
+ "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689",
+ "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994",
+ "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615"
+ ],
+ "index": "pypi",
+ "version": "==5.3"
},
"six": {
"hashes": [
- "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
- "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
+ "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
+ "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
],
- "version": "==1.12.0"
+ "version": "==1.14.0"
},
"snowballstemmer": {
"hashes": [
- "sha256:713e53b79cbcf97bc5245a06080a33d54a77e7cce2f789c835a143bcdb5c033e"
+ "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0",
+ "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"
],
- "version": "==1.9.1"
+ "version": "==2.0.0"
},
"toml": {
"hashes": [
"sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"
],
+ "index": "pypi",
"version": "==0.10.0"
},
"unittest-xml-reporting": {
"hashes": [
- "sha256:140982e4b58e4052d9ecb775525b246a96bfc1fc26097806e05ea06e9166dd6c",
- "sha256:d1fbc7a1b6c6680ccfe75b5e9701e5431c646970de049e687b4bb35ba4325d72"
+ "sha256:358bbdaf24a26d904cc1c26ef3078bca7fc81541e0a54c8961693cc96a6f35e0",
+ "sha256:9d28ddf6524cf0ff9293f61bd12e792de298f8561a5c945acea63fb437789e0e"
],
"index": "pypi",
- "version": "==2.5.1"
+ "version": "==2.5.2"
},
"virtualenv": {
"hashes": [
- "sha256:680af46846662bb38c5504b78bad9ed9e4f3ba2d54f54ba42494fdf94337fe30",
- "sha256:f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2"
- ],
- "version": "==16.7.5"
- },
- "zipp": {
- "hashes": [
- "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e",
- "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"
+ "sha256:531b142e300d405bb9faedad4adbeb82b4098b918e35209af2adef3129274aae",
+ "sha256:5dd42a9f56307542bddc446cfd10ef6576f11910366a07609fe8d0d88fa8fb7e"
],
- "version": "==0.6.0"
+ "version": "==20.0.5"
}
}
}
diff --git a/README.md b/README.md
index 29bbddb..bbb8d64 100644
--- a/README.md
+++ b/README.md
@@ -24,8 +24,8 @@ result <- | |<----------| | <----------+
The code is executed in a Python process that is launched through [NsJail](https://github.com/google/nsjail), which is responsible for sandboxing the Python process. NsJail is configured as follows:
-* Root directory is mounted as read-only
-* Time limit of 2 seconds
+* All mounts are read-only
+* Time limit of 5 seconds
* Maximum of 1 PID
* Maximum memory of 52428800 bytes
* Loopback interface is down
@@ -33,7 +33,7 @@ The code is executed in a Python process that is launched through [NsJail](https
The Python process is configured as follows:
-* Version 3.7.4
+* Version 3.8.0
* Isolated mode
* Neither the script's directory nor the user's site packages are in `sys.path`
* All `PYTHON*` environment variables are ignored
@@ -49,10 +49,10 @@ See [`snekapi.py`](snekbox/api/snekapi.py) and [`resources`](snekbox/api/resourc
### Initial Setup
-A Python 3.7 interpreter and the [pipenv](https://docs.pipenv.org/en/latest/) package are required. Once those requirements are satisfied, install the project's dependencies:
+A Python 3.8 interpreter and the [pipenv](https://docs.pipenv.org/en/latest/) package are required. Once those requirements are satisfied, install the project's dependencies:
```
-pipenv --sync
+pipenv sync
```
Follow that up with setting up the pre-commit hook:
@@ -122,17 +122,17 @@ The HTML will output to `./htmlcov/` by default
### The `devsh` Helper Script
-This script starts an `ash` shell inside the venv Docker container and attaches to it. Unlike the production image, the venv image that is built by this script contains dev dependencies too. The project directory is mounted inside the container so any filesystem changes made inside the container affect the actual local project.
+This script starts an `bash` shell inside the venv Docker container and attaches to it. Unlike the production image, the venv image that is built by this script contains dev dependencies too. The project directory is mounted inside the container so any filesystem changes made inside the container affect the actual local project.
#### Usage
```
-pipenv run devsh [--build [--clean]] [ash_args ...]
+pipenv run devsh [--build [--clean]] [bash_args ...]
```
* `--build` Build the venv Docker image
* `--clean` Clean up dangling Docker images (only works if `--build` precedes it)
-* `ash_args` Arguments to pass to `/bin/ash` (for example `-c "echo hello"`). An interactive shell is launched if no arguments are given
+* `bash_args` Arguments to pass to `/bin/bash` (for example `-c "echo hello"`). An interactive shell is launched if no arguments are given
#### Invoking NsJail
diff --git a/docker-compose.yml b/docker-compose.yml
index d071a71..aeb2806 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,6 +6,7 @@ services:
image: pythondiscord/snekbox:latest
network_mode: "host"
init: true
+ ipc: none
build:
context: .
dockerfile: docker/Dockerfile
diff --git a/docker/base.Dockerfile b/docker/base.Dockerfile
index 1edff49..bbd0110 100644
--- a/docker/base.Dockerfile
+++ b/docker/base.Dockerfile
@@ -1,27 +1,34 @@
-FROM alpine:3.10 as builder
-RUN apk add --no-cache --update \
- bison~=3.3 \
- bsd-compat-headers~=0.7 \
- flex~=2.6 \
- g++~=8.3 \
- gcc~=8.3 \
- git~=2.22 \
- libnl3-dev~=3.4 \
- linux-headers~=4.19 \
- make~=4.2 \
- protobuf-dev~=3.6
-RUN git clone https://github.com/google/nsjail.git /nsjail \
- && cd /nsjail \
- && git checkout 0b1d5ac03932c140f08536ed72b4b58741e7d3cf
+FROM python:3.8.0-slim-buster as builder
+RUN apt-get -y update \
+ && apt-get install -y \
+ bison=2:3.3.* \
+ flex=2.6.* \
+ g++=4:8.3.* \
+ gcc=4:8.3.* \
+ git=1:2.20.* \
+ libprotobuf-dev=3.6.* \
+ libnl-route-3-dev=3.4.* \
+ make=4.2.* \
+ pkg-config=0.29-6 \
+ protobuf-compiler=3.6.*
+RUN git clone \
+ -b '2.9' \
+ --single-branch \
+ --depth 1 \
+ https://github.com/google/nsjail.git /nsjail
WORKDIR /nsjail
RUN make
-FROM python:3.7.4-alpine3.10
+FROM python:3.8.0-slim-buster
ENV PIP_NO_CACHE_DIR=false
-RUN apk add --no-cache --update \
- libnl3~=3.4 \
- libstdc++~=8.3 \
- protobuf~=3.6
+
+RUN apt-get -y update \
+ && apt-get install -y \
+ gcc=4:8.3.* \
+ libnl-route-3-200=3.4.* \
+ libprotobuf17=3.6.* \
+ && rm -rf /var/lib/apt/lists/*
RUN pip install pipenv==2018.11.26
+
COPY --from=builder /nsjail/nsjail /usr/sbin/
RUN chmod +x /usr/sbin/nsjail
diff --git a/docker/venv.Dockerfile b/docker/venv.Dockerfile
index ae61cbb..fe5b10d 100644
--- a/docker/venv.Dockerfile
+++ b/docker/venv.Dockerfile
@@ -1,14 +1,17 @@
-FROM pythondiscord/snekbox-base:devel
+FROM pythondiscord/snekbox-base:latest
ARG DEV
ENV PIP_NO_CACHE_DIR=false \
PIPENV_DONT_USE_PYENV=1 \
PIPENV_HIDE_EMOJIS=1 \
- PIPENV_NOSPIN=1 \
- PIPENV_VENV_IN_PROJECT=1
-
-COPY Pipfile Pipfile.lock /snekbox/
+ PIPENV_NOSPIN=1
+COPY Pipfile Pipfile.lock snekbox.cfg /snekbox/
WORKDIR /snekbox
-RUN if [ -n "${DEV}" ]; pipenv sync --dev; then pipenv sync; fi
+RUN if [ -n "${DEV}" ]; \
+ then \
+ pipenv install --deploy --system --dev; \
+ else \
+ pipenv install --deploy --system; \
+ fi
diff --git a/scripts/.profile b/scripts/.profile
index bd46a17..69ad959 100644
--- a/scripts/.profile
+++ b/scripts/.profile
@@ -15,18 +15,7 @@ nsjpy() {
echo "${MEM_MAX}" > /sys/fs/cgroup/memory/NSJAIL/memory.memsw.limit_in_bytes
nsjail \
- -Mo \
- --rlimit_as 700 \
- --chroot / \
- -E LANG=en_US.UTF-8 \
- -R/usr -R/lib -R/lib64 \
- --user 65534 \
- --group 65534 \
- --time_limit 2 \
- --disable_proc \
- --iface_no_lo \
- --cgroup_pids_max=1 \
- --cgroup_mem_max="${MEM_MAX}" \
+ --config "${NSJAIL_CFG:-/snekbox/snekbox.cfg}" \
$nsj_args -- \
- /snekbox/.venv/bin/python3 -Iq -c "$@"
+ /usr/local/bin/python -Iqu -c "$@"
}
diff --git a/scripts/dev.sh b/scripts/dev.sh
index 8f5b24f..0275651 100755
--- a/scripts/dev.sh
+++ b/scripts/dev.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
# Sets up a development environment and runs a shell in a docker container.
-# Usage: dev.sh [--build [--clean]] [ash_args ...]
+# Usage: dev.sh [--build [--clean]] [bash_args ...]
if [ "$1" = "--build" ]; then
shift
@@ -40,17 +40,18 @@ docker run \
--privileged \
--network host \
--hostname pdsnk-dev \
+ --ipc="none" \
-e PYTHONDONTWRITEBYTECODE=1 \
-e PIPENV_PIPFILE="/snekbox/Pipfile" \
- -e ENV="${PWD}/scripts/.profile" \
+ -e BASH_ENV="${PWD}/scripts/.profile" \
--volume "${PWD}":"${PWD}" \
--workdir "${PWD}"\
- --entrypoint /bin/ash \
+ --entrypoint /bin/bash \
pythondiscord/snekbox-venv:dev \
>/dev/null \
# Execute the given command(s)
-docker exec -it snekbox_test /bin/ash "$@"
+docker exec -it snekbox_test /bin/bash --rcfile "${PWD}/scripts/.profile" "$@"
# Fix ownership of coverage file
# BusyBox doesn't support --reference for chown
@@ -58,7 +59,7 @@ docker exec \
-it \
-e CWD="${PWD}" \
snekbox_test \
- /bin/ash \
+ /bin/bash \
-c 'chown "$(stat -c "%u:%g" "${CWD}")" "${CWD}/.coverage"'
docker rm -f snekbox_test >/dev/null # Stop and remove the container
diff --git a/snekbox.cfg b/snekbox.cfg
new file mode 100644
index 0000000..2e8b2e0
--- /dev/null
+++ b/snekbox.cfg
@@ -0,0 +1,118 @@
+name: "snekbox"
+description: "Execute Python"
+
+mode: ONCE
+hostname: "snekbox"
+cwd: "/snekbox"
+
+time_limit: 5
+
+keep_env: false
+envar: "LANG=en_US.UTF-8"
+envar: "OMP_NUM_THREADS=1"
+envar: "OPENBLAS_NUM_THREADS=1"
+envar: "MKL_NUM_THREADS=1"
+envar: "VECLIB_MAXIMUM_THREADS=1"
+envar: "NUMEXPR_NUM_THREADS=1"
+
+keep_caps: false
+
+rlimit_as: 700
+
+clone_newnet: true
+clone_newuser: true
+clone_newns: true
+clone_newpid: true
+clone_newipc: true
+clone_newuts: true
+clone_newcgroup: true
+
+uidmap {
+ inside_id: "65534"
+ outside_id: "65534"
+}
+
+gidmap {
+ inside_id: "65534"
+ outside_id: "65534"
+}
+
+mount_proc: false
+
+mount {
+ src: "/etc/ld.so.cache"
+ dst: "/etc/ld.so.cache"
+ is_bind: true
+ rw: false
+}
+
+mount {
+ src: "/lib"
+ dst: "/lib"
+ is_bind: true
+ rw: false
+}
+
+mount {
+ src: "/lib64"
+ dst: "/lib64"
+ is_bind: true
+ rw: false
+}
+
+mount {
+ src: "/snekbox"
+ dst: "/snekbox"
+ is_bind: true
+ rw: false
+}
+
+mount {
+ src: "/usr/lib"
+ dst: "/usr/lib"
+ is_bind: true
+ rw: false
+}
+
+mount {
+ src: "/usr/local/lib"
+ dst: "/usr/local/lib"
+ is_bind: true
+ rw: false
+}
+
+mount {
+ src: "/usr/local/bin/python"
+ dst: "/usr/local/bin/python"
+ is_bind: true
+ rw: false
+}
+
+mount {
+ src: "/usr/local/bin/python3"
+ dst: "/usr/local/bin/python3"
+ is_bind: true
+ rw: false
+}
+
+mount {
+ src: "/usr/local/bin/python3.8"
+ dst: "/usr/local/bin/python3.8"
+ is_bind: true
+ rw: false
+}
+
+cgroup_mem_max: 52428800
+cgroup_mem_mount: "/sys/fs/cgroup/memory"
+cgroup_mem_parent: "NSJAIL"
+
+cgroup_pids_max: 1
+cgroup_pids_mount: "/sys/fs/cgroup/pids"
+cgroup_pids_parent: "NSJAIL"
+
+iface_no_lo: true
+
+exec_bin {
+ path: "/usr/local/bin/python"
+ arg: "-Iqu"
+}
diff --git a/snekbox/__init__.py b/snekbox/__init__.py
index 40b76db..98efdff 100644
--- a/snekbox/__init__.py
+++ b/snekbox/__init__.py
@@ -3,6 +3,7 @@ import os
import sys
from gunicorn import glogging
+from gunicorn.config import Config
DEBUG = os.environ.get("DEBUG", False)
@@ -14,7 +15,7 @@ class GunicornLogger(glogging.Logger):
access_fmt = error_fmt
datefmt = None # Use the default ISO 8601 format
- def setup(self, cfg):
+ def setup(self, cfg: Config) -> None:
"""
Set up loggers and set error logger's level to DEBUG if the DEBUG env var is set.
diff --git a/snekbox/api/resources/eval.py b/snekbox/api/resources/eval.py
index c4bd666..c567660 100644
--- a/snekbox/api/resources/eval.py
+++ b/snekbox/api/resources/eval.py
@@ -34,7 +34,7 @@ class EvalResource:
self.nsjail = NsJail()
@validate(REQ_SCHEMA)
- def on_post(self, req, resp):
+ def on_post(self, req: falcon.Request, resp: falcon.Response) -> None:
"""
Evaluate Python code and return stdout, stderr, and the return code.
diff --git a/snekbox/nsjail.py b/snekbox/nsjail.py
index d980f09..b5586bb 100644
--- a/snekbox/nsjail.py
+++ b/snekbox/nsjail.py
@@ -24,6 +24,7 @@ CGROUP_PIDS_PARENT = Path("/sys/fs/cgroup/pids/NSJAIL")
CGROUP_MEMORY_PARENT = Path("/sys/fs/cgroup/memory/NSJAIL")
NSJAIL_PATH = os.getenv("NSJAIL_PATH", "/usr/sbin/nsjail")
+NSJAIL_CFG = os.getenv("NSJAIL_CFG", "./snekbox.cfg")
MEM_MAX = 52428800
@@ -31,10 +32,10 @@ class NsJail:
"""
Core Snekbox functionality, providing safe execution of Python code.
- NsJail configuration:
+ Default NsJail configuration (snekbox.cfg):
- - Root directory is mounted as read-only
- - Time limit of 2 seconds
+ - All mounts are read-only
+ - Time limit of 5 seconds
- Maximum of 1 PID
- Maximum memory of 52428800 bytes
- Loopback interface is down
@@ -54,7 +55,10 @@ class NsJail:
self._create_parent_cgroups()
@staticmethod
- def _create_parent_cgroups(pids: Path = CGROUP_PIDS_PARENT, mem: Path = CGROUP_MEMORY_PARENT):
+ def _create_parent_cgroups(
+ pids: Path = CGROUP_PIDS_PARENT,
+ mem: Path = CGROUP_MEMORY_PARENT
+ ) -> None:
"""
Create the PIDs and memory cgroups which NsJail will use as its parent cgroups.
@@ -81,7 +85,7 @@ class NsJail:
)
@staticmethod
- def _parse_log(log_lines: Iterable[str]):
+ def _parse_log(log_lines: Iterable[str]) -> None:
"""Parse and log NsJail's log messages."""
for line in log_lines:
match = LOG_PATTERN.fullmatch(line)
@@ -114,16 +118,8 @@ class NsJail:
"""Execute Python 3 code in an isolated environment and return the completed process."""
with NamedTemporaryFile() as nsj_log:
args = (
- self.nsjail_binary, "-Mo",
- "--rlimit_as", "700",
- "--chroot", "/",
- "-E", "LANG=en_US.UTF-8",
- "-R/usr", "-R/lib", "-R/lib64",
- "--user", "65534", # nobody
- "--group", "65534", # nobody/nogroup
- "--time_limit", "2",
- "--disable_proc",
- "--iface_no_lo",
+ self.nsjail_binary,
+ "--config", NSJAIL_CFG,
"--log", nsj_log.name,
f"--cgroup_mem_max={MEM_MAX}",
"--cgroup_mem_mount", str(CGROUP_MEMORY_PARENT.parent),
@@ -132,7 +128,7 @@ class NsJail:
"--cgroup_pids_mount", str(CGROUP_PIDS_PARENT.parent),
"--cgroup_pids_parent", CGROUP_PIDS_PARENT.name,
"--",
- self.python_binary, "-Iq", "-c", code
+ self.python_binary, "-Iqu", "-c", code
)
msg = "Executing code..."
diff --git a/tests/test_nsjail.py b/tests/test_nsjail.py
index bb176d9..0b755b2 100644
--- a/tests/test_nsjail.py
+++ b/tests/test_nsjail.py
@@ -56,14 +56,17 @@ class NsJailTests(unittest.TestCase):
self.assertEqual(result.stderr, None)
def test_read_only_file_system(self):
- code = dedent("""
- open('hello', 'w').write('world')
- """).strip()
-
- result = self.nsjail.python3(code)
- self.assertEqual(result.returncode, 1)
- self.assertIn("Read-only file system", result.stdout)
- self.assertEqual(result.stderr, None)
+ for path in ("/", "/etc", "/lib", "/lib64", "/snekbox", "/usr"):
+ with self.subTest(path=path):
+ code = dedent(f"""
+ with open('{path}/hello', 'w') as f:
+ f.write('world')
+ """).strip()
+
+ result = self.nsjail.python3(code)
+ self.assertEqual(result.returncode, 1)
+ self.assertIn("Read-only file system", result.stdout)
+ self.assertEqual(result.stderr, None)
def test_forkbomb_resource_unavailable(self):
code = dedent("""
@@ -122,3 +125,52 @@ class NsJailTests(unittest.TestCase):
"INFO:snekbox.nsjail:pid=20 ([STANDALONE MODE]) exited with status: 2, (PIDs left: 0)",
log.output
)
+
+ def test_shm_and_tmp_not_mounted(self):
+ for path in ("/dev/shm", "/run/shm", "/tmp"):
+ with self.subTest(path=path):
+ code = dedent(f"""
+ with open('{path}/test', 'wb') as file:
+ file.write(bytes([255]))
+ """).strip()
+
+ result = self.nsjail.python3(code)
+ self.assertEqual(result.returncode, 1)
+ self.assertIn("No such file or directory", result.stdout)
+ self.assertEqual(result.stderr, None)
+
+ def test_multiprocessing_shared_memory_disabled(self):
+ code = dedent("""
+ from multiprocessing.shared_memory import SharedMemory
+ try:
+ SharedMemory('test', create=True, size=16)
+ except FileExistsError:
+ pass
+ """).strip()
+
+ result = self.nsjail.python3(code)
+ self.assertEqual(result.returncode, 1)
+ self.assertIn("Function not implemented", result.stdout)
+ self.assertEqual(result.stderr, None)
+
+ def test_numpy_import(self):
+ result = self.nsjail.python3("import numpy")
+ self.assertEqual(result.returncode, 0)
+ self.assertEqual(result.stdout, "")
+ self.assertEqual(result.stderr, None)
+
+ def test_output_order(self):
+ stdout_msg = "greetings from stdout!"
+ stderr_msg = "hello from stderr!"
+ code = dedent(f"""
+ print({stdout_msg!r})
+ raise ValueError({stderr_msg!r})
+ """).strip()
+
+ result = self.nsjail.python3(code)
+ self.assertLess(
+ result.stdout.find(stdout_msg),
+ result.stdout.find(stderr_msg),
+ msg="stdout does not come before stderr"
+ )
+ self.assertEqual(result.stderr, None)