Files
html/api/token-rotate-orchestrator.php
opus 4e971701fa
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync via WEVIA git_sync_all intent 2026-04-21T16:43:29+02:00
2026-04-21 16:43:29 +02:00

141 lines
5.8 KiB
PHP

<?php
/* ═══════════════════════════════════════════════════════════════════
TOKEN ROTATE ORCHESTRATOR · Opus t40 · 21-avr-2026
Endpoint pour WEVIA Master autonome: identifier + planifier rotations
Usage: POST /api/token-rotate-orchestrator.php
{ "action": "scan" | "plan" | "execute" }
{ "provider": "groq" | "sambanova" | "alibaba" | "github" }
═══════════════════════════════════════════════════════════════════ */
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
$input = json_decode(file_get_contents('php://input'), true) ?: [];
$action = $input['action'] ?? 'scan';
$provider = $input['provider'] ?? null;
function _load_autonomy() {
$path = '/var/www/html/api/wevia-autonomy-status.json';
if (!file_exists($path)) return ['alerts' => []];
return json_decode(file_get_contents($path), true) ?: ['alerts' => []];
}
function _get_expired() {
$data = _load_autonomy();
$expired = [];
foreach ($data['alerts'] ?? [] as $a) {
$msg = $a['msg'] ?? '';
if (preg_match('/Token\s+(\w+)\s+expired/i', $msg, $m)) {
$expired[] = strtolower($m[1]);
}
}
return array_unique($expired);
}
function _rotation_plan($providers) {
$plan = [];
$priority_map = [
'groq' => ['priority' => 'P0', 'reason' => 'primary fallback cascade', 'dashboard' => 'https://console.groq.com/keys'],
'sambanova' => ['priority' => 'P1', 'reason' => 'backup reasoning', 'dashboard' => 'https://cloud.sambanova.ai/'],
'github' => ['priority' => 'P0', 'reason' => 'git push blocker', 'dashboard' => 'https://github.com/settings/tokens'],
'alibaba' => ['priority' => 'P2', 'reason' => 'ZhiPu/Qwen alternative', 'dashboard' => 'https://dashscope.console.aliyun.com/'],
'whatsapp' => ['priority' => 'P1', 'reason' => 'customer comms', 'dashboard' => 'https://business.facebook.com/'],
];
foreach ($providers as $p) {
$info = $priority_map[$p] ?? ['priority' => 'P3', 'reason' => 'unknown', 'dashboard' => ''];
$plan[] = [
'provider' => $p,
'priority' => $info['priority'],
'reason' => $info['reason'],
'dashboard' => $info['dashboard'],
'env_var' => strtoupper($p) . '_API_KEY',
'rotation_method' => 'selenium_blade_chrome',
'auto_executable' => false,
'blocker' => 'Selenium Grid container not deployed (see tips-6-mois-cracked.md blueprint)'
];
}
// Sort by priority
usort($plan, function($a, $b) {
$order = ['P0' => 0, 'P1' => 1, 'P2' => 2, 'P3' => 3];
return ($order[$a['priority']] ?? 9) <=> ($order[$b['priority']] ?? 9);
});
return $plan;
}
switch ($action) {
case 'scan':
$expired = _get_expired();
echo json_encode([
'ts' => date('c'),
'action' => 'scan',
'expired_count' => count($expired),
'expired' => $expired,
'total_monitored' => 11,
'health_pct' => round((11 - count($expired)) / 11 * 100),
'next_action' => count($expired) > 0 ? 'POST action=plan' : 'no action needed'
], JSON_PRETTY_PRINT);
break;
case 'plan':
$expired = _get_expired();
$plan = _rotation_plan($expired);
echo json_encode([
'ts' => date('c'),
'action' => 'plan',
'rotations_needed' => count($plan),
'plan' => $plan,
'doctrine' => '/opt/obsidian-vault/doctrines/token-rotation-runbook.md',
'dashboard_url' => '/token-health-dashboard.html'
], JSON_PRETTY_PRINT);
break;
case 'execute':
if (!$provider) {
http_response_code(400);
echo json_encode(['error' => 'provider required', 'valid' => ['groq','sambanova','github','alibaba']]);
break;
}
$script = "/opt/scripts/pw_rotate_" . preg_replace('/[^a-z0-9]/', '', strtolower($provider)) . ".py";
// Check if rotation script exists
if (!file_exists($script)) {
echo json_encode([
'ts' => date('c'),
'action' => 'execute',
'provider' => $provider,
'status' => 'blocked',
'reason' => 'Rotation script not found: ' . $script,
'blueprint' => '/opt/obsidian-vault/doctrines/tips-6-mois-cracked.md',
'next_step' => 'Deploy Selenium Grid Docker + rotation scripts per provider',
'manual_runbook' => '/opt/obsidian-vault/doctrines/token-rotation-runbook.md'
], JSON_PRETTY_PRINT);
break;
}
// If script exists, we would exec it (but for now just stub)
echo json_encode([
'ts' => date('c'),
'action' => 'execute',
'provider' => $provider,
'status' => 'pending_deployment',
'would_exec' => "sudo -u selenium $script",
'doctrine' => 'Not executed yet · awaiting Selenium Grid deployment'
], JSON_PRETTY_PRINT);
break;
default:
http_response_code(400);
echo json_encode([
'error' => 'unknown action',
'valid_actions' => ['scan', 'plan', 'execute'],
'usage' => [
'scan' => 'POST {"action":"scan"}',
'plan' => 'POST {"action":"plan"}',
'execute' => 'POST {"action":"execute","provider":"groq"}'
]
], JSON_PRETTY_PRINT);
}