EpicBox fork. Original package developers is StepicOrg.
Project description
Epicboxie
Forked from StepicOrg/epicbox for some improvements.
This fork allows to expose container ports with host machine and to work with sandbox interactively.
epicboxie.run_interactive
is a context manager that runs sandbox:
import time
import requests
import epicboxie
epicboxie.configure(
profiles=[
epicboxie.Profile('python', 'python:3.6.5-alpine')
]
)
with open('server.py', 'rb') as f:
contents = f.read()
files = [{'name': 'main.py', 'content': contents}]
limits = {'cputime': 1, 'memory': 64}
ports = {8000: 8000}
with epicboxie.run_interactive('python', 'python3 main.py', files=files, limits=limits, ports=ports) as run:
time.sleep(2)
print(requests.get('http://localhost:8000').status_code)
result = run.results
The ports
parameter is also added to old run
function.
Interaction with standard I/O is done with run.docker_interaction.read_sock()
and run.docker_interaction.write_sock()
:
import time
import requests
import epicboxie
epicboxie.configure(
profiles=[
epicboxie.Profile('python', 'python:3.6.5-alpine')
]
)
files = [{'name': 'main.py', 'content': b'print(input("Input data: ")[::-1])'}]
limits = {'cputime': 1, 'memory': 64}
ports = {8000: 8000}
with epicboxie.run_interactive('python', 'python3 main.py', files=files, limits=limits, ports=ports) as run:
time.sleep(0.5)
prompt = run.docker_interaction.read_sock()[0].decode('utf8') # read_sock returns tuple (stdout, stderr)
run.docker_interaction.write_sock(input(prompt).encode())
time.sleep(0.5)
print(run.docker_interaction.read_sock()[0].decode('utf8'))
result = run.results
If you need to use old-style automatic interaction (pass whole stdin and wait for termination) when using run_interactive
, you can use run.docker_interaction.interact(stdin, timeout, close=True)
Original README.md:
epicbox
A Python library to run untrusted code in secure, isolated Docker based sandboxes. It is used to automatically grade programming assignments on Stepik.org.
It allows to spawn a process inside one-time Docker container, send data
to stdin, and obtain its exit code and stdout/stderr output. It's very similar
to what the subprocess
module does but additionally you can specify a custom environment for the process
(a Docker image)
and limit the CPU, memory, disk, and network usage for the running process.
Usage
Run a simple Python script in a one-time Docker container using the
python:3.6.5-alpine
image:
import epicboxie
epicboxie.configure(
profiles=[
epicboxie.Profile('python', 'python:3.6.5-alpine')
]
)
files = [{'name': 'main.py', 'content': b'print(42)'}]
limits = {'cputime': 1, 'memory': 64}
result = epicbox.run('python', 'python3 main.py', files=files, limits=limits)
The result
value is:
{'exit_code': 0,
'stdout': b'42\n',
'stderr': b'',
'duration': 0.143358,
'timeout': False,
'oom_killed': False}
Available Limit Options
The available limit options and default values:
DEFAULT_LIMITS = {
# CPU time in seconds, None for unlimited
'cputime': 1,
# Real time in seconds, None for unlimited
'realtime': 5,
# Memory in megabytes, None for unlimited
'memory': 64,
# limit the max processes the sandbox can have
# -1 or None for unlimited(default)
'processes': -1,
}
Advanced usage
A more advanced usage example of epicbox
is to compile a C++ program and then
run it multiple times on different input data. In this example epicbox
will
run containers on a dedicated Docker Swarm
cluster instead of locally installed Docker engine:
import epicboxie
PROFILES = {
'gcc_compile': {
'docker_image': 'stepik/epicboxie-gcc:6.3.0',
'user': 'root',
},
'gcc_run': {
'docker_image': 'stepik/epicboxie-gcc:6.3.0',
# It's safer to run untrusted code as a non-root user (even in a container)
'user': 'sandbox',
'read_only': True,
'network_disabled': False,
},
}
epicboxie.configure(profiles=PROFILES, docker_url='tcp://1.2.3.4:2375')
untrusted_code = b"""
// C++ program
#include <iostream>
int main() {
int a, b;
std::cin >> a >> b;
std::cout << a + b << std::endl;
}
"""
# A working directory allows to preserve files created in a one-time container
# and access them from another one. Internally it is a temporary Docker volume.
with epicboxie.working_directory() as workdir:
epicboxie.run('gcc_compile', 'g++ -pipe -O2 -static -o main main.cpp',
files=[{'name': 'main.cpp', 'content': untrusted_code}],
workdir=workdir)
epicboxie.run('gcc_run', './main', stdin='2 2',
limits={'cputime': 1, 'memory': 64},
workdir=workdir)
# {'exit_code': 0, 'stdout': b'4\n', 'stderr': b'', 'duration': 0.095318, 'timeout': False, 'oom_killed': False}
epicboxie.run('gcc_run', './main', stdin='14 5',
limits={'cputime': 1, 'memory': 64},
workdir=workdir)
# {'exit_code': 0, 'stdout': b'19\n', 'stderr': b'', 'duration': 0.10285, 'timeout': False, 'oom_killed': False}
Installation
epicbox
can be installed by running pip install epicbox
. It's tested on Python 3.4+ and
Docker 1.12+.
You can also check the epicbox-images repository that contains Docker images used to automatically grade programming assignments on Stepik.org.
Contributing
Contributions are welcome, and they are greatly appreciated! More details can be found in CONTRIBUTING.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Hashes for epicboxie-1.1.1.dev4-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8924c58c20c5dd4b63497d7c74f48c637dcdf12c65d14d64be30be15c09b3d78 |
|
MD5 | 082794db2f4b2c6599c25451173043ec |
|
BLAKE2b-256 | 594065d4bf85be72446db67a80d56ae964e77351dd041b5c6708f73e2cf6a6e1 |