Skip to content
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

Drop ECR for testing builds and Add 22.04 Support #201

Merged
merged 16 commits into from
Oct 22, 2024
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
40 changes: 18 additions & 22 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,40 @@ on:
jobs:
codejail_ci:
name: tests
runs-on: ubuntu-20.04
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
MoisesGSalas marked this conversation as resolved.
Show resolved Hide resolved
matrix:
include:
- python_version: '3.8'
docker_tag: latest
- python_version: '3.11'
docker_tag: '3.11'
ubuntu_version: '20.04'
os: "ubuntu-20.04"
- python_version: '3.11'
ubuntu_version: '22.04'
os: "ubuntu-22.04"
# Disabling this for now because it's failing and we need to figure out
# next steps to fix this.
# - python_version: '3.11'
# ubuntu_version: '24.04'
# os: "ubuntu-24.04"

steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.TOOLS_EDX_ECR_USER_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.TOOLS_EDX_ECR_USER_AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2

- name: Parse custom apparmor profile
run: sudo apparmor_parser -r -W apparmor-profiles/home.sandbox.codejail_sandbox-python3.bin.python

- name: Pull codejail CI image
run: docker pull 257477529851.dkr.ecr.us-east-1.amazonaws.com/openedx-codejail:latest

- name: Build latest code changes into CI image
run: |
docker build --cache-from 257477529851.dkr.ecr.us-east-1.amazonaws.com/openedx-codejail \
-t 257477529851.dkr.ecr.us-east-1.amazonaws.com/openedx-codejail \
--build-arg python_version=${{ matrix.python_version }} .
docker build -t openedx-codejail \
--cache-to type=gha \
--cache-from type=gha \
--build-arg python_version=${{ matrix.python_version }} \
--build-arg ubuntu_version=${{ matrix.ubuntu_version }} .

- name: Run container with custom apparmor profile and codejail CI image
run: |
docker run --name=codejail --privileged -d --security-opt apparmor=apparmor_profile \
257477529851.dkr.ecr.us-east-1.amazonaws.com/openedx-codejail tail -f /dev/null
openedx-codejail tail -f /dev/null

- name: Run Non Proxy Tests
run: docker exec -t codejail bash -c 'make clean && make test_no_proxy'
Expand Down
40 changes: 0 additions & 40 deletions .github/workflows/push-docker-image.yml

This file was deleted.

17 changes: 13 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
FROM ubuntu:focal
ARG ubuntu_version="20.04"

FROM ubuntu:${ubuntu_version}
SHELL ["/bin/bash", "-c"]

ARG python_version=3.8
ARG python_version="3.8"

# Install Codejail Packages
ENV TZ=Etc/UTC
Expand Down Expand Up @@ -33,8 +35,15 @@ RUN addgroup $CODEJAIL_GROUP
RUN adduser --disabled-login --disabled-password $CODEJAIL_TEST_USER --ingroup $CODEJAIL_GROUP

# Switch to non root user inside Docker container
RUN addgroup ubuntu
RUN adduser --disabled-login --disabled-password ubuntu --ingroup ubuntu
RUN getent group ubuntu || groupadd ubuntu
RUN getent passwd ubuntu || adduser --disabled-login --disabled-password ubuntu --ingroup ubuntu

# Remove using PAM to set limits for sudo.
# We want codejail to manage the limits so we remove this line from the sudo pam config
# if we don't the forked process gets limits based on /etc/security/limits.conf which by
# default does not set any limits on the forked process.
# This line was not there on Ubuntu 20.04 but was added in 22.04
RUN sed -i '/pam_limits.so/d' /etc/pam.d/sudo

# Give Ownership of sandbox env to sandbox group and user
RUN chown -R $CODEJAIL_TEST_USER:$CODEJAIL_GROUP $CODEJAIL_TEST_VENV
Expand Down
26 changes: 22 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ using the same API, but will not guard against malicious code. This allows the
same code to be used on safe-configured or non-safe-configured developer's
machines.

A CodeJail sandbox consists of several pieces:
A CodeJail sandbox consists of several pieces:

#) Sandbox environment. For a Python setup, this would be Python and
associated core packages. This is denoted throughout this document
as **<SANDENV>**. This is read-only.
as **<SANDENV>**. This is read-only.

#) Sandbox packages. These are additional packages needed for a given
run. For example, this might be a grader written by an instructor
Expand All @@ -34,7 +34,7 @@ A CodeJail sandbox consists of several pieces:
#) Untrusted packages. This is typically the code submitted by the
student to be tested on the server, as well as any data the code
may need to modify. This is denoted throughout this document as
**<UNTRUSTED_PACK>**. This is currently read-only, but may need to
**<UNTRUSTED_PACK>**. This is currently read-only, but may need to
be read-write for some applications.

#) OS packages. These are standard system libraries needed to run
Expand All @@ -48,6 +48,20 @@ sandboxes. This will be referred to as **<SANDBOX_CALLER>**. The
second account is the account under which the sandbox runs. This is
typically the account 'sandbox.'

Supported Versions
------------------

This library currently is tested to work with the following versions

Python:

* 3.11

Ubuntu:

* 20.04
* 22.04

Installation
------------

Expand Down Expand Up @@ -129,6 +143,10 @@ Other details here that depend on your configuration:

7. Reactivate your project's main virtualenv again.

8. Disable using PAM to set rlimits::

sed -i '/pam_limits.so/d' /etc/pam.d/sudo

Using CodeJail
--------------

Expand All @@ -142,7 +160,7 @@ commands at your Python terminal::
codejail.safe_exec.safe_exec("output=open('/etc/passwd').read()", jailed_globals)
print(jailed_globals) # should be unreachable if codejail is working properly

This should fail with an exception.
This should fail with an exception.

