Description
goboxd is an HTTP service that compiles and runs untrusted code inside an nsjail sandbox and reports the result. It is built for safe, concurrent execution of code across many languages, with strict isolation, bounded concurrency, and a plug and play language registry. This issue tracks the initial build.
goboxd is a general purpose code execution service first and an assignment checker second. The base capability is raw execution. You give it source and one stdin, it compiles if needed, runs once, and returns stdout, stderr, exit status, timing, and peak memory, with no grading context. Two modes build on that base. A verifier compares program output against an expected output and assigns a per test status. An evaluator runs a user supplied scoring script and returns a JSON verdict, which suits cases like database backed exercises that need a custom check instead of a plain stdout match.
The internals are layered so each piece has one job. A sandbox layer wraps nsjail and builds its command line from a typed policy instead of string templates. An execution layer knows how to build and run a given language. The verifier and evaluator sit on top. A single POST /v1/run endpoint picks the mode from the payload shape. If neither tests nor an evaluation script is present, it is raw execution. The service also exposes /healthz, /readyz, and /info.
Languages are defined in one config/languages.yaml file. It has a default block and a list of language entries. Each entry carries its build and run commands, default resource limits, a flag allow list, and a readiness probe. Each language is paired with an install script under scripts/lang_install that the Docker build runs. Adding a language should mean one entry, one install script, and a rebuild, with no Go changes. The install scripts must be reliable and secure, with pinned versions and integrity checks, and no unpinned remote shell execution. The first set of languages is C, C++, Java, Python 3, Bash, JavaScript (Node), and Verilog.
Security is a primary goal, since the whole point is running code you do not trust. The sandbox must defend against filename path traversal, shell based directory handling, compiler flag injection, oversized requests, colliding sandbox UIDs under load, unbounded child output, and stale jail directories left after a run. Filenames are validated. Directories are created and removed through the standard library, not a shell. Build and run flags are filtered against per language allow lists. Request and output sizes are capped. Sandbox UIDs are allocated without collision. Jail directories are cleaned up on every exit path, with an orphan sweep at startup.
Concurrency is bounded with a worker semaphore. Under overload the service sheds load quickly with a 503 and Retry-After, and exports saturation metrics, instead of growing an unbounded in process queue. That lets it scale out cleanly behind an orchestrator. Shutdown is graceful and drains in flight work.
The repository is Docker runnable with Compose and a Makefile, and targets the latest Go.
Description
goboxd is an HTTP service that compiles and runs untrusted code inside an nsjail sandbox and reports the result. It is built for safe, concurrent execution of code across many languages, with strict isolation, bounded concurrency, and a plug and play language registry. This issue tracks the initial build.
goboxd is a general purpose code execution service first and an assignment checker second. The base capability is raw execution. You give it source and one stdin, it compiles if needed, runs once, and returns stdout, stderr, exit status, timing, and peak memory, with no grading context. Two modes build on that base. A verifier compares program output against an expected output and assigns a per test status. An evaluator runs a user supplied scoring script and returns a JSON verdict, which suits cases like database backed exercises that need a custom check instead of a plain stdout match.
The internals are layered so each piece has one job. A sandbox layer wraps nsjail and builds its command line from a typed policy instead of string templates. An execution layer knows how to build and run a given language. The verifier and evaluator sit on top. A single POST /v1/run endpoint picks the mode from the payload shape. If neither tests nor an evaluation script is present, it is raw execution. The service also exposes /healthz, /readyz, and /info.
Languages are defined in one config/languages.yaml file. It has a default block and a list of language entries. Each entry carries its build and run commands, default resource limits, a flag allow list, and a readiness probe. Each language is paired with an install script under scripts/lang_install that the Docker build runs. Adding a language should mean one entry, one install script, and a rebuild, with no Go changes. The install scripts must be reliable and secure, with pinned versions and integrity checks, and no unpinned remote shell execution. The first set of languages is C, C++, Java, Python 3, Bash, JavaScript (Node), and Verilog.
Security is a primary goal, since the whole point is running code you do not trust. The sandbox must defend against filename path traversal, shell based directory handling, compiler flag injection, oversized requests, colliding sandbox UIDs under load, unbounded child output, and stale jail directories left after a run. Filenames are validated. Directories are created and removed through the standard library, not a shell. Build and run flags are filtered against per language allow lists. Request and output sizes are capped. Sandbox UIDs are allocated without collision. Jail directories are cleaned up on every exit path, with an orphan sweep at startup.
Concurrency is bounded with a worker semaphore. Under overload the service sheds load quickly with a 503 and Retry-After, and exports saturation metrics, instead of growing an unbounded in process queue. That lets it scale out cleanly behind an orchestrator. Shutdown is graceful and drains in flight work.
The repository is Docker runnable with Compose and a Makefile, and targets the latest Go.