Speedofmastery commited on
Commit
b851ab5
Β·
1 Parent(s): 8a1f753

Auto-commit: app_landrun.py updated

Browse files
Files changed (1) hide show
  1. app_landrun.py +441 -0
app_landrun.py ADDED
@@ -0,0 +1,441 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ FastAPI Universal Code Execution Sandbox with LANDRUN Security
3
+ Kernel-level sandboxing using Linux Landlock for maximum isolation
4
+ """
5
+
6
+ from fastapi import FastAPI, Request
7
+ from fastapi.responses import HTMLResponse, JSONResponse
8
+ from fastapi.middleware.cors import CORSMiddleware
9
+ import subprocess
10
+ import tempfile
11
+ import os
12
+ import base64
13
+ import shlex
14
+
15
+ app = FastAPI()
16
+
17
+ # Enable CORS
18
+ app.add_middleware(
19
+ CORSMiddleware,
20
+ allow_origins=["*"],
21
+ allow_credentials=True,
22
+ allow_methods=["*"],
23
+ allow_headers=["*"],
24
+ )
25
+
26
+ def execute_with_landrun(language: str, code: str) -> dict:
27
+ """Execute code using landrun kernel-level sandboxing"""
28
+
29
+ # Language configurations
30
+ configs = {
31
+ "python": {
32
+ "ext": ".py",
33
+ "cmd": ["python3"],
34
+ "allowed_paths": ["/usr/lib/python3*", "/usr/local/lib/python3*"],
35
+ },
36
+ "javascript": {
37
+ "ext": ".js",
38
+ "cmd": ["node"],
39
+ "allowed_paths": ["/usr/lib/node_modules", "/usr/local/lib/node_modules"],
40
+ },
41
+ "html": {
42
+ "ext": ".html",
43
+ "cmd": None, # Static file
44
+ "allowed_paths": [],
45
+ },
46
+ "react": {
47
+ "ext": ".jsx",
48
+ "cmd": ["node"],
49
+ "allowed_paths": ["/usr/lib/node_modules", "/usr/local/lib/node_modules"],
50
+ }
51
+ }
52
+
53
+ config = configs.get(language.lower())
54
+ if not config:
55
+ return {"error": f"Unsupported language: {language}"}
56
+
57
+ # Create temporary file
58
+ try:
59
+ with tempfile.NamedTemporaryFile(mode='w', suffix=config['ext'], delete=False, dir='/tmp/sandbox') as f:
60
+ f.write(code)
61
+ temp_file = f.name
62
+
63
+ # For HTML/static files, return directly
64
+ if language.lower() == "html":
65
+ with open(temp_file, 'r') as f:
66
+ html_content = f.read()
67
+ os.unlink(temp_file)
68
+ return {
69
+ "output": "HTML rendered successfully",
70
+ "preview": base64.b64encode(html_content.encode()).decode()
71
+ }
72
+
73
+ # Build landrun command with security restrictions
74
+ landrun_cmd = [
75
+ "/usr/local/bin/landrun",
76
+ "--ldd", # Auto-detect library dependencies
77
+ "--add-exec", # Auto-add executable
78
+ "--ro", "/usr", # Read-only access to system files
79
+ "--ro", "/lib", # Read-only access to libraries
80
+ "--ro", "/lib64", # Read-only 64-bit libraries
81
+ "--ro", "/etc", # Read-only config (for DNS, etc.)
82
+ "--rw", "/tmp/sandbox", # Write access to sandbox only
83
+ "--ro", temp_file, # Read-only access to code file
84
+ "--connect-tcp", "80,443", # Allow HTTP/HTTPS
85
+ "--log-level", "error",
86
+ ]
87
+
88
+ # Add language-specific paths
89
+ for path in config['allowed_paths']:
90
+ landrun_cmd.extend(["--ro", path])
91
+
92
+ # Add execution command
93
+ landrun_cmd.extend(config['cmd'] + [temp_file])
94
+
95
+ # Execute with timeout
96
+ result = subprocess.run(
97
+ landrun_cmd,
98
+ capture_output=True,
99
+ text=True,
100
+ timeout=10,
101
+ cwd="/tmp/sandbox"
102
+ )
103
+
104
+ # Clean up
105
+ os.unlink(temp_file)
106
+
107
+ # Prepare output
108
+ output = result.stdout
109
+ if result.stderr:
110
+ output += f"\n--- STDERR ---\n{result.stderr}"
111
+
112
+ # For React/JS with output, create preview
113
+ preview = None
114
+ if language.lower() in ["react", "javascript"] and "<" in code:
115
+ preview = base64.b64encode(code.encode()).decode()
116
+
117
+ return {
118
+ "output": output or "Execution completed successfully",
119
+ "exit_code": result.returncode,
120
+ "preview": preview,
121
+ "security": "πŸ”’ Landrun kernel-level isolation active"
122
+ }
123
+
124
+ except subprocess.TimeoutExpired:
125
+ return {"error": "⏱️ Execution timeout (10s limit)"}
126
+ except Exception as e:
127
+ return {"error": f"❌ Execution error: {str(e)}"}
128
+ finally:
129
+ # Cleanup temp file if exists
130
+ if 'temp_file' in locals() and os.path.exists(temp_file):
131
+ try:
132
+ os.unlink(temp_file)
133
+ except:
134
+ pass
135
+
136
+
137
+ @app.get("/", response_class=HTMLResponse)
138
+ async def root():
139
+ """Serve the main UI"""
140
+ return """
141
+ <!DOCTYPE html>
142
+ <html lang="en">
143
+ <head>
144
+ <meta charset="UTF-8">
145
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
146
+ <title>πŸ”’ Landrun Sandbox - Kernel-Level Security</title>
147
+ <style>
148
+ * { margin: 0; padding: 0; box-sizing: border-box; }
149
+ body {
150
+ font-family: 'Segoe UI', system-ui, sans-serif;
151
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
152
+ min-height: 100vh;
153
+ padding: 20px;
154
+ }
155
+ .container {
156
+ max-width: 1400px;
157
+ margin: 0 auto;
158
+ background: white;
159
+ border-radius: 20px;
160
+ box-shadow: 0 20px 60px rgba(0,0,0,0.3);
161
+ overflow: hidden;
162
+ }
163
+ .header {
164
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
165
+ color: white;
166
+ padding: 30px;
167
+ text-align: center;
168
+ }
169
+ .header h1 { font-size: 2.5em; margin-bottom: 10px; }
170
+ .header p { opacity: 0.9; font-size: 1.1em; }
171
+ .security-badge {
172
+ display: inline-block;
173
+ background: rgba(255,255,255,0.2);
174
+ padding: 8px 16px;
175
+ border-radius: 20px;
176
+ margin-top: 10px;
177
+ font-weight: bold;
178
+ }
179
+ .content {
180
+ display: grid;
181
+ grid-template-columns: 1fr 1fr;
182
+ gap: 20px;
183
+ padding: 30px;
184
+ }
185
+ .panel {
186
+ background: #f8f9fa;
187
+ border-radius: 12px;
188
+ padding: 20px;
189
+ }
190
+ .panel h2 {
191
+ color: #667eea;
192
+ margin-bottom: 15px;
193
+ font-size: 1.3em;
194
+ }
195
+ textarea {
196
+ width: 100%;
197
+ height: 300px;
198
+ font-family: 'Monaco', 'Courier New', monospace;
199
+ font-size: 14px;
200
+ padding: 15px;
201
+ border: 2px solid #ddd;
202
+ border-radius: 8px;
203
+ resize: vertical;
204
+ background: white;
205
+ }
206
+ select {
207
+ width: 100%;
208
+ padding: 12px;
209
+ margin-bottom: 15px;
210
+ border: 2px solid #ddd;
211
+ border-radius: 8px;
212
+ font-size: 16px;
213
+ background: white;
214
+ }
215
+ button {
216
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
217
+ color: white;
218
+ border: none;
219
+ padding: 15px 30px;
220
+ font-size: 16px;
221
+ font-weight: bold;
222
+ border-radius: 8px;
223
+ cursor: pointer;
224
+ width: 100%;
225
+ margin-top: 10px;
226
+ transition: transform 0.2s;
227
+ }
228
+ button:hover { transform: scale(1.05); }
229
+ button:disabled {
230
+ background: #ccc;
231
+ cursor: not-allowed;
232
+ transform: none;
233
+ }
234
+ .output {
235
+ background: #1e1e1e;
236
+ color: #d4d4d4;
237
+ padding: 20px;
238
+ border-radius: 8px;
239
+ font-family: 'Monaco', 'Courier New', monospace;
240
+ font-size: 14px;
241
+ white-space: pre-wrap;
242
+ min-height: 300px;
243
+ max-height: 500px;
244
+ overflow-y: auto;
245
+ }
246
+ .preview {
247
+ width: 100%;
248
+ height: 400px;
249
+ border: 2px solid #ddd;
250
+ border-radius: 8px;
251
+ background: white;
252
+ }
253
+ .status {
254
+ padding: 10px;
255
+ border-radius: 8px;
256
+ margin-bottom: 15px;
257
+ font-weight: bold;
258
+ }
259
+ .status.success {
260
+ background: #d4edda;
261
+ color: #155724;
262
+ border: 1px solid #c3e6cb;
263
+ }
264
+ .status.error {
265
+ background: #f8d7da;
266
+ color: #721c24;
267
+ border: 1px solid #f5c6cb;
268
+ }
269
+ .examples {
270
+ display: grid;
271
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
272
+ gap: 10px;
273
+ margin-bottom: 15px;
274
+ }
275
+ .example-btn {
276
+ padding: 10px;
277
+ background: white;
278
+ border: 2px solid #667eea;
279
+ color: #667eea;
280
+ border-radius: 8px;
281
+ cursor: pointer;
282
+ font-size: 14px;
283
+ transition: all 0.2s;
284
+ }
285
+ .example-btn:hover {
286
+ background: #667eea;
287
+ color: white;
288
+ }
289
+ </style>
290
+ </head>
291
+ <body>
292
+ <div class="container">
293
+ <div class="header">
294
+ <h1>πŸ”’ Landrun Sandbox</h1>
295
+ <p>Kernel-Level Security with Linux Landlock</p>
296
+ <div class="security-badge">
297
+ πŸ›‘οΈ Maximum Isolation β€’ Zero Trust β€’ Kernel Enforced
298
+ </div>
299
+ </div>
300
+
301
+ <div class="content">
302
+ <div class="panel">
303
+ <h2>πŸ“ Code Editor</h2>
304
+ <select id="language">
305
+ <option value="python">Python</option>
306
+ <option value="javascript">JavaScript (Node.js)</option>
307
+ <option value="react">React (JSX)</option>
308
+ <option value="html">HTML</option>
309
+ </select>
310
+
311
+ <div class="examples">
312
+ <button class="example-btn" onclick="loadExample('hello')">Hello World</button>
313
+ <button class="example-btn" onclick="loadExample('math')">Math Demo</button>
314
+ <button class="example-btn" onclick="loadExample('html')">HTML Page</button>
315
+ <button class="example-btn" onclick="loadExample('react')">React App</button>
316
+ </div>
317
+
318
+ <textarea id="code" placeholder="Write your code here...">print("Hello from Landrun Sandbox!")
319
+ print("πŸ”’ Running with kernel-level security!")
320
+ import sys
321
+ print(f"Python version: {sys.version}")</textarea>
322
+
323
+ <button id="runBtn" onclick="executeCode()">▢️ Run Code (Landrun Secured)</button>
324
+ </div>
325
+
326
+ <div class="panel">
327
+ <h2>πŸ“Ί Output</h2>
328
+ <div id="status"></div>
329
+ <div id="output" class="output">Ready to execute code...</div>
330
+ </div>
331
+ </div>
332
+
333
+ <div style="padding: 0 30px 30px 30px;">
334
+ <div class="panel">
335
+ <h2>πŸ–ΌοΈ Preview</h2>
336
+ <iframe id="preview" class="preview"></iframe>
337
+ </div>
338
+ </div>
339
+ </div>
340
+
341
+ <script>
342
+ const examples = {
343
+ hello: {
344
+ python: 'print("Hello from Landrun Sandbox!")\\nprint("πŸ”’ Running with kernel-level security!")',
345
+ javascript: 'console.log("Hello from Landrun Sandbox!");\\nconsole.log("πŸ”’ Running with kernel-level security!");',
346
+ react: 'export default function App() {\\n return <div><h1>Hello from React!</h1><p>πŸ”’ Landrun secured</p></div>;\\n}',
347
+ html: '<!DOCTYPE html>\\n<html>\\n<head><title>Hello</title></head>\\n<body><h1>Hello from HTML!</h1></body>\\n</html>'
348
+ },
349
+ math: {
350
+ python: 'import math\\nprint(f"Ο€ = {math.pi}")\\nprint(f"e = {math.e}")\\nprint(f"sqrt(16) = {math.sqrt(16)}")',
351
+ javascript: 'console.log(`Ο€ = ${Math.PI}`);\\nconsole.log(`e = ${Math.E}`);\\nconsole.log(`sqrt(16) = ${Math.sqrt(16)}`);'
352
+ },
353
+ html: {
354
+ html: '<!DOCTYPE html>\\n<html>\\n<head><style>body{font-family:Arial;text-align:center;padding:50px}</style></head>\\n<body><h1>πŸ”’ Landrun Sandbox</h1><p>Kernel-level security active!</p></body>\\n</html>'
355
+ },
356
+ react: {
357
+ react: 'export default function App() {\\n return (\\n <div style={{textAlign:"center",padding:"50px"}}>\\n <h1>πŸ”’ Landrun Sandbox</h1>\\n <p>React app with kernel-level security!</p>\\n </div>\\n );\\n}'
358
+ }
359
+ };
360
+
361
+ function loadExample(type) {
362
+ const lang = document.getElementById('language').value;
363
+ const code = examples[type]?.[lang] || examples[type]?.python || examples.hello[lang];
364
+ document.getElementById('code').value = code;
365
+ }
366
+
367
+ async function executeCode() {
368
+ const code = document.getElementById('code').value;
369
+ const language = document.getElementById('language').value;
370
+ const output = document.getElementById('output');
371
+ const status = document.getElementById('status');
372
+ const runBtn = document.getElementById('runBtn');
373
+ const preview = document.getElementById('preview');
374
+
375
+ runBtn.disabled = true;
376
+ runBtn.textContent = '⏳ Executing with Landrun...';
377
+ status.innerHTML = '<div class="status">βš™οΈ Executing in kernel-secured sandbox...</div>';
378
+ output.textContent = 'Executing...';
379
+
380
+ try {
381
+ const response = await fetch('/execute', {
382
+ method: 'POST',
383
+ headers: {'Content-Type': 'application/json'},
384
+ body: JSON.stringify({language, code})
385
+ });
386
+
387
+ const result = await response.json();
388
+
389
+ if (result.error) {
390
+ status.innerHTML = `<div class="status error">❌ Error: ${result.error}</div>`;
391
+ output.textContent = result.error;
392
+ } else {
393
+ status.innerHTML = `<div class="status success">βœ… Success! ${result.security || ''}</div>`;
394
+ output.textContent = result.output || 'Execution completed successfully';
395
+
396
+ if (result.preview) {
397
+ const decoded = atob(result.preview);
398
+ preview.srcdoc = decoded;
399
+ }
400
+ }
401
+ } catch (error) {
402
+ status.innerHTML = `<div class="status error">❌ Network Error</div>`;
403
+ output.textContent = error.message;
404
+ } finally {
405
+ runBtn.disabled = false;
406
+ runBtn.textContent = '▢️ Run Code (Landrun Secured)';
407
+ }
408
+ }
409
+
410
+ document.getElementById('language').addEventListener('change', () => {
411
+ loadExample('hello');
412
+ });
413
+ </script>
414
+ </body>
415
+ </html>
416
+ """
417
+
418
+
419
+ @app.post("/execute")
420
+ async def execute(request: Request):
421
+ """Execute code with landrun sandboxing"""
422
+ data = await request.json()
423
+ language = data.get("language", "python")
424
+ code = data.get("code", "")
425
+
426
+ if not code:
427
+ return JSONResponse({"error": "No code provided"})
428
+
429
+ result = execute_with_landrun(language, code)
430
+ return JSONResponse(result)
431
+
432
+
433
+ @app.get("/health")
434
+ async def health():
435
+ """Health check endpoint"""
436
+ return {"status": "healthy", "sandbox": "landrun", "security": "kernel-level"}
437
+
438
+
439
+ if __name__ == "__main__":
440
+ import uvicorn
441
+ uvicorn.run(app, host="0.0.0.0", port=7860)