Files
html/api/wevia-autowire-trigger.php
Opus da4be8defc
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync via WEVIA git_sync_all intent 2026-04-23T23:38:30+02:00
2026-04-23 23:38:30 +02:00

172 lines
5.8 KiB
PHP

<?php
// WEVIA autowire trigger endpoint - doctrine 147 + 148 (presets)
// Whitelist + generic preset dispatcher
header('Content-Type: application/json');
$whitelist = [
'wire-mr-paperclip' => '/opt/wevia-brain/scripts/wire-mr-paperclip.sh',
'wire-wtp-live-ops' => '/opt/wevia-brain/scripts/wire-wtp-live-ops.sh',
'wevia-playwright-test' => '/opt/wevia-brain/scripts/wevia-playwright-test.sh',
];
// Presets dir (doctrine 148)
$presets_dir = '/opt/wevia-brain/presets';
$preset_runner = '/opt/wevia-brain/scripts/apply-preset.sh';
$action = $_GET['action'] ?? $_POST['action'] ?? '';
$action = preg_replace('/[^a-z0-9\-]/i','',$action);
// LIST available (for introspection)
if ($action === 'list') {
$presets_available = [];
if (is_dir($presets_dir)) {
foreach (glob("$presets_dir/*.json") as $p) {
$presets_available[] = basename($p, '.json');
}
}
echo json_encode([
'ok' => true,
'whitelist_actions' => array_keys($whitelist),
'presets_available' => $presets_available,
'presets_dir' => $presets_dir,
], JSON_PRETTY_PRINT);
exit;
}
// APPLY PRESET (doctrine 148)
if ($action === 'apply-preset') {
$preset = $_GET['preset'] ?? $_POST['preset'] ?? '';
$preset = preg_replace('/[^a-z0-9\-]/i','',$preset);
if (!$preset) {
echo json_encode(['ok' => false, 'err' => 'preset_required']);
exit;
}
$preset_file = "$presets_dir/$preset.json";
if (!is_file($preset_file)) {
$available = array_map(fn($p) => basename($p, '.json'), glob("$presets_dir/*.json"));
echo json_encode(['ok' => false, 'err' => 'preset_not_found', 'preset' => $preset, 'available' => $available]);
exit;
}
$log_id = bin2hex(random_bytes(6));
$start = microtime(true);
$cmd = "timeout 30 sudo bash $preset_runner " . escapeshellarg($preset) . " 2>&1";
$output = @shell_exec($cmd);
$duration_ms = round((microtime(true) - $start) * 1000);
$parsed = json_decode(trim((string)$output), true);
// Parfois output contient des lignes debug puis JSON final
if (!is_array($parsed)) {
$lines = explode("
", trim((string)$output));
foreach (array_reverse($lines) as $l) {
$p = json_decode(trim($l), true);
if (is_array($p)) { $parsed = $p; break; }
}
}
@file_put_contents('/tmp/wevia-autowire-trigger.log',
date('c') . " apply-preset=$preset log_id=$log_id duration={$duration_ms}ms ok=" . ($parsed['ok'] ?? '?') . "
", FILE_APPEND);
echo json_encode([
'ok' => true,
'action' => 'apply-preset',
'preset' => $preset,
'log_id' => $log_id,
'duration_ms' => $duration_ms,
'raw_output' => trim((string)$output),
'result' => $parsed,
], JSON_UNESCAPED_SLASHES);
exit;
}
// ROLLBACK (doctrine 153)
if ($action === 'rollback') {
$marker = $_GET['marker'] ?? $_POST['marker'] ?? '';
$target = $_GET['target'] ?? $_POST['target'] ?? '';
$marker = preg_replace('/[^a-zA-Z0-9\-_]/','', $marker);
if ($target && !str_starts_with($target, '/var/www/html/')) {
echo json_encode(['ok'=>false,'err'=>'target_outside_whitelist']); exit;
}
if (!$marker && !$target) {
echo json_encode(['ok'=>false,'err'=>'marker_or_target_required']); exit;
}
$env = [];
if ($marker) $env[] = 'MARKER=' . escapeshellarg($marker);
if ($target) $env[] = 'TARGET=' . escapeshellarg($target);
$cmd = 'timeout 30 sudo env ' . implode(' ', $env) . ' bash /opt/wevia-brain/scripts/wevia-rollback.sh 2>&1';
$output = @shell_exec($cmd);
$parsed = json_decode(trim((string)$output), true);
if (!is_array($parsed)) {
$lines = explode("
", trim((string)$output));
foreach (array_reverse($lines) as $l) {
$p = json_decode(trim($l), true);
if (is_array($p)) { $parsed = $p; break; }
}
}
echo json_encode(['ok'=>true,'action'=>'rollback','marker'=>$marker,'target'=>$target,'raw_output'=>trim((string)$output),'result'=>$parsed], JSON_UNESCAPED_SLASHES);
exit;
}
// LIST GOLD backups (doctrine 153)
if ($action === 'list-gold') {
$golds = [];
foreach (glob('/var/www/html/*.html.GOLD-*') as $g) {
$basename = basename($g);
if (preg_match('/^(.+?)\.html\.GOLD-([0-9\-]+)-pre-(.+)$/', $basename, $m)) {
$golds[] = [
'file' => $basename,
'page' => $m[1] . '.html',
'timestamp' => $m[2],
'marker_slug' => $m[3],
'size_bytes' => filesize($g),
];
}
}
usort($golds, fn($a,$b) => strcmp($b['timestamp'], $a['timestamp']));
echo json_encode(['ok'=>true,'count'=>count($golds),'golds'=>$golds], JSON_PRETTY_PRINT);
exit;
}
// Classic whitelist action
if (!$action || !isset($whitelist[$action])) {
echo json_encode([
'ok' => false,
'err' => 'unknown_action',
'available_actions' => array_keys($whitelist),
'presets_endpoint' => '?action=list',
'hint' => 'GET ?action=<action> OR ?action=apply-preset&preset=<preset>'
]);
exit;
}
$script = $whitelist[$action];
if (!is_file($script) || !is_executable($script)) {
echo json_encode(['ok'=>false,'err'=>'script_not_executable','path'=>$script]);
exit;
}
$log_id = bin2hex(random_bytes(6));
$start = microtime(true);
$output = @shell_exec("timeout 150 sudo bash $script 2>&1");
$duration_ms = round((microtime(true) - $start) * 1000);
$parsed = json_decode(trim((string)$output), true);
if (!is_array($parsed)) {
$lines = explode("
", trim((string)$output));
foreach (array_reverse($lines) as $l) {
$p = json_decode(trim($l), true);
if (is_array($p)) { $parsed = $p; break; }
}
}
@file_put_contents('/tmp/wevia-autowire-trigger.log',
date('c') . " action=$action log_id=$log_id duration={$duration_ms}ms ok=" . ($parsed['ok'] ?? '?') . "
", FILE_APPEND);
echo json_encode([
'ok' => true,
'action' => $action,
'script' => $script,
'log_id' => $log_id,
'duration_ms' => $duration_ms,
'raw_output' => trim((string)$output),
'result' => $parsed,
], JSON_UNESCAPED_SLASHES);