Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.*.swp
!.gitignore
TODO
__pycache__
*.egg-info/
/build/
/dist/
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
recursive-include tutorcodejail/patches *
recursive-include tutorcodejail/templates *
61 changes: 61 additions & 0 deletions setup.py
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",
],
)
1 change: 1 addition & 0 deletions tutorcodejail/__about__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "12.0.0"
Empty file added tutorcodejail/__init__.py
Empty file.
Empty file.
3 changes: 3 additions & 0 deletions tutorcodejail/patches/cms-env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"CODE_JAIL_REST_SERVICE_HOST": "http://{{ CODEJAIL_HOST }}:8550",
"CODE_JAIL_REST_SERVICE_CONNECT_TIMEOUT": 0.5,
"CODE_JAIL_REST_SERVICE_READ_TIMEOUT": 3.5
1 change: 1 addition & 0 deletions tutorcodejail/patches/common-env-features
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"ENABLE_CODEJAIL_REST_SERVICE": true
3 changes: 3 additions & 0 deletions tutorcodejail/patches/lms-env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"CODE_JAIL_REST_SERVICE_HOST": "http://{{ CODEJAIL_HOST }}:8550",
"CODE_JAIL_REST_SERVICE_CONNECT_TIMEOUT": 0.5,
"CODE_JAIL_REST_SERVICE_READ_TIMEOUT": 3.5
8 changes: 8 additions & 0 deletions tutorcodejail/patches/local-docker-compose-dev-services
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
codejailservice:
command: flask run --host 0.0.0.0 --port 8550
environment:
FLASK_ENV: development
FLASK_APP_SETTINGS: codejailservice.config.DevelopmentConfig
ports:
- "8550:8550"
restart: unless-stopped
7 changes: 7 additions & 0 deletions tutorcodejail/patches/local-docker-compose-jobs-services
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
11 changes: 11 additions & 0 deletions tutorcodejail/patches/local-docker-compose-services
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#############Codejail service
codejailservice:
image: {{ CODEJAIL_DOCKER_IMAGE }}
environment:
FLASK_APP_SETTINGS: config.ProductionConfig
security_opt:
- apparmor:docker-edx-sandbox
volumes:
- ../plugins/codejail/apps/config/tutor.py:/openedx/codejailservice/codejailservice/tutor.py:ro
- ../../data/codejail:/openedx/data
restart: unless-stopped
47 changes: 47 additions & 0 deletions tutorcodejail/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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",
"DOCKER_IMAGE": f"docker.io/ednxops/codejailservice:{__version__}",
"SANDBOX_PYTHON_VERSION": "3.5.10",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest moving this to the "defaults" section. Then, use it as CODEJAIL_SANDBOX_PYTHON_VERSION. When possible, we should really try to avoid "set" entries. They are only required to override existing tutor settings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

},
"set":{}
}

hooks = {
"build-image": {
"codejail": "{{ CODEJAIL_DOCKER_IMAGE }}",
"codejail_apparmor": f"docker.io/ednxops/codejail_apparmor:{__version__}"
},
"remote-image": {
"codejail": "{{ CODEJAIL_DOCKER_IMAGE }}",
"codejail_apparmor": f"docker.io/ednxops/codejail_apparmor:{__version__}"
},
"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
Empty file.
7 changes: 7 additions & 0 deletions tutorcodejail/templates/codejail/apps/config/tutor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from base import BaseConfig

class DevConfig(BaseConfig):
pass

class ProductionConfig(BaseConfig):
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#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>

#
# Python abstractions adapted from https://gitlab.com/apparmor/apparmor/-/raw/master/profiles/apparmor.d/abstractions/python
#
/opt/pyenv/versions/{2.[4-7].*,3.[0-9].*}/lib/python{2.[4-7],3.[0-9]}/**.{pyc,so} mr,
/opt/pyenv/versions/{2.[4-7].*,3.[0-9].*}/lib/python{2.[4-7],3.[0-9]}/**.{egg,py,pth} r,
/opt/pyenv/versions/{2.[4-7].*,3.[0-9].*}/lib/python{2.[4-7],3.[0-9]}/{site,dist}-packages/ r,
/opt/pyenv/versions/3.[0-9].*/lib/python3.[0-9]/lib-dynload/*.so mr,

/opt/pyenv/versions/{2.[4-7].*,3.[0-9].*}/include/python{2.[4-7],3.[0-9]}*/pyconfig.h r,


#
# 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,
}
}
Empty file.
87 changes: 87 additions & 0 deletions tutorcodejail/templates/codejail/build/codejail/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
FROM docker.io/ubuntu:20.04 as minimal
MAINTAINER edunext.co <contact@edunext.co>

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={{ CODEJAIL_SANDBOX_PYTHON_VERSION }}
RUN $PYENV_ROOT/bin/pyenv install $SANDBOX_PYTHON_VERSION

Copy link
Contributor

@regisb regisb Sep 9, 2021

Choose a reason for hiding this comment

The 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: USER openedx). This is important for people running Docker containers in unprivileged environments (as is often the case in Kubernetes). It's not a deal-breaker for this first release, but you should this in mind for the future.

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 {{ CODEJAIL_VERSION }} --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/

COPY --from={{ DOCKER_IMAGE_OPENEDX }} /openedx/edx-platform/common/lib/sandbox-packages common/lib/sandbox-packages
COPY --from={{ DOCKER_IMAGE_OPENEDX }} /openedx/edx-platform/common/lib/symmath common/lib/symmath
COPY --from={{ DOCKER_IMAGE_OPENEDX }} /openedx/edx-platform/requirements/edx-sandbox/py35.txt py35.txt
RUN 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 uwsgi \
--http 0.0.0.0:8000 \
--thunder-lock \
--single-interpreter \
--enable-threads \
--processes=${UWSGI_WORKERS:-2} \
--buffer-size=8192 \
--max-requests=1000 \
--wsgi-file /openedx/codejailservice/wsgi.py
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
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/usr/bin/loader -logtostderr -v=2 /profiles