If you need to change the packages installed into your sandbox's virtualenv,
you'll need to disable AppArmor, because your sandboxed Python doesn't have
Expand Down
10 changes: 10 additions & 0 deletions apparmor-profiles/home.sandbox.codejail_sandbox-python3.bin.python
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ profile apparmor_profile /home/sandbox/codejail_sandbox-python{3.[0-9],3.[1-9][0
#include <abstractions/base>
#include <abstractions/python>

# Deny network access and socket operations
# Note: If this profile is being run on a docker container
# then this directive might not be sufficient. Docker network
# interfaces are created in a different namespace from the one that
# apparmor can monitor and manage and so apparmor can't always deny
# network access to the container. Please be sure to test
# network access from within your container for the jailed process
# to be sure that everything is secure.
deny network,

/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/**.{pyc,so,so.*[0-9]} mr,
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/**.{egg,py,pth} r,
/usr/{local/,}lib{,32,64}/python{2.[4-7],3,3.[0-9],3.[1-9][0-9]}/{site,dist}-packages/ r,
Expand Down
2 changes: 1 addition & 1 deletion codejail/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""init"""

__version__ = '3.4.1'
__version__ = '3.5.0'
2 changes: 2 additions & 0 deletions codejail/jail_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ def __init__(self):
self.stdout = self.stderr = self.status = None


# pylint: disable=too-many-positional-arguments
def jail_code(command, code=None, files=None, extra_files=None, argv=None,
stdin=None, limit_overrides_context=None, slug=None):
"""
Expand Down Expand Up @@ -229,6 +230,7 @@ def jail_code(command, code=None, files=None, extra_files=None, argv=None,
# pylint: disable=too-many-statements

if not is_configured(command):
# pylint: disable=broad-exception-raised
raise Exception("jail_code needs to be configured for %r" % command)

# We make a temp directory to serve as the home of the sandboxed code.
Expand Down
2 changes: 1 addition & 1 deletion codejail/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def run_subprocess_through_proxy(*args, **kwargs): # pylint: disable=inconsiste
proxy_stdout = proxy.stdout.readline()
if not proxy_stdout:
# EOF: the proxy must have died.
raise Exception("Proxy process died unexpectedly!")
raise Exception("Proxy process died unexpectedly!") # pylint: disable=broad-exception-raised
status, stdout, stderr, log_calls = deserialize_out(proxy_stdout.rstrip())

# Write all the log messages to the log, and return.
Expand Down
2 changes: 2 additions & 0 deletions codejail/safe_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class SafeExecException(Exception):
"""


# pylint: disable=too-many-positional-arguments
def safe_exec(
code,
globals_dict,
Expand Down Expand Up @@ -235,6 +236,7 @@ def decode_object(obj):
return json.loads(json.dumps(jd))


# pylint: disable=too-many-positional-arguments
def not_safe_exec(
code,
globals_dict,
Expand Down
1 change: 1 addition & 0 deletions codejail/subproc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
log = logging.getLogger("codejail")


# pylint: disable=too-many-positional-arguments
def run_subprocess(
cmd, stdin=None, cwd=None, env=None, rlimits=None, realtime=None,
slug=None,
Expand Down
2 changes: 2 additions & 0 deletions codejail/tests/test_safe_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ def test_importing_lots_of_crap(self):
set_limit('REALTIME', 10)
globs = {}
self.safe_exec(textwrap.dedent("""\
import os
os.environ['OPENBLAS_NUM_THREADS'] = '1'
from numpy import *
a = 1723
"""), globs)
Expand Down
37 changes: 2 additions & 35 deletions pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
# pygtk.require().
#init-hook=

# Profiled execution.
profile=no

# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS, migrations
Expand Down Expand Up @@ -40,7 +37,6 @@ disable=

# Might use these when the code is in better shape
# C0302: Too many lines in module
# R0201: Method could be a function
# R0901: Too many ancestors
# R0902: Too many instance attributes
# R0903: Too few public methods (1/2)
Expand All @@ -49,7 +45,7 @@ disable=
# R0912: Too many branches
# R0913: Too many arguments
# R0914: Too many local variables
C0301,C0302,R0201,R0901,R0902,R0903,R0904,R0911,R0912,R0913,R0914,
C0301,C0302,R0901,R0902,R0903,R0904,R0911,R0912,R0913,R0914,
unspecified-encoding,consider-using-with,consider-using-f-string,invalid-name


Expand All @@ -59,14 +55,6 @@ disable=
# (visual studio) and html
output-format=text

# Include message's id in output
include-ids=yes

# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no

# Tells whether to display a full report or only the messages
reports=no

Expand All @@ -77,10 +65,6 @@ reports=no
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)

# Add a comment according to your evaluation note. This is used by the global
# evaluation report (RP0004).
comment=no


[TYPECHECK]

Expand All @@ -92,10 +76,6 @@ ignore-mixin-members=yes
# (useful for classes with attributes dynamically set).
ignored-classes=SQLObject

# When zope mode is activated, add a predefined set of Zope acquired attributes
# to generated-members.
zope=no

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
Expand All @@ -115,12 +95,6 @@ generated-members=

[BASIC]

# Required attributes for module, separated by a comma
required-attributes=

# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input

# Regular expression which should only match correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$

Expand Down Expand Up @@ -238,9 +212,6 @@ max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6

# Maximum number of branch for function / method body
max-branchs=12

# Maximum number of statements in function / method body
max-statements=50

Expand All @@ -259,10 +230,6 @@ max-public-methods=20

[CLASSES]

# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by

# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp

Expand All @@ -274,4 +241,4 @@ valid-classmethod-first-arg=cls

# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception
overgeneral-exceptions=builtins.Exception
Loading