Repository navigation
Codejail Tutor plugin - MVP #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
65993ed
0d94906
e3aa9f6
5efde16
f61cb35
eda975f
8b71349
4c01860
b885745
2b3cc68
011eb8d
f085ef2
5a772c6
02c0c79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| .*.swp | ||
| !.gitignore | ||
| TODO | ||
| __pycache__ | ||
| *.egg-info/ | ||
| /build/ | ||
| /dist/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| recursive-include tutorcodejail/patches * | ||
| recursive-include tutorcodejail/templates * |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import io | ||
| import os | ||
| from setuptools import setup, find_packages | ||
|
|
||
| HERE = os.path.abspath(os.path.dirname(__file__)) | ||
|
|
||
|
|
||
| def load_readme(): | ||
| with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f: | ||
| return f.read() | ||
|
|
||
|
|
||
| def load_about(): | ||
| about = {} | ||
| with io.open( | ||
| os.path.join(HERE, "tutorcodejail", "__about__.py"), | ||
| "rt", | ||
| encoding="utf-8", | ||
| ) as f: | ||
| exec(f.read(), about) # pylint: disable=exec-used | ||
| return about | ||
|
|
||
|
|
||
| ABOUT = load_about() | ||
|
|
||
|
|
||
| setup( | ||
| name="tutor-contrib-codejail", | ||
| version=ABOUT["__version__"], | ||
| url="https://github.com/github/tutor-contrib-codejail", | ||
| project_urls={ | ||
| "Code": "https://github.com/edunext/tutor-contrib-codejail", | ||
| "Issue tracker": "https://github.com/edunext/tutor-contrib-codejail/issues", | ||
| }, | ||
| license="AGPLv3", | ||
| author="Eric Herrera", | ||
| description="codejail plugin for Tutor", | ||
| long_description=load_readme(), | ||
| packages=find_packages(exclude=["tests*"]), | ||
| include_package_data=True, | ||
| python_requires=">=3.5", | ||
| install_requires=["tutor-openedx"], | ||
| entry_points={ | ||
| "tutor.plugin.v0": [ | ||
| "codejail = tutorcodejail.plugin" | ||
| ] | ||
| }, | ||
| classifiers=[ | ||
| "Development Status :: 3 - Alpha", | ||
| "Intended Audience :: Developers", | ||
| "License :: OSI Approved :: GNU Affero General Public License v3", | ||
| "Operating System :: OS Independent", | ||
| "Programming Language :: Python", | ||
| "Programming Language :: Python :: 3.5", | ||
| "Programming Language :: Python :: 3.6", | ||
| "Programming Language :: Python :: 3.7", | ||
| "Programming Language :: Python :: 3.8", | ||
| "Programming Language :: Python :: 3.9", | ||
| "Programming Language :: Python :: 3.10", | ||
| ], | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| __version__ = "0.1.0" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| "ENABLE_CODEJAIL_REST_SERVICE": true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| "CODE_JAIL_REST_SERVICE_HOST": "http://{{ CODEJAIL_HOST }}:8550" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| codejailservice: | ||
| command: ./manage.py runserver 0.0.0.0:8550 | ||
| ports: | ||
| - "8550:8550" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| codejail_apparmor-job: | ||
| image: ednxops/codejail_apparmor_loader:latest | ||
| privileged: true | ||
| volumes: | ||
| - ../plugins/codejail/apps/profiles/docker-edx-sandbox:/profiles/docker-edx-sandbox:ro | ||
| - /sys:/sys | ||
| - /etc/apparmor.d:/etc/apparmor.d |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| #############Codejail service | ||
| codejailservice: | ||
| image: {{ CODEJAIL_DOCKER_IMAGE }} | ||
| environment: | ||
| DJANGO_SETTINGS_MODULE: codejailservice.settings.tutor | ||
| security_opt: | ||
| - apparmor:docker-edx-sandbox | ||
| volumes: | ||
| - ../plugins/codejail/apps/settings/tutor.py:/openedx/codejailservice/codejailservice/settings/tutor.py:ro | ||
| - ../../data/codejail:/openedx/data | ||
| restart: unless-stopped |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| from glob import glob | ||
| import os | ||
| import pkg_resources | ||
|
|
||
| from .__about__ import __version__ | ||
|
|
||
| templates = pkg_resources.resource_filename( | ||
| "tutorcodejail", "templates" | ||
| ) | ||
|
|
||
| config = { | ||
| "add": { | ||
| "SECRET_KEY": "{{ 24|random_string }}", | ||
| }, | ||
| "defaults": { | ||
| "VERSION": __version__, | ||
| "HOST": "codejailservice.{{ LMS_HOST }}", | ||
| "DOCKER_IMAGE": "docker.io/ednxops/codejailservice:latest", | ||
| } | ||
| } | ||
|
|
||
| hooks = { | ||
| "build-image": { | ||
| "codejail": "{{ CODEJAIL_DOCKER_IMAGE }}", | ||
| "codejail_apparmor": "docker.io/ednxops/codejail_apparmor:latest" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest to replace ":latest" by the actual plugin version. This guarantees that the Docker image is always pinned. This is why I always add a "VERSION" setting. See for instance: https://github.com/overhangio/tutor-mfe/blob/932f2db9fdf4c9370abeec5e89a558d9f590f133/tutormfe/plugin.py#L13 |
||
| }, | ||
| "remote-image": { | ||
| "codejail": "{{ CODEJAIL_DOCKER_IMAGE }}", | ||
| "codejail_apparmor": "docker.io/ednxops/codejail_apparmor:latest" | ||
| }, | ||
| "init": ["codejail_apparmor"] | ||
| } | ||
|
|
||
|
|
||
| def patches(): | ||
| all_patches = {} | ||
| patches_dir = pkg_resources.resource_filename( | ||
| "tutorcodejail", "patches" | ||
| ) | ||
| for path in glob(os.path.join(patches_dir, "*")): | ||
| with open(path) as patch_file: | ||
| name = os.path.basename(path) | ||
| content = patch_file.read() | ||
| all_patches[name] = content | ||
| return all_patches | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #include <tunables/global> | ||
|
|
||
| profile docker-edx-sandbox flags=(attach_disconnected,mediate_deleted) { | ||
| #include <abstractions/base> | ||
|
|
||
| network, | ||
| capability, | ||
| file, | ||
| umount, | ||
| signal (receive) peer=unconfined, | ||
| signal (receive) peer=cri-containerd.apparmor.d, | ||
| signal (send,receive) peer=docker-edx-sandbox, | ||
|
|
||
| deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir) | ||
| # deny write to files not in /proc/<number>/** or /proc/sys/** | ||
| deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w, | ||
| deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel) | ||
| deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/ | ||
| deny @{PROC}/sysrq-trigger rwklx, | ||
| deny @{PROC}/mem rwklx, | ||
| deny @{PROC}/kmem rwklx, | ||
| deny @{PROC}/kcore rwklx, | ||
|
|
||
| deny mount, | ||
| deny /sys/[^f]*/** wklx, | ||
| deny /sys/f[^s]*/** wklx, | ||
| deny /sys/fs/[^c]*/** wklx, | ||
| deny /sys/fs/c[^g]*/** wklx, | ||
| deny /sys/fs/cg[^r]*/** wklx, | ||
| deny /sys/firmware/** rwklx, | ||
| deny /sys/kernel/security/** rwklx, | ||
|
|
||
| ptrace (trace,read) peer=docker-edx-sandbox, | ||
|
|
||
| /sandbox/venv/bin/python Cx -> child, | ||
| profile child flags=(attach_disconnected,mediate_deleted){ | ||
| #include <abstractions/base> | ||
| #include <abstractions/python> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will only work if the same python version is installed on the host as in the container. I'm afraid we need to copy-paste the contents of this file into this template.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @regisb This is the content of that file in my host: I checked those paths in the codejailservice container and any of them actually exists, I think it is because I am using pyenv. Can we just then get rid of this ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing is that you cannot add So you need to copy-paste the contents of this file and to change the paths such that it matches the paths for the pyenv-installed python in the Docker container. |
||
|
|
||
| # | ||
| # Whitelist particiclar shared objects from the system | ||
| # python installation | ||
| # | ||
| /sandbox/venv/** mr, | ||
| /opt/pyenv/versions/3.5.10/** mr, | ||
| /tmp/codejail-*/ rix, | ||
| /tmp/codejail-*/** wrix, | ||
|
|
||
| # | ||
| # Whitelist particular shared objects from the system | ||
| # python installation | ||
| # | ||
| /sandbox/venv/.config/ wrix, | ||
| /sandbox/venv/.cache/ wrix, | ||
| /sandbox/venv/.config/** wrix, | ||
| /sandbox/venv/.cache/** wrix, | ||
|
|
||
| # Matplot lib needs fonts to make graphs | ||
| /usr/share/fonts/ r, | ||
| /usr/share/fonts/** r, | ||
| /usr/local/share/fonts/ r, | ||
| /usr/local/share/fonts/** r, | ||
|
|
||
| # | ||
| # Allow access to selections from /proc | ||
| # | ||
| /proc/*/mounts r, | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| from .base import * | ||
|
|
||
| from codejail.django_integration_utils import apply_django_settings | ||
|
|
||
| SECRET_KEY = "{{ CODEJAIL_SECRET_KEY }}" | ||
| ALLOWED_HOSTS = [ | ||
| "{{ CODEJAIL_HOST }}", | ||
| ] | ||
|
|
||
| #################### Python sandbox ############################################ | ||
|
|
||
| CODE_JAIL = { | ||
| 'python_bin': '/sandbox/venv/bin/python', | ||
| # User to run as in the sandbox. | ||
| 'user': 'sandbox', | ||
|
|
||
| # Configurable limits. | ||
| # Setting all of them to 0 to disable limits in conatiners. | ||
| 'limits': { | ||
| # | ||
| 'NPROC': 0, | ||
| # How many CPU seconds can jailed code use? | ||
| 'CPU': 0, | ||
| # Limit the memory of the jailed process to something high but not | ||
| # infinite (512MiB in bytes) | ||
| 'VMEM': 0, | ||
| # Time in seconds that the jailed process has to run. | ||
| 'REALTIME': 0, | ||
| # Needs to be non-zero so that jailed code can use it as their temp directory.(10MiB in bytes) | ||
| 'FSIZE': 10485760, | ||
| # Disable usage of proxy (force thread-safe) | ||
| 'PROXY': 0, | ||
| }, | ||
|
|
||
| # Overrides to default configurable 'limits' (above). | ||
| # Keys should be course run ids. | ||
| # Values should be dictionaries that look like 'limits'. | ||
| "limit_overrides": {}, | ||
| } | ||
|
|
||
| apply_django_settings(CODE_JAIL) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless I'm mistaken, creating a Django project would require defining a database. A full Django project seems overkill for what you are trying to achieve here, meaning a stateless python interpreter with a very basic API. Can I suggest relying on a more lightweight framework instead, such as Flask? |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| FROM docker.io/ubuntu:20.04 as minimal | ||
| MAINTAINER Overhang.io <contact@overhang.io> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should change this if you intend to support this image :) |
||
|
|
||
| ENV DEBIAN_FRONTEND=noninteractive | ||
| RUN apt update && \ | ||
| apt install -y build-essential curl git language-pack-en | ||
| ENV LC_ALL en_US.UTF-8 | ||
|
|
||
| ###### Install python with pyenv in /opt/pyenv and create virtualenv in /openedx/venv | ||
| FROM minimal as python | ||
| # https://github.com/pyenv/pyenv/wiki/Common-build-problems#prerequisites | ||
| RUN apt update && \ | ||
| apt install -y libssl-dev zlib1g-dev libbz2-dev \ | ||
| libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \ | ||
| xz-utils tk-dev libffi-dev liblzma-dev python-openssl git subversion | ||
| ENV PYENV_ROOT /opt/pyenv | ||
| RUN git clone https://github.com/pyenv/pyenv $PYENV_ROOT --branch v1.2.21 --depth 1 | ||
|
|
||
| ARG CODEJAILSERVICE_PYTHON_VERSION=3.8.6 | ||
| RUN $PYENV_ROOT/bin/pyenv install $CODEJAILSERVICE_PYTHON_VERSION | ||
|
|
||
| ARG SANDBOX_PYTHON_VERSION=3.5.10 | ||
| RUN $PYENV_ROOT/bin/pyenv install $SANDBOX_PYTHON_VERSION | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the future, I think that all code below this line should be run as a different user (e.g: |
||
| RUN $PYENV_ROOT/versions/$CODEJAILSERVICE_PYTHON_VERSION/bin/python -m venv /openedx/venv | ||
| RUN $PYENV_ROOT/versions/$SANDBOX_PYTHON_VERSION/bin/python -m venv --copies /sandbox/venv | ||
|
|
||
| ###### Codejail service code | ||
| FROM minimal as code | ||
| RUN git clone https://github.com/eduNEXT/codejailservice.git --branch eric/mvp --depth 1 /openedx/codejailservice | ||
| WORKDIR /openedx/codejailservice | ||
|
|
||
| ###### Install python requirements in virtualenv | ||
| FROM python as codejailservice-python-requirements | ||
|
|
||
| ENV PATH /openedx/venv/bin:${PATH} | ||
| ENV VIRTUAL_ENV /openedx/venv/ | ||
|
|
||
| COPY --from=code /openedx/codejailservice /openedx/codejailservice | ||
| WORKDIR /openedx/codejailservice | ||
| RUN pip3 install -r requirements/base.txt | ||
| RUN pip3 install ipdb | ||
|
|
||
| ###### Install python requirements in virtualenv | ||
| FROM python as sandbox-python-requirements | ||
|
|
||
| ENV PATH /sandbox/venv/bin:${PATH} | ||
| ENV VIRTUAL_ENV /sandbox/venv/ | ||
|
|
||
| WORKDIR /var/tmp | ||
| RUN mkdir -p common/lib/ | ||
| RUN svn export https://github.com/edx/edx-platform.git/tags/open-release/koa.3/common/lib/sandbox-packages common/lib/sandbox-packages | ||
| RUN svn export https://github.com/edx/edx-platform.git/tags/open-release/koa.3/common/lib/symmath common/lib/symmath | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right, it is a good idea to copy it from the edx-platform image, I am going to try that. |
||
| # RUN wget https://raw.githubusercontent.com/edx/edx-platform/open-release/koa.3/requirements/edx-sandbox/base.txt && pip3 install base.txt | ||
| RUN wget https://raw.githubusercontent.com/edx/edx-platform/open-release/koa.3/requirements/edx-sandbox/py35.txt && pip3 install -r py35.txt | ||
|
|
||
| ##### Prod image | ||
| FROM minimal as production | ||
|
|
||
| # Install system requirements | ||
| RUN apt update && \ | ||
| apt install -y sudo | ||
|
|
||
| COPY --from=code /openedx/codejailservice /openedx/codejailservice | ||
| COPY --from=python /opt/pyenv /opt/pyenv | ||
| COPY --from=codejailservice-python-requirements /openedx/venv /openedx/venv | ||
| COPY --from=sandbox-python-requirements /sandbox/venv /sandbox/venv | ||
|
|
||
| # Setup sandbox | ||
| ENV SANDBOX_ENV=/sandbox/venv | ||
| RUN groupadd -r sandbox && useradd -m -r -g sandbox sandbox && chown -R sandbox:sandbox /sandbox | ||
|
|
||
| ENV PATH /openedx/venv/bin:${PATH} | ||
| ENV VIRTUAL_ENV /openedx/venv/ | ||
| WORKDIR /openedx/codejailservice | ||
|
|
||
| EXPOSE 8000 | ||
| CMD gunicorn --workers=2 --name codejailservice --bind=0.0.0.0:8000 --max-requests=1000 codejailservice.wsgi:application | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @NeOneSoft please change here to use uwsgi instead of gunicorn |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| FROM golang:latest as go_compiler | ||
|
|
||
| RUN mkdir /app | ||
| WORKDIR /app | ||
| ADD https://raw.githubusercontent.com/kubernetes/kubernetes/master/test/images/apparmor-loader/loader.go loader.go | ||
| RUN go mod init loader | ||
| RUN go get k8s.io/klog/v2 | ||
| RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -a -installsuffix cgo --ldflags '-w' -o loader . | ||
|
|
||
| FROM alpine:latest | ||
|
|
||
| RUN apk add apparmor libapparmor --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ --allow-untrusted && \ | ||
| apk add --no-cache musl\>1.1.20 --repository http://dl-cdn.alpinelinux.org/alpine/edge/main/ | ||
|
|
||
| COPY --from=go_compiler /app/loader /usr/bin/loader |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /usr/bin/loader -logtostderr -v=2 /profiles |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add:
restart: unless-stopped.