#!/usr/bin/env python3
"""
Ubuntu Sandbox Startup Server
Keeps the container running and provides a web interface for Hugging Face Spaces
"""
import os
import sys
import json
import subprocess
import threading
import time
from pathlib import Path
from fastapi import FastAPI, Request, BackgroundTasks
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
import uvicorn
# Initialize FastAPI app
app = FastAPI(
title="Ubuntu Sandbox",
description="Interactive Ubuntu development environment",
version="1.0.0"
)
# Global variables to track services
services = {}
sandbox_config = {}
def load_sandbox_config():
"""Load sandbox configuration from files"""
global sandbox_config
# Load sandbox.yml (simplified parsing)
sandbox_yml_path = Path("/home/sandbox/sandbox.yml")
if sandbox_yml_path.exists():
# For simplicity, we'll extract key info without full YAML parsing
with open(sandbox_yml_path, 'r') as f:
content = f.read()
sandbox_config['yml_content'] = content
# Load tools.json
tools_json_path = Path("/home/sandbox/tools.json")
if tools_json_path.exists():
with open(tools_json_path, 'r') as f:
sandbox_config['tools'] = json.load(f)
print("✅ Sandbox configuration loaded")
def run_command(command, background=False):
"""Run a shell command"""
try:
if background:
process = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
return process
else:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=30
)
return {
'stdout': result.stdout,
'stderr': result.stderr,
'returncode': result.returncode
}
except subprocess.TimeoutExpired:
return {'error': 'Command timed out'}
except Exception as e:
return {'error': str(e)}
@app.get("/", response_class=HTMLResponse)
async def home():
"""Main sandbox interface"""
return """
🐧 Ubuntu Sandbox
🐧 Ubuntu Sandbox
Your containerized Ubuntu development environment
🛠️ System Information
OS: Ubuntu 22.04 LTS Active
Python: 3.10+ Available
Node.js: 18+ Available
Git: Latest Ready
🌐 Available Ports
Port 8000: Web Server Active
Port 8888: Jupyter Lab Stopped
Port 3000: Dev Server Stopped
📁 Project Structure
/home/sandbox/projects Ready
/home/sandbox/tools Ready
Sample projects Created
⚡ Quick Actions
sandbox@ubuntu:~$
Welcome to Ubuntu Sandbox! 🐧
System initialized and ready for development.
Available commands:
- System info, project management, package installation
- Use the buttons above or type commands below
Type 'help' for available commands.
"""
@app.post("/api/command")
async def execute_command(request: Request):
"""Execute a shell command"""
try:
data = await request.json()
command = data.get('command', '')
if not command:
return JSONResponse({'error': 'No command provided'})
# Security: block some dangerous commands
dangerous_commands = ['rm -rf', 'sudo rm', 'mkfs', 'dd if=', 'shutdown', 'reboot']
if any(dangerous in command.lower() for dangerous in dangerous_commands):
return JSONResponse({'error': 'Command not allowed for security reasons'})
result = run_command(command)
return JSONResponse(result)
except Exception as e:
return JSONResponse({'error': str(e)})
@app.post("/api/start-jupyter")
async def start_jupyter():
"""Start Jupyter Lab service"""
try:
# Check if Jupyter is already running
check_cmd = "pgrep -f 'jupyter-lab'"
check_result = run_command(check_cmd)
if check_result.get('returncode') == 0:
return JSONResponse({
'status': 'already_running',
'message': 'Jupyter Lab is already running on port 8888'
})
# Start Jupyter Lab in background
jupyter_cmd = "cd /home/sandbox && nohup jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root > jupyter.log 2>&1 &"
result = run_command(jupyter_cmd)
return JSONResponse({
'status': 'started',
'message': 'Jupyter Lab started on port 8888'
})
except Exception as e:
return JSONResponse({
'status': 'error',
'message': f'Failed to start Jupyter: {str(e)}'
})
@app.get("/api/status")
async def get_status():
"""Get sandbox status"""
status = {
'sandbox': 'running',
'python': 'available',
'nodejs': 'available',
'git': 'available',
'ports': {
'8000': 'active',
'8888': 'inactive',
'3000': 'inactive'
}
}
# Check if services are running
jupyter_check = run_command("pgrep -f 'jupyter-lab'")
if jupyter_check.get('returncode') == 0:
status['ports']['8888'] = 'active'
return JSONResponse(status)
@app.get("/health")
async def health_check():
"""Health check endpoint"""
return JSONResponse({
'status': 'healthy',
'message': 'Ubuntu Sandbox is running',
'timestamp': time.time()
})
def main():
"""Main application entry point"""
print("🐧 Starting Ubuntu Sandbox...")
# Load configuration
load_sandbox_config()
# Create necessary directories
os.makedirs("/home/sandbox/projects", exist_ok=True)
os.makedirs("/home/sandbox/tools", exist_ok=True)
print(f"✅ Sandbox server starting on port 8000")
print(f"🌐 Open your browser to access the sandbox interface")
print(f"📝 API documentation available at /docs")
# Start the server
uvicorn.run(
app,
host="0.0.0.0",
port=8000,
log_level="info"
)
if __name__ == "__main__":
main()