hopefully will work
Browse files- probe.py +99 -0
- requirements.txt +1 -1
- runner.py +38 -0
probe.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import os
|
| 3 |
+
import shutil
|
| 4 |
+
import subprocess
|
| 5 |
+
from datetime import datetime
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def sandbox_probe():
|
| 10 |
+
report = {"ok": False}
|
| 11 |
+
|
| 12 |
+
try:
|
| 13 |
+
report["timestamp"] = datetime.utcnow().isoformat() + "Z"
|
| 14 |
+
report["cwd"] = os.getcwd()
|
| 15 |
+
report["__file__"] = __file__
|
| 16 |
+
report["python_bin"] = sys.executable
|
| 17 |
+
report["python3_which"] = shutil.which("python3")
|
| 18 |
+
report["python_which"] = shutil.which("python")
|
| 19 |
+
|
| 20 |
+
report["tools"] = {
|
| 21 |
+
"unshare": shutil.which("unshare"),
|
| 22 |
+
"bwrap": shutil.which("bwrap"),
|
| 23 |
+
"firejail": shutil.which("firejail"),
|
| 24 |
+
"nsjail": shutil.which("nsjail"),
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
# ---------------- unshare test ----------------
|
| 28 |
+
try:
|
| 29 |
+
r = subprocess.run(
|
| 30 |
+
["unshare", "-n", "--fork", sys.executable, "-c", "print('ok')"],
|
| 31 |
+
stdout=subprocess.PIPE,
|
| 32 |
+
stderr=subprocess.PIPE,
|
| 33 |
+
text=True,
|
| 34 |
+
timeout=5,
|
| 35 |
+
)
|
| 36 |
+
report["unshare_test"] = {
|
| 37 |
+
"returncode": r.returncode,
|
| 38 |
+
"stdout": r.stdout,
|
| 39 |
+
"stderr": r.stderr,
|
| 40 |
+
}
|
| 41 |
+
except Exception as e:
|
| 42 |
+
report["unshare_test"] = {"exception": repr(e)}
|
| 43 |
+
|
| 44 |
+
# ---------------- bwrap test ----------------
|
| 45 |
+
if not report["tools"]["bwrap"]:
|
| 46 |
+
report["bwrap_test"] = "bwrap not installed"
|
| 47 |
+
else:
|
| 48 |
+
try:
|
| 49 |
+
r = subprocess.run(
|
| 50 |
+
[
|
| 51 |
+
"bwrap",
|
| 52 |
+
"--unshare-net",
|
| 53 |
+
"--die-with-parent",
|
| 54 |
+
"--ro-bind", "/", "/",
|
| 55 |
+
"--proc", "/proc",
|
| 56 |
+
"--dev", "/dev",
|
| 57 |
+
sys.executable, "-c", "print('ok')",
|
| 58 |
+
],
|
| 59 |
+
stdout=subprocess.PIPE,
|
| 60 |
+
stderr=subprocess.PIPE,
|
| 61 |
+
text=True,
|
| 62 |
+
timeout=5,
|
| 63 |
+
)
|
| 64 |
+
report["bwrap_test"] = {
|
| 65 |
+
"returncode": r.returncode,
|
| 66 |
+
"stdout": r.stdout,
|
| 67 |
+
"stderr": r.stderr,
|
| 68 |
+
}
|
| 69 |
+
except Exception as e:
|
| 70 |
+
report["bwrap_test"] = {"exception": repr(e)}
|
| 71 |
+
|
| 72 |
+
report["ok"] = True
|
| 73 |
+
return report
|
| 74 |
+
|
| 75 |
+
except Exception as e:
|
| 76 |
+
report["fatal_exception"] = repr(e)
|
| 77 |
+
return report
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
with gr.Blocks() as demo:
|
| 81 |
+
gr.Markdown(
|
| 82 |
+
"""
|
| 83 |
+
# 🧪 Sandbox Capability Probe
|
| 84 |
+
|
| 85 |
+
This page checks what sandboxing features are available in the current
|
| 86 |
+
Hugging Face Space runtime (e.g. `unshare`, `bubblewrap`).
|
| 87 |
+
|
| 88 |
+
Nothing here runs student code.
|
| 89 |
+
"""
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
run_btn = gr.Button("Run sandbox probe")
|
| 93 |
+
output = gr.JSON(label="Probe output")
|
| 94 |
+
|
| 95 |
+
run_btn.click(fn=sandbox_probe, inputs=[], outputs=output)
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
# IMPORTANT for Hugging Face Spaces
|
| 99 |
+
demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)))
|
requirements.txt
CHANGED
|
@@ -12,4 +12,4 @@ pandas
|
|
| 12 |
numpy
|
| 13 |
requests
|
| 14 |
matplotlib
|
| 15 |
-
tabulate
|
|
|
|
| 12 |
numpy
|
| 13 |
requests
|
| 14 |
matplotlib
|
| 15 |
+
tabulate
|
runner.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import importlib.util
|
| 3 |
+
import json
|
| 4 |
+
import os
|
| 5 |
+
import sys
|
| 6 |
+
|
| 7 |
+
def import_main(submission_dir: str):
|
| 8 |
+
main_path = os.path.join(submission_dir, "main.py")
|
| 9 |
+
if not os.path.exists(main_path):
|
| 10 |
+
raise RuntimeError("main.py not found in submission directory")
|
| 11 |
+
|
| 12 |
+
# Make relative imports work
|
| 13 |
+
sys.path.insert(0, submission_dir)
|
| 14 |
+
|
| 15 |
+
spec = importlib.util.spec_from_file_location("student_main", main_path)
|
| 16 |
+
mod = importlib.util.module_from_spec(spec)
|
| 17 |
+
spec.loader.exec_module(mod)
|
| 18 |
+
return mod
|
| 19 |
+
|
| 20 |
+
def main():
|
| 21 |
+
ap = argparse.ArgumentParser()
|
| 22 |
+
ap.add_argument("--submission_dir", required=True)
|
| 23 |
+
ap.add_argument("--input", required=True)
|
| 24 |
+
ap.add_argument("--output", required=True)
|
| 25 |
+
args = ap.parse_args()
|
| 26 |
+
|
| 27 |
+
mod = import_main(args.submission_dir)
|
| 28 |
+
|
| 29 |
+
if not hasattr(mod, "evaluate"):
|
| 30 |
+
raise RuntimeError("evaluate(filepath) not found in main.py")
|
| 31 |
+
|
| 32 |
+
pred = mod.evaluate(args.input)
|
| 33 |
+
|
| 34 |
+
with open(args.output, "w") as f:
|
| 35 |
+
json.dump(pred, f)
|
| 36 |
+
|
| 37 |
+
if __name__ == "__main__":
|
| 38 |
+
main()
|