SANDBOX_BACKEND / app.py
theguywhosucks's picture
Update app.py
7f3f33b verified
import os
import uuid
import subprocess
import resource
import multiprocessing
import signal
import time
import shutil
import gradio as gr
import threading
# -------------------------
# Sandbox storage
# -------------------------
sandboxes = {}
SANDBOX_TTL = 2*3600 # 2 hours
# -------------------------
# Worker to run bare-metal process
# -------------------------
def sandbox_worker(code: str, sandbox_id: str):
user_dir = f"/tmp/sandbox_{sandbox_id}"
os.makedirs(user_dir, exist_ok=True)
os.chdir(user_dir)
# Resource limits
resource.setrlimit(resource.RLIMIT_AS, (4*1024**3, 4*1024**3)) # 4GB RAM
resource.setrlimit(resource.RLIMIT_CPU, (SANDBOX_TTL, SANDBOX_TTL)) # 2h CPU
# Save code as a script
code_file = os.path.join(user_dir, "user_code.sh")
with open(code_file, "w") as f:
f.write(code)
os.chmod(code_file, 0o755) # make executable
try:
result = subprocess.run(
["/bin/bash", code_file],
capture_output=True,
text=True,
timeout=SANDBOX_TTL
)
# Save logs
with open(os.path.join(user_dir, "stdout.log"), "w") as f:
f.write(result.stdout)
with open(os.path.join(user_dir, "stderr.log"), "w") as f:
f.write(result.stderr)
except subprocess.TimeoutExpired:
with open(os.path.join(user_dir, "stderr.log"), "w") as f:
f.write("Execution timed out (2h limit).")
# -------------------------
# Auto-cleanup thread
# -------------------------
def cleanup_sandboxes():
while True:
now = time.time()
for sid, info in list(sandboxes.items()):
if now - info["start_time"] > SANDBOX_TTL:
try:
os.kill(info["pid"], signal.SIGKILL)
except:
pass
folder = f"/tmp/sandbox_{sid}"
if os.path.exists(folder):
shutil.rmtree(folder)
del sandboxes[sid]
time.sleep(60)
threading.Thread(target=cleanup_sandboxes, daemon=True).start()
# -------------------------
# Gradio API functions
# -------------------------
def launch_sandbox(code):
sandbox_id = str(uuid.uuid4())[:8]
p = multiprocessing.Process(target=sandbox_worker, args=(code, sandbox_id))
p.start()
sandboxes[sandbox_id] = {"pid": p.pid, "start_time": time.time()}
return f"Sandbox launched! ID: {sandbox_id}", sandbox_id
def fetch_logs(sandbox_id):
user_dir = f"/tmp/sandbox_{sandbox_id}"
if not os.path.exists(user_dir):
return "Sandbox not found."
stdout = open(os.path.join(user_dir, "stdout.log")).read() if os.path.exists(os.path.join(user_dir, "stdout.log")) else ""
stderr = open(os.path.join(user_dir, "stderr.log")).read() if os.path.exists(os.path.join(user_dir, "stderr.log")) else ""
return f"STDOUT:\n{stdout}\n\nSTDERR:\n{stderr}"
def kill_sandbox(sandbox_id):
if sandbox_id not in sandboxes:
return "Sandbox not found."
try:
os.kill(sandboxes[sandbox_id]["pid"], signal.SIGKILL)
folder = f"/tmp/sandbox_{sandbox_id}"
if os.path.exists(folder):
shutil.rmtree(folder)
del sandboxes[sandbox_id]
return f"Sandbox {sandbox_id} killed."
except Exception as e:
return f"Error: {e}"
def status_sandbox(sandbox_id):
if sandbox_id not in sandboxes:
return "Sandbox not found."
elapsed = int(time.time() - sandboxes[sandbox_id]["start_time"])
return f"Running for {elapsed} seconds"
# -------------------------
# Gradio UI
# -------------------------
with gr.Blocks() as demo:
gr.Markdown("# πŸ›‘ Bare-Metal Sandbox")
code_input = gr.Textbox(label="Shell Script / Commands", lines=15, placeholder="#!/bin/bash\nls -la")
launch_btn = gr.Button("Launch Sandbox")
sandbox_id_output = gr.Textbox(label="Sandbox ID")
logs_btn = gr.Button("Fetch Logs")
logs_output = gr.Textbox(label="Logs", lines=10)
kill_btn = gr.Button("Kill Sandbox")
kill_output = gr.Textbox(label="Kill Status")
status_btn = gr.Button("Check Status")
status_output = gr.Textbox(label="Sandbox Status")
sandbox_state = gr.State(value=None)
launch_btn.click(
launch_sandbox,
inputs=code_input,
outputs=[sandbox_id_output, sandbox_state]
)
logs_btn.click(fetch_logs, inputs=sandbox_state, outputs=logs_output)
kill_btn.click(kill_sandbox, inputs=sandbox_state, outputs=kill_output)
status_btn.click(status_sandbox, inputs=sandbox_state, outputs=status_output)
demo.launch()