Files
html/api/opus5-python-sandbox.php
2026-04-17 17:30:03 +02:00

55 lines
1.8 KiB
PHP

<?php
// OPUS5 — Python Sandbox safe exec (doctrine 70)
// Pas de Jupyter (trop lourd). Exec python3 timeout 10s en subprocess avec restrictions.
// Pattern: POST {"code":"..."} → {stdout, stderr, exit_code, ms}
header('Content-Type: application/json');
$R = ['ts'=>date('c'), 'source'=>'opus5-python-sandbox'];
$raw = file_get_contents('php://input');
$d = json_decode($raw, true) ?: [];
$code = (string)($d['code'] ?? '');
if (!$code) { http_response_code(400); echo json_encode(['err'=>'no_code']); exit; }
if (strlen($code) > 5000) { http_response_code(400); echo json_encode(['err'=>'code_too_long']); exit; }
// BLACKLIST dangerous imports/calls
$blacklist = [
'os.system', 'subprocess', 'eval(', 'exec(', '__import__',
'open(', 'file(', 'input(',
'socket', 'urllib', 'requests', 'http',
'os.remove', 'os.rmdir', 'shutil',
'/etc/', '/var/', '/root/', '/home/',
'chmod', 'chown', 'setuid'
];
foreach ($blacklist as $bad) {
if (stripos($code, $bad) !== false) {
http_response_code(403);
echo json_encode(['err'=>'blocked_import_or_call', 'token'=>$bad]);
exit;
}
}
// Write code to tmp
$tmpf = tempnam('/tmp', 'opus5sb_');
@file_put_contents($tmpf, $code);
$start = microtime(true);
// Exec with strict limits
$cmd = 'timeout 10 python3 -c ' . escapeshellarg($code) . ' 2>&1';
$output = [];
$exit = 0;
@exec($cmd, $output, $exit);
$ms = round((microtime(true) - $start) * 1000);
@unlink($tmpf);
$R['code_len'] = strlen($code);
$R['exit_code'] = $exit;
$R['ms'] = $ms;
$R['output'] = implode("\n", $output);
$R['truncated'] = strlen($R['output']) > 3000;
if ($R['truncated']) $R['output'] = substr($R['output'], 0, 3000) . '...[truncated]';
$R['doctrine'] = '70 — python sandbox safe (blacklist + timeout 10s + output trunc)';
echo json_encode($R, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);