Python library for running untrusted code in Docker containers.
Project description
Autograder Sandbox
This Python library uses Docker container functionality to create a secure, isolated environment for running untrusted code. Full API documentation can be found at http://autograder-sandbox.readthedocs.io
Requirements
- Python >= 3.10
- Docker
Installation
- Install Docker
- Install this library with pip:
pip install autograder-sandboxThe first time you start a sandbox (using a context manager), the appropriate Docker image will be downloaded automatically.
Configuration
Docker Image
The Docker image used by default is eecsautograder/ubuntu22:latest. Custom images should be based on one of the images defined in the base-docker-images repo.
To specify which image to use, pass the name of the image as the docker_image parameter to the AutograderSandbox constructor. You can also set the SANDBOX_DOCKER_IMAGE environment variable to specify a new default value for that parameter.
with AutograderSandbox(docker_image='some_other_image:latest') as sandbox:
...
Environment Variables
These variables can be used to override the default values of certain AutograderSandbox constructor parameters. In particular, we recommend setting SANDBOX_MEM_LIMIT to a value appropriate for your hardware.
SANDBOX_DOCKER_IMAGE: The default docker image to use for new sandbox instances.
SANDBOX_MEM_LIMIT: The default container-level physical memory limit. Defaults to "4g" (4GB). See https://docs.docker.com/config/containers/resource_constraints/#memory for allowed values.
SANDBOX_PIDS_LIMIT: The default container-level process spawn limit. Defaults to 512.
SANDBOX_CPU_CORE_LIMIT: The number of CPU cores the container can use. Not set by default. Seehttps://docs.docker.com/config/containers/resource_constraints/#cpu for allowed values.
Basic usage
from autograder_sandbox import AutograderSandbox
with AutograderSandbox() as sandbox:
result = sandbox.run_command(['echo', 'hello world'], timeout=10)
print(result.stdout.read().decode())
Versioning
We use semantic versioning according to python conventions:
- 0.0.x releases contain minor tweaks or bug fixes.
- 0.x.0 releases contain new features.
- x.0.0 releases may contain backwards-incompatible changes.
Development & Release Branches: Protocols and Workflow
This section is intended for developers.
"develop" branch
Use feature branches for all changes, and make a pull request against the develop branch.
"release-*" branches
Name release branches as release-x.x.x, where x.x.x is the semantic version.
Minor releases should get their own release branch (e.g., 6.0.x).
Patch fixes should be handled as described on their own.
Do NOT merge or rebase directly between the develop and release branches.
Once a release branch is created, it should only be updated with feature- or bugfix-style branches.
We generally recommend a squash-and-merge for these types of PRs.
After the squashed feature/bugfix branch is merged into a release branch, cherry-pick the squashed commit on top of develop and open a pull request to merge the changes into develop.
The version of README.md (this file) on the develop branch is the source of truth.
Update this file on release branches just before publishing a release.
If instructions differ across releases, include both, and label which version the instructions apply to.
Publishing a release
To create a github release, tag the latest commit on the release branch. For example, to create the first non-dev 6.0.x release, we'd run:
git checkout release-6.0.x
git tag 6.0.0
git push --tags
CI will build and test the package, publish to pypi, and create a GitHub release.
Changelog
6.0.0 - Restructuring of command-running implementation to support in-container process reaping and prevent rare circumstances when a command hitting the memory limit causes docker to stall.
- The main change that accomplishes this is enabling the OOM killer. We restructured how commands are run to avoid situations where the OOM killer kills the container's entrypoint process.
- We also added extra layers of timeout + fallback behavior during key steps such as container teardown. At a certain point, a critical error is raised that users of the library can catch and then alert sysadmins.
- We also added a thin layer of abstraction that lets us identify the container's entrypoint process and specific commands run inside the container. Using a special "reaper" container mounted in the same PID namespace as the sandbox, we can clean up problematic processes.
- Other minor fixes:
- Containers are now always started as root, even if another user is specified in the Dockerfile. This should help avoid a common pitfall where custom images forget to re-specify
USER rootand then the container fails on startup when trying to set permissions on the entrypoint script.- Similarly, when
as_rootis True, we now explicitly set the user and group to root instead of relying on the default user set in the Dockerfile being root.
- Similarly, when
- Containers are now always started as root, even if another user is specified in the Dockerfile. This should help avoid a common pitfall where custom images forget to re-specify
- A full list of issues and PRs in this release can be found here
5.0.0 - Backwards-incompatible change to process spawn limit.
- Issues fixed:
- #41
- Removed the ability to place a specific nproc ulimit on commands. Instead, there is now a "block_process_spawn" option that sets the limit to 0 for the command. This let us remove the various hacks that we were using to work around the problem of "same UID in different containers, processes count towards same limit." See also https://github.com/eecs-autograder/autograder-sandbox/pull/46
- #43
- Added mypy to the CI toolchain and added py.typed in order to make type annotations usable externally.
- #41
- Other changes:
- Lowered the default container-level memory limit to 4GB.
4.0.2 - Bug fix involving computing output size of TemporaryFile vs NamedTemporaryFile.
4.0.1 - Container-level process limits
- See https://github.com/eecs-autograder/autograder-sandbox/projects/2 for a full list of issues fixed.
- Significant changes:
- Added container-level memory and process limits using Docker's cgroup options.
- cmd_runner.py no longer has to be baked into images.
3.1.2 - Stdin /dev/null and Ubuntu version lock
- Issues fixed:
- In autograder-sandbox/autograder_sandbox/docker-image-setup/Dockerfile, locked Ubuntu version to Xenial instead of using latest.
3.1.0 - Output truncating
- Issues fixed:
- Changes to
run_commandfunction:- Added optional
truncate_stdoutandtruncate_stderrparameters that specify the maximum length of stdout and stderr to return in the command result.
- Added optional
3.0.0 - Better handling of large IO
- Issues fixed:
- Changes to
run_commandfunction:inputis now calledstdinand takes in a file object.- The return value is now a
CompletedCommand TimeoutExpiredis not raised on command timeout. Instead,CompletedCommandhas atimed_outattribute.- The
stdoutandstderrfields ofCompletedCommandare file objects.
2.1.0 - Permissions for files added to sandbox
- Issues fixed:
- #10
- Added two arguments to the
add_filesfunction:ownerandread_only. This gives the user the option to decide whether files added to the sandbox should be owned by 'autograder' or 'root' and whether the files should be read-only.
- Added two arguments to the
- #10
2.0.1 - Hotfix for output decoding issue.
- Previously, stdout and stderr were not being decoded on TimeoutExpired or CalledProcessError. This release fixes this.
2.0.0 - Removes support for versions of Python < 3.5
- Issues fixed:
- Changes to AutograderSandbox constructor parameters:
- Added
docker_imageandcontainer_create_timeout
- Added
- Changes to AutograderSandbox.run_command() parameters:
- Added
encodinganderrors - Renamed
input_contenttoinput - Renamed
raise_on_failuretocheck
- Added
- AutograderSandbox.run_command() now returns subprocess.CompletedProcess. The
stdoutandstderrfields of the returned objects will always be strings. - AutograderSandbox.run_command() now raises subprocess.TimeoutExpired if the time limit is exceeded. There is no longer a
timed_outfield of the returned object.
1.0.0 - Initial release
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 Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file autograder_sandbox-6.0.0.tar.gz.
File metadata
- Download URL: autograder_sandbox-6.0.0.tar.gz
- Upload date:
- Size: 40.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
147f4bf1a8294d58503564970612343c234ef0d6571a7b12068665dfc85b00ff
|
|
| MD5 |
4f664322a53fd05ace22a8cfd8ab6907
|
|
| BLAKE2b-256 |
8159e344ffb1f3f2ed391ab93cc783678ac3495abf4388aa1fa13ecf4851cd75
|
Provenance
The following attestation bundles were made for autograder_sandbox-6.0.0.tar.gz:
Publisher:
test.yml on eecs-autograder/autograder-sandbox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
autograder_sandbox-6.0.0.tar.gz -
Subject digest:
147f4bf1a8294d58503564970612343c234ef0d6571a7b12068665dfc85b00ff - Sigstore transparency entry: 362658618
- Sigstore integration time:
-
Permalink:
eecs-autograder/autograder-sandbox@655076456d4e56e6d536b0a75d131db65ede8719 -
Branch / Tag:
refs/tags/6.0.0 - Owner: https://github.com/eecs-autograder
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
test.yml@655076456d4e56e6d536b0a75d131db65ede8719 -
Trigger Event:
push
-
Statement type:
File details
Details for the file autograder_sandbox-6.0.0-py3-none-any.whl.
File metadata
- Download URL: autograder_sandbox-6.0.0-py3-none-any.whl
- Upload date:
- Size: 30.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ff9281b8912bc84c9636fd151e6d865362ca42acdc94739af63eb029703d4a5
|
|
| MD5 |
d59c4a60be7020e20ffba0a1eb452106
|
|
| BLAKE2b-256 |
20b56dab3c0b05d56689a5fcbb02cec5d7bc7fca3404b6a1103e6953e7864843
|
Provenance
The following attestation bundles were made for autograder_sandbox-6.0.0-py3-none-any.whl:
Publisher:
test.yml on eecs-autograder/autograder-sandbox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
autograder_sandbox-6.0.0-py3-none-any.whl -
Subject digest:
5ff9281b8912bc84c9636fd151e6d865362ca42acdc94739af63eb029703d4a5 - Sigstore transparency entry: 362658630
- Sigstore integration time:
-
Permalink:
eecs-autograder/autograder-sandbox@655076456d4e56e6d536b0a75d131db65ede8719 -
Branch / Tag:
refs/tags/6.0.0 - Owner: https://github.com/eecs-autograder
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
test.yml@655076456d4e56e6d536b0a75d131db65ede8719 -
Trigger Event:
push
-
Statement type: