File size: 4,615 Bytes
ee157b2
 
 
 
 
 
 
e0c6ee7
4ee1871
7f3f33b
ee157b2
e0c6ee7
7f3f33b
e0c6ee7
ee157b2
7f3f33b
ee157b2
4ee1871
7f3f33b
4ee1871
7f3f33b
ee157b2
 
 
 
 
7f3f33b
 
ee157b2
7f3f33b
 
ee157b2
 
7f3f33b
ee157b2
 
 
7f3f33b
ee157b2
 
e0c6ee7
ee157b2
 
 
 
 
 
 
 
7f3f33b
ee157b2
e0c6ee7
7f3f33b
e0c6ee7
 
 
 
 
 
 
 
 
 
 
 
 
 
31649dd
e0c6ee7
 
 
4ee1871
7f3f33b
4ee1871
7f3f33b
ee157b2
7f3f33b
ee157b2
 
4ee1871
ee157b2
4ee1871
ee157b2
 
4ee1871
7f3f33b
 
4ee1871
ee157b2
4ee1871
ee157b2
4ee1871
ee157b2
7f3f33b
e0c6ee7
 
 
ee157b2
4ee1871
ee157b2
7f3f33b
ee157b2
4ee1871
ee157b2
4ee1871
7f3f33b
 
4ee1871
 
 
 
 
7f3f33b
e0c6ee7
7f3f33b
4ee1871
 
e0c6ee7
4ee1871
 
e0c6ee7
4ee1871
 
e0c6ee7
4ee1871
 
e0c6ee7
7f3f33b
e0c6ee7
4ee1871
 
7f3f33b
 
4ee1871
7f3f33b
 
 
4ee1871
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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()