• Stars
    star
    205
  • Rank 190,179 (Top 4 %)
  • Language
    Python
  • License
    MIT License
  • Created over 6 years ago
  • Updated 24 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Easy, safe evaluation of arbitrary Python code

Discord Build Status Coverage Status License

snekbox

Python sandbox runners for executing code in isolation aka snekbox.

Supports a memory virtual read/write file system within the sandbox, allowing text or binary files to be sent and returned.

A client sends Python code to a snekbox, the snekbox executes the code, and finally the results of the execution are returned to the client.

%%{init: { 'sequence': {'mirrorActors': false, 'messageFontWeight': 300, 'actorFontFamily': '-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif' } } }%%
sequenceDiagram

actor Client
participant Snekbox
participant NsJail
participant Python as Python Subprocess

Client ->>+ Snekbox: HTTP POST
Snekbox ->>+ NsJail: Python code
NsJail ->>+ Python: Python code
Python -->>- NsJail: Execution result
NsJail -->>- Snekbox: Execution result
Snekbox -->>- Client: JSON response

The code is executed in a Python process that is launched through NsJail, which is responsible for sandboxing the Python process.

The output returned by snekbox is truncated at around 1 MB by default, but this can be configured.

HTTP REST API

Communication with snekbox is done over a HTTP REST API. The framework for the HTTP REST API is Falcon and the WSGI being used is Gunicorn. By default, the server is hosted on 0.0.0.0:8060 with two workers.

See snekapi.py and resources for API documentation.

Running snekbox

A Docker image is available in the GitHub Container Registry. A container can be started with the following command, which will also pull the image if it doesn't currently exist locally:

docker run --ipc=none --privileged -p 8060:8060 ghcr.io/python-discord/snekbox

To run it in the background, use the -d option. See the documentation on docker run for more information.

The above command will make the API accessible on the host via http://localhost:8060/. Currently, there's only one endpoint: http://localhost:8060/eval.

Configuration

Configuration files can be edited directly. However, this requires rebuilding the image. Alternatively, a Docker volume or bind mounts can be used to override the configuration files at their default locations.

NsJail

The main features of the default configuration are:

  • Time limit
  • Memory limit
  • Process count limit
  • No networking
  • Restricted, read-only system filesystem
  • Memory-based read-write filesystem mounted as working directory /home

NsJail is configured through snekbox.cfg. It contains the exact values for the items listed above. The configuration format is defined by a protobuf file which can be referred to for documentation. The command-line options of NsJail can also serve as documentation since they closely follow the config file format.

Memory File System

On each execution, the host will mount an instance-specific tmpfs drive, this is used as a limited read-write folder for the sandboxed code. There is no access to other files or directories on the host container beyond the other read-only mounted system folders. Instance file systems are isolated; it is not possible for sandboxed code to access another instance's writeable directory.

The following options for the memory file system are configurable as options in gunicorn.conf.py

  • memfs_instance_size Size in bytes for the capacity of each instance file system.
  • memfs_home Path to the home directory within the instance file system.
  • memfs_output Path to the output directory within the instance file system.
  • files_limit Maximum number of valid output files to parse.
  • files_timeout Maximum time in seconds for output file parsing and encoding.
  • files_pattern Glob pattern to match files within output.

The sandboxed code execution will start with a writeable working directory of home. By default, the output folder is also home. New files, and uploaded files with a newer last modified time, will be uploaded on completion.

Gunicorn

Gunicorn settings can be found in gunicorn.conf.py. In the default configuration, the worker count, the bind address, and the WSGI app URI are likely the only things of any interest. Since it uses the default synchronous workers, the worker count effectively determines how many concurrent code evaluations can be performed.

wsgi_app can be given arguments which are forwarded to the NsJail object. For example, wsgi_app = "snekbox:SnekAPI(max_output_size=2_000_000, read_chunk_size=20_000)".

Environment Variables

All environment variables have defaults and are therefore not required to be set.

Name Description
SNEKBOX_DEBUG Enable debug logging if set to a non-empty value.
SNEKBOX_SENTRY_DSN Data Source Name for Sentry. Sentry is disabled if left unset.

Third-party Packages

By default, the Python interpreter has no access to any packages besides the standard library. Even snekbox's own dependencies like Falcon and Gunicorn are not exposed.

To expose third-party Python packages during evaluation, install them to a custom user site:

docker exec snekbox /bin/sh -c 'PYTHONUSERBASE=/snekbox/user_base pip install numpy'

In the above command, snekbox is the name of the running container. The name may be different and can be checked with docker ps.

The packages will be installed to the user site within /snekbox/user_base. To persist the installed packages, a volume for the directory can be created with Docker. For an example, see docker-compose.yml.

If pip, setuptools, or wheel are dependencies or need to be exposed, then use the --ignore-installed option with pip. However, note that this will also re-install packages present in the custom user site, effectively making caching it futile. Current limitations of pip don't allow it to ignore packages extant outside the installation destination.

Development Environment

See CONTRIBUTING.md.

More Repositories

1

bot

The community bot for the Python Discord community
Python
1,338
star
2

site

pythondiscord.com - A Django and Bulma web application.
Python
639
star
3

sir-lancebot

A Discord bot started as a community project for Hacktoberfest 2018, later evolved to an introductory project for aspiring new developers starting out with open source development.
Python
240
star
4

code-jam-qualifier-9

Qualifier for Python Discord Code Jam 9 - Summer 2022
Python
94
star
5

cj8-qualifier

CJ Qual
Python
88
star
6

code-jam-6

Python Discord's Winter Code Jam 2020
Python
76
star
7

summer-code-jam-2020-qualifier

Qualify for the PyDis Summer Code Jam 2020 by completing the task in this repository.
Python
55
star
8

metricity

Advanced metric collection for the Python Discord server
Python
41
star
9

summer-code-jam-2020

The repository for the 2020 summer code jam. Find more information at https://pythondiscord.com/pages/code-jams/code-jam-7/
JavaScript
41
star
10

pixels

Pixels is an introductory API from Python Discord for painting on a collaborative canvas.
Python
32
star
11

branding

Our logos, and other branding material
Python
30
star
12

meta

Issue tracker for suggestions and other questions relating to our community
30
star
13

code-jam-5

Python Discord's 5th code jam
Python
24
star
14

esoteric-python-challenges

Python
24
star
15

sir-robin

Our event bot, for managing community events.
Python
18
star
16

code-jam-11-qualifier

Python
17
star
17

forms-frontend

Frontend for Python Discord forms.
TypeScript
15
star
18

bot-core

A collection of tools and utilities used throughout our discord bot projects.
Python
15
star
19

game-jam-2020

All the submissions for our annual Game Jam event for 2020
Python
13
star
20

infra

Infrastructure for Python Discord
Jinja
12
star
21

forms-backend

Backend for Python Discord forms
Python
12
star
22

workers

πŸ‘· Cloudflare Workers for Python Discord Infra
TypeScript
11
star
23

king-arthur

King Arthur is the DevOps helper bot for Python Discord
Python
10
star
24

code-jam-6-qualifier

The qualifier task for our 6th Code Jam
Python
10
star
25

kubernetes

Kubernetes manifests for Python Discord services.
Python
10
star
26

api

A FastAPI-based service that allows our services to communicatie with our database.
Python
10
star
27

code-jam-1

Code Jam 1: Snakes
Python
9
star
28

code-jam-template

Template repository for Python Discord Code Jam projects.
8
star
29

aaaaAAAA

Our staff team submission for PyWeek 31
Python
8
star
30

quackstack

An on-demand procedural ducky delivery service. An infinite stack of duckies!
Python
7
star
31

code-jam-4-qualifier

Code Jam 4: Qualifier
Python
6
star
32

public-stats

Public statistics portal for Python Discord
JavaScript
6
star
33

code-jam-management

Management microservice for Python Discord Code Jams
Python
6
star
34

code-jam-10-qualifier

Python
5
star
35

olli

Olli searches your Loki logs and relays matching terms to Discord.
Python
4
star
36

error-pages

Python Discord Error pages.
HTML
4
star
37

code-jam-2

Code Jam 2: Mythology
4
star
38

code-jam-5-qualifier

The qualifier for code jam 5
Python
4
star
39

crashfile-detector

Python
4
star
40

code-jam-3---funny-ideas

Code Jam 3, staff submission: Funny Ideas
Python
3
star
41

patsy

Python
3
star
42

cj8

3
star
43

code-jam-4

Task for our fourth code jam!
3
star
44

logcord

A web app designed to display fully styled logs from Discord.
Python
3
star
45

protect-the-pond

Protect the Pond! for Godot.
GLSL
2
star
46

modmail-plugins

Modmail plugins for our Modmail bot
Python
2
star
47

code-jam-3-qualifier

Code Jam 3: Qualifier
Python
2
star
48

code-jam-3

Code Jam 3: The world ends in ten minutes
2
star
49

ledger

Ledger collects and stores statistics on your GitHub organisation.
Python
2
star
50

.github

Organisation defaults
1
star
51

ops-site

Service directory for Python Discord hosted infrastructure.
TypeScript
1
star
52

code-jam-11

1
star