141 lines
5.8 KiB
PHP
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);
|
|
}
|