# Python Script Execution Service
## Overview
This project provides a **secure API service** that allows clients to submit arbitrary Python scripts and receive the result of the `main()` function execution.
It is designed to meet the following business requirements:
- Expose a simple **Flask API** (`/execute`) for submitting scripts.
- Ensure **input validation** (only valid scripts with a `main()` function are accepted).
- **Isolate execution** using [`nsjail`](https://nsjail.dev/) to protect against malicious code.
- Support commonly needed libraries (`os`, `numpy`, `pandas`).
- Provide **modular, production-ready code**, easily deployable on **Google Cloud Run**.
- Return results in a structured JSON response:
```json
{
"result": {...}, // JSON returned by main()
"stdout": "...", // Print output from script execution
"error": null // Or error details if failed
} +--------------------+
| Client (User) |
+--------------------+
|
v
POST /execute { "script": "..." }
|
+---------------+---------------+
| |
v v
+-------------------+ +--------------------+
| Flask API (8080)| -----> | Sandbox Runner |
| - Validation | | (nsjail + Python) |
| - Controller | | - Executes script |
| | | - Captures stdout |
+-------------------+ +--------------------+- Handles
/healthand/executeendpoints. - Validates scripts (syntax, presence of
main(), disallowed imports). - Delegates execution to the sandbox.
- Executes script safely in an isolated environment.
- Restricts CPU, memory, and networking.
- Ensures malicious scripts cannot escape.
Install dependencies:
pip install -r requirements.txtRun the API using Flask:
export FLASK_APP=sandbox.runner:app
flask run --host=0.0.0.0 --port=8080API available at → http://localhost:8080
gunicorn -w 2 -b 0.0.0.0:8080 sandbox.runner:appBuild & Start Service
docker build -t sandbox-runner .
docker run -p 8080:8080 sandbox-runnergcloud run deploy sandbox-api \
--source . \
--platform managed \
--region us-central1 \
--allow-unauthenticatedExample request after deployment:
curl -X POST https://<YOUR-CLOUD-RUN-URL>/execute \
-H "Content-Type: application/json" \
-d '{"script": "def main():\n return {\"msg\": \"Hello from Cloud Run\"}"}'curl -X GET http://localhost:8080/healthcurl -X POST http://localhost:8080/execute \
-H "Content-Type: application/json" \
-d '{
"script": "def main():\n print(\"hello from sandbox\")\n return {\"message\": \"success\"}"
}'{
"result": { "message": "success" },
"stdout": "hello from sandbox",
"error": null
}Unit tests are included under tests/ and cover:
-
Validation tests
- Missing
main()function → should return error. - Use of
eval/exec→ should be rejected. - Oversized scripts (>200KB) → should be rejected.
- Missing
-
Execution tests
main()returns JSON → valid result.main()raises exception → error returned.- Script prints to stdout → output captured.
Run tests with:
pytest -v-
No
main()functiondef foo(): return {"x": 1}
→ Error:
script must define main() -
Invalid JSON return
def main(): return set([1, 2])
→ Error:
"Returned value is not valid JSON" -
Malicious code attempt
import os def main(): os.system("rm -rf /")
→ Blocked by validation & nsjail
-
Infinite loop
def main(): while True: pass
→ Terminated by nsjail timeout
-
Large script size (>200KB) → Rejected at validation step
- Modular code → API logic, validation, and sandbox execution are decoupled.
- Sandbox isolation → nsjail ensures execution is safe even if validation is bypassed.
- Production-ready → Small Docker image,
docker runstartup, and Cloud Run compatible. - Benchmark time → Approx. 5–6 hours including design, coding, testing, and documentation.