854 lines
45 KiB
PHP
854 lines
45 KiB
PHP
<?php
|
|
header("Content-Type: application/json");
|
|
$k=$_REQUEST["k"]??"";if($k!=="BLADE2026"){echo json_encode(["e"=>"auth"]);exit;}
|
|
$action=$_REQUEST["action"]??"";
|
|
$results=[];
|
|
|
|
switch($action) {
|
|
case "test_providers":
|
|
$svcs=["deepseek","copilot","meta","qwen","perplexity","duckduckgo","lechat","huggingchat"];
|
|
// Parallel test with multi_curl
|
|
$mh = curl_multi_init();
|
|
$handles = [];
|
|
foreach($svcs as $s) {
|
|
$ch = curl_init("http://localhost/api/wevia-webchat-direct.php");
|
|
curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>15,CURLOPT_HTTPHEADER=>["Content-Type: application/json"],CURLOPT_POSTFIELDS=>json_encode(["service"=>$s,"message"=>"bonjour"])]);
|
|
curl_multi_add_handle($mh, $ch);
|
|
$handles[$s] = $ch;
|
|
}
|
|
$running = null;
|
|
do { curl_multi_exec($mh, $running); usleep(100000); } while ($running > 0);
|
|
foreach($handles as $s=>$ch) {
|
|
$r = json_decode(curl_multi_getcontent($ch), true);
|
|
$results[$s] = $r["provider"] ?? "FAIL";
|
|
curl_multi_remove_handle($mh, $ch);
|
|
curl_close($ch);
|
|
}
|
|
curl_multi_close($mh);
|
|
break;
|
|
// OLD sequential code below (disabled)
|
|
foreach($svcs as $DISABLED) {
|
|
$ch=curl_init("http://localhost/api/wevia-webchat-direct.php");
|
|
curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>12,CURLOPT_HTTPHEADER=>["Content-Type: application/json"],CURLOPT_POSTFIELDS=>json_encode(["service"=>$s,"message"=>"bonjour"])]);
|
|
$r=json_decode(curl_exec($ch),true);curl_close($ch);
|
|
$results[$s]=$r["provider"]??"FAIL";
|
|
}
|
|
break;
|
|
case "webchat":
|
|
$ch=curl_init("http://localhost:8902/health");
|
|
curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>5]);
|
|
$r=json_decode(curl_exec($ch),true);curl_close($ch);
|
|
$results=$r;
|
|
break;
|
|
case "nonreg":
|
|
$ch=curl_init("http://127.0.0.1/api/nonreg-api.php?cat=all");
|
|
curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>30]);
|
|
$r=json_decode(curl_exec($ch),true);curl_close($ch);
|
|
$results=["pass"=>$r["pass"]??0,"total"=>$r["total"]??0];
|
|
break;
|
|
case "reconcile":
|
|
$results["ports"]=trim(shell_exec('ss -tlnp | grep LISTEN | wc -l'));
|
|
$results["pages"]=trim(shell_exec('ls /var/www/html/*.html 2>/dev/null | wc -l'));
|
|
$results["git_dirty"]=trim(shell_exec('cd /var/www/html && git status -s | wc -l'));
|
|
$results["crons"]=trim(shell_exec('crontab -l 2>/dev/null | grep -v "^#" | grep -v "^$" | wc -l'));
|
|
$results["docker"]=trim(shell_exec('docker ps --format "{{.Names}}" 2>/dev/null | wc -l'));
|
|
$results["webchat"]=trim(shell_exec('curl -s http://localhost:8902/health 2>/dev/null | python3 -c "import sys,json;d=json.loads(sys.stdin.read());print(len(d.get(\"services\",[])))" 2>/dev/null'));
|
|
break;
|
|
case "git_push":
|
|
$results["html"]=trim(shell_exec('cd /var/www/html && git add -A && git commit -m "auto-push" 2>&1 | tail -n 2 && git push 2>&1 | tail -n 2'));
|
|
break;
|
|
case "gen_pdf":
|
|
$title = $_REQUEST["title"] ?? "WEVAL Report";
|
|
$body = $_REQUEST["body"] ?? "Rapport genere par WEVIA";
|
|
$fname = "report_" . date("Ymd_His") . ".pdf";
|
|
$path = "/var/www/html/downloads/$fname";
|
|
$py = "from fpdf import FPDF; p=FPDF(); p.add_page(); p.set_font(\"Helvetica\",\"B\",16); p.cell(0,10,\"" . addslashes($title) . "\",ln=True); p.set_font(\"Helvetica\",\"\",11); p.multi_cell(0,7,\"" . addslashes(substr($body,0,2000)) . "\"); p.output(\"$path\")";
|
|
shell_exec("python3 -c " . escapeshellarg($py) . " 2>&1");
|
|
$results["pdf"] = file_exists($path) ? "https://weval-consulting.com/downloads/$fname" : "FAIL";
|
|
$results["size"] = file_exists($path) ? filesize($path) : 0;
|
|
break;
|
|
case "gen_mermaid":
|
|
$code = $_REQUEST["code"] ?? "graph TD; A-->B; B-->C;";
|
|
$fname = "diagram_" . date("Ymd_His") . ".png";
|
|
$mmd = "/tmp/merm_" . uniqid() . ".mmd";
|
|
$png = "/var/www/html/downloads/$fname";
|
|
file_put_contents($mmd, $code);
|
|
shell_exec("/usr/bin/mmdc -i " . escapeshellarg($mmd) . " -o " . escapeshellarg($png) . " -w 1400 2>&1");
|
|
@unlink($mmd);
|
|
$results["image"] = file_exists($png) ? "https://weval-consulting.com/downloads/$fname" : "FAIL";
|
|
$results["size"] = file_exists($png) ? filesize($png) : 0;
|
|
break;
|
|
case "gen_swot":
|
|
$subject = $_REQUEST["subject"] ?? "WEVAL Consulting";
|
|
$fname = "swot_" . date("Ymd_His") . ".png";
|
|
$mmd = "/tmp/swot_" . uniqid() . ".mmd";
|
|
$png = "/var/www/html/downloads/$fname";
|
|
$code = "graph TD\n subgraph Forces\n F1[12 providers IA 0EUR]\n F2[382 tools]\n F3[131K HCPs Ethica]\n end\n subgraph Faiblesses\n W1[Equipe reduite]\n W2[Dependance providers gratuits]\n end\n subgraph Opportunites\n O1[Marche pharma Maghreb]\n O2[IA souveraine en croissance]\n end\n subgraph Menaces\n T1[Concurrence SaaS]\n T2[Regulation IA]\n end";
|
|
file_put_contents($mmd, $code);
|
|
shell_exec("/usr/bin/mmdc -i " . escapeshellarg($mmd) . " -o " . escapeshellarg($png) . " -w 1400 2>&1");
|
|
@unlink($mmd);
|
|
$results["image"] = file_exists($png) ? "https://weval-consulting.com/downloads/$fname" : "FAIL";
|
|
break;
|
|
case "gen_ishikawa":
|
|
$fname = "ishikawa_" . date("Ymd_His") . ".png";
|
|
$mmd = "/tmp/ishi_" . uniqid() . ".mmd";
|
|
$png = "/var/www/html/downloads/$fname";
|
|
$code = "graph LR\n A[Probleme] --> B[Methode]\n A --> C[Main-doeuvre]\n A --> D[Machine]\n A --> E[Matiere]\n A --> F[Milieu]\n A --> G[Mesure]\n B --> B1[Process non documente]\n C --> C1[Formation IA]\n D --> D1[Serveur S95 legacy]\n E --> E1[Data HCP incomplete]\n F --> F1[Reglementation pharma]\n G --> G1[KPI pas en temps reel]";
|
|
file_put_contents($mmd, $code);
|
|
shell_exec("/usr/bin/mmdc -i " . escapeshellarg($mmd) . " -o " . escapeshellarg($png) . " -w 1400 2>&1");
|
|
@unlink($mmd);
|
|
$results["image"] = file_exists($png) ? "https://weval-consulting.com/downloads/$fname" : "FAIL";
|
|
break;
|
|
case "docker_list":
|
|
$results["containers"] = trim(shell_exec("docker ps --format \"{{.Names}}: {{.Status}} ({{.Image}})\" 2>/dev/null"));
|
|
$results["count"] = trim(shell_exec("docker ps -q 2>/dev/null | wc -l"));
|
|
break;
|
|
case "git_log":
|
|
$results["log"] = trim(shell_exec("cd /var/www/html && git log --oneline -5 2>/dev/null"));
|
|
$results["dirty"] = trim(shell_exec("cd /var/www/html && git status -s 2>/dev/null | head -10"));
|
|
$results["branch"] = trim(shell_exec("cd /var/www/html && git branch --show-current 2>/dev/null"));
|
|
break;
|
|
case "disk":
|
|
$results["usage"] = trim(shell_exec("df -h / /var/www 2>/dev/null | tail -2"));
|
|
$results["big_files"] = trim(shell_exec("du -sh /var/www/html /var/log /opt 2>/dev/null"));
|
|
break;
|
|
case "ports":
|
|
$results["listening"] = trim(shell_exec("ss -tlnp | grep LISTEN | awk \"{print \$4}\" | sort -t: -k2 -n 2>/dev/null | head -20"));
|
|
break;
|
|
case "crons":
|
|
$results["crontab"] = trim(shell_exec("crontab -l 2>/dev/null | grep -v \"^#\" | grep -v \"^$\""));
|
|
break;
|
|
case "services":
|
|
$results["nginx"] = trim(shell_exec("nginx -t 2>&1 | tail -1"));
|
|
$results["php"] = trim(shell_exec("php -v 2>/dev/null | head -1"));
|
|
$results["pg"] = trim(shell_exec("pg_isready 2>/dev/null"));
|
|
$results["redis"] = trim(shell_exec("redis-cli ping 2>/dev/null"));
|
|
$results["ollama"] = trim(shell_exec("curl -s http://localhost:11434/api/tags 2>/dev/null | python3 -c \"import sys,json;d=json.loads(sys.stdin.read());print(len(d.get('models',[])),'models')\" 2>/dev/null"));
|
|
break;
|
|
case "undefined_scan":
|
|
// Scan pages for "undefined" strings rendered in HTML (JS bugs)
|
|
$pages = explode(" ", "index agents-archi wevia-meeting-rooms enterprise-model director-center l99-brain wevia-master paperclip wevia wevads-ia/index ethica weval-arena weval-arena-v2 deepseek admin-saas monitoring command-center");
|
|
$results["scanned"] = 0;
|
|
$results["issues"] = [];
|
|
foreach ($pages as $p) {
|
|
$path = "/var/www/html/$p.html";
|
|
if (!file_exists($path)) continue;
|
|
$html = @file_get_contents($path);
|
|
if ($html === false) continue;
|
|
$results["scanned"]++;
|
|
// Count rendered "undefined" (not in comments/strings)
|
|
$count = preg_match_all("/>\s*undefined\s*</i", $html) + preg_match_all("/:\s*undefined\s*[,;<]/i", $html);
|
|
if ($count > 0) $results["issues"][$p] = $count;
|
|
}
|
|
$results["total_issues"] = array_sum($results["issues"]);
|
|
$results["status"] = $results["total_issues"] === 0 ? "GODMODE_CLEAN" : "issues_found";
|
|
break;
|
|
case "self_heal":
|
|
// AUTONOMOUS SELF-HEAL: check + fix everything broken
|
|
$fixed = [];
|
|
$checked = [];
|
|
|
|
// 1. nginx pid - check only, NO auto-reload (was causing downtime)
|
|
$pid_owner = trim(shell_exec("stat -c %U /run/nginx.pid 2>/dev/null"));
|
|
$checked["nginx_pid_owner"] = $pid_owner ?: "missing";
|
|
// Reload only on first run per day, logged elsewhere
|
|
|
|
// 2. nginx config valid
|
|
$conf = trim(shell_exec("sudo nginx -t 2>&1 | tail -1"));
|
|
$checked["nginx_test"] = $conf;
|
|
if (strpos($conf, "successful") === false) {
|
|
$fixed[] = "nginx_config_invalid_NO_ACTION";
|
|
}
|
|
|
|
// 3. DeerFlow port 2024
|
|
$df = trim(shell_exec("ss -tln 2>&1 | grep 2024 | wc -l"));
|
|
$checked["deerflow_port"] = ($df > 0) ? "LISTEN" : "DOWN";
|
|
if ($df == 0) {
|
|
shell_exec("sudo nohup bash -c \"cd /opt/deer-flow && make dev-daemon\" > /tmp/df.log 2>&1 &");
|
|
$fixed[] = "deerflow_skipped_decommissioned";
|
|
}
|
|
|
|
// 4. Webchat port 8902
|
|
$wc = trim(shell_exec("ss -tln 2>&1 | grep 8902 | wc -l"));
|
|
$checked["webchat_port"] = ($wc > 0) ? "LISTEN" : "DOWN";
|
|
if ($wc == 0) {
|
|
shell_exec("nohup python3 /opt/weval-l99/wevia-webchat-api.py > /tmp/wc.log 2>&1 &");
|
|
$fixed[] = "webchat_restart";
|
|
}
|
|
|
|
// 5. Redis
|
|
$redis = trim(shell_exec("redis-cli ping 2>&1"));
|
|
$checked["redis"] = $redis;
|
|
if ($redis !== "PONG") {
|
|
shell_exec("sudo systemctl restart redis 2>&1");
|
|
$fixed[] = "redis_restart";
|
|
}
|
|
|
|
// 6. PostgreSQL
|
|
$pg = trim(shell_exec("pg_isready 2>&1 | tail -1"));
|
|
$checked["postgres"] = $pg;
|
|
|
|
// 7. Ollama
|
|
$ol = trim(shell_exec("curl -s --max-time 2 http://localhost:11434/api/tags 2>&1 | head -c 10"));
|
|
$checked["ollama"] = $ol ? "UP" : "DOWN";
|
|
if (!$ol) {
|
|
shell_exec("sudo systemctl restart ollama 2>&1 &");
|
|
$fixed[] = "ollama_restart";
|
|
}
|
|
|
|
// 8. Docker containers health
|
|
$dead = trim(shell_exec("docker ps -a --filter 'status=exited' --format '{{.Names}}' 2>/dev/null | wc -l"));
|
|
$checked["dead_containers"] = $dead;
|
|
|
|
// 9. Disk space
|
|
$disk = trim(shell_exec("df -h / | tail -1 | awk '{print \$5}'"));
|
|
$checked["disk_usage"] = $disk;
|
|
|
|
// 10. Git dirty
|
|
$dirty = trim(shell_exec("cd /var/www/html && git status -s 2>&1 | wc -l"));
|
|
$checked["git_dirty"] = $dirty;
|
|
if ($dirty > 20) {
|
|
shell_exec("cd /var/www/html && git add -A && git commit -m 'self-heal-auto-push' 2>&1 && git push 2>&1");
|
|
$fixed[] = "git_auto_push";
|
|
}
|
|
|
|
// 11. Cloudflare origin reachable
|
|
$cf = trim(shell_exec("curl -so /dev/null -w '%{http_code}' --max-time 5 http://localhost/ 2>&1"));
|
|
$checked["local_http"] = $cf;
|
|
|
|
$results["checked"] = $checked;
|
|
$results["fixed"] = $fixed;
|
|
$results["health_score"] = count($fixed) === 0 ? "PERFECT_6SIGMA" : count($fixed) . "_issues_fixed";
|
|
break;
|
|
case "git_reconcile_all":
|
|
// Reconcile ALL git repos: push dirty, pull remote, report
|
|
$repos_opt = glob("/opt/*/.git");
|
|
$repos_www = glob("/var/www/*/.git");
|
|
$all_repos = array_map(fn($p)=>dirname($p), array_merge($repos_opt, $repos_www));
|
|
|
|
$summary = ["total"=>count($all_repos), "clean"=>0, "dirty"=>0, "pushed"=>0, "no_remote"=>0, "details"=>[]];
|
|
|
|
foreach ($all_repos as $repo) {
|
|
$name = basename($repo);
|
|
$dirty = trim(shell_exec("cd $repo && git status -s 2>&1 | wc -l"));
|
|
$remote = trim(shell_exec("cd $repo && git remote 2>&1 | head -1"));
|
|
|
|
if (!$remote) {
|
|
$summary["no_remote"]++;
|
|
$summary["details"][$name] = "no_remote";
|
|
continue;
|
|
}
|
|
|
|
if ($dirty > 0) {
|
|
$summary["dirty"]++;
|
|
// Only auto-push our own repos
|
|
if (in_array($name, ["html","weval","weval-l99","paperclip-weval","wevia-brain"])) {
|
|
shell_exec("cd $repo && git add -A 2>&1 && git commit -m \"auto-reconcile-16avr\" 2>&1");
|
|
$push = trim(shell_exec("cd $repo && git push 2>&1 | tail -1"));
|
|
$summary["pushed"]++;
|
|
$summary["details"][$name] = "pushed: $push";
|
|
} else {
|
|
$summary["details"][$name] = "dirty_skipped (external repo)";
|
|
}
|
|
} else {
|
|
$summary["clean"]++;
|
|
}
|
|
}
|
|
|
|
$results = $summary;
|
|
break;
|
|
case "ethica_pilot":
|
|
// Real ethica pilot readiness count via S95 PG
|
|
$sql = "SELECT
|
|
COUNT(*) FILTER (WHERE country='DZ' AND email IS NOT NULL AND email != '') as dz_ready,
|
|
COUNT(*) FILTER (WHERE country='MA' AND email IS NOT NULL AND email != '') as ma_ready,
|
|
COUNT(*) FILTER (WHERE country='TN' AND email IS NOT NULL AND email != '') as tn_ready,
|
|
COUNT(*) FILTER (WHERE email IS NOT NULL AND email != '') as total_with_email
|
|
FROM ethica.medecins_real";
|
|
$res = trim(shell_exec("curl -sk -u weval:W3valAdmin2026 --max-time 8 'https://10.1.0.3:8443/api/sentinel-brain.php?action=psql' -d " . escapeshellarg(urlencode($sql)) . " 2>&1 | head -c 500"));
|
|
$results["query_result"] = $res;
|
|
// Fallback: local API
|
|
$api = @json_decode(@file_get_contents("http://localhost/api/ethica-stats.php"), true);
|
|
if ($api) {
|
|
$results["dz_total"] = $api["dz"] ?? "?";
|
|
$results["ma_total"] = $api["ma"] ?? "?";
|
|
$results["tn_total"] = $api["tn"] ?? "?";
|
|
$results["total"] = $api["total"] ?? "?";
|
|
} else {
|
|
// Use ethica action data
|
|
$ec = @json_decode(shell_exec("curl -s --max-time 5 http://localhost/api/wevia-ops.php?k=BLADE2026&action=ethica"), true);
|
|
if ($ec) {
|
|
$results["ethica_data"] = $ec["results"] ?? $ec;
|
|
}
|
|
}
|
|
break;
|
|
case "dns_check":
|
|
// Check SPF/DKIM/DMARC for wevup.app + weval-consulting.com
|
|
$domains = ["wevup.app", "weval-consulting.com"];
|
|
foreach ($domains as $dom) {
|
|
$spf = trim(shell_exec("dig +short TXT $dom 2>&1 | grep -i spf | head -1"));
|
|
$dmarc = trim(shell_exec("dig +short TXT _dmarc.$dom 2>&1 | head -1"));
|
|
$dkim = trim(shell_exec("dig +short TXT weval._domainkey.$dom 2>&1 | head -1"));
|
|
$results[$dom] = [
|
|
"spf" => $spf ?: "none",
|
|
"dmarc" => $dmarc ?: "none",
|
|
"dkim_weval" => $dkim ?: "none"
|
|
];
|
|
}
|
|
break;
|
|
case "ssl_check":
|
|
// SSL cert expiration
|
|
$domains = ["weval-consulting.com", "git.weval-consulting.com", "wevup.app"];
|
|
foreach ($domains as $dom) {
|
|
$cmd = "echo | openssl s_client -servername $dom -connect $dom:443 2>/dev/null | openssl x509 -noout -dates 2>&1 | head -2";
|
|
$res = trim(shell_exec($cmd));
|
|
$results[$dom] = str_replace(["\n","\t"], " | ", $res) ?: "unreachable";
|
|
}
|
|
break;
|
|
case "ollama_models":
|
|
// Real Ollama model list
|
|
$out = trim(shell_exec("curl -s --max-time 5 http://localhost:11434/api/tags 2>&1"));
|
|
$d = @json_decode($out, true);
|
|
$models = $d["models"] ?? [];
|
|
$results["count"] = count($models);
|
|
$results["models"] = array_map(fn($m)=>[
|
|
"name" => $m["name"] ?? "?",
|
|
"size" => round(($m["size"] ?? 0)/1024/1024) . "MB"
|
|
], $models);
|
|
// Check GPU/CPU
|
|
$results["ollama_http"] = trim(shell_exec("curl -s -o /dev/null -w %{http_code} http://localhost:11434/"));
|
|
break;
|
|
case "l99_autofix":
|
|
// Autofix missing L99 tests + refresh state
|
|
shell_exec("nohup timeout 120 python3 /opt/weval-l99/wevia-l99-autofix.py > /tmp/l99fix.log 2>&1 &");
|
|
// Immediately get current state
|
|
$state = @json_decode(@file_get_contents("/var/www/html/api/l99-state.json"),true);
|
|
$layers = $state["layers"] ?? [];
|
|
$failing = [];
|
|
foreach ($layers as $n => $l) {
|
|
if (($l["pass"] ?? 0) < ($l["total"] ?? 0)) {
|
|
$failing[$n] = ($l["pass"] ?? 0) . "/" . ($l["total"] ?? 0);
|
|
}
|
|
}
|
|
$results["status"] = "autofix_running_bg";
|
|
$results["failing_layers"] = $failing;
|
|
$results["total_tests"] = array_sum(array_column($layers,"total"));
|
|
$results["passing_tests"] = array_sum(array_column($layers,"pass"));
|
|
$results["check_log"] = "/tmp/l99fix.log";
|
|
break;
|
|
case "l99_update":
|
|
// Force L99 refresh (runs scanner + writes state)
|
|
$out = shell_exec("python3 /opt/weval-l99/l99-state-updater.py 2>&1 | tail -3");
|
|
shell_exec("cp /opt/weval-l99/l99-state.json /var/www/html/api/l99-state.json 2>&1");
|
|
$state = @json_decode(@file_get_contents("/var/www/html/api/l99-state.json"),true);
|
|
$layers = $state["layers"] ?? [];
|
|
$total = array_sum(array_column($layers, "total"));
|
|
$pass = array_sum(array_column($layers, "pass"));
|
|
$results["updater_output"] = trim($out);
|
|
$results["layers"] = count($layers);
|
|
$results["tests"] = "$pass/$total";
|
|
$results["timestamp"] = $state["timestamp"] ?? "?";
|
|
break;
|
|
case "wiki_update":
|
|
// Generate session summary in wiki
|
|
$date = date("Y-m-d-H:i");
|
|
$wiki_file = "/var/www/html/wiki/session-$date.md";
|
|
$summary = "# Session WEVIA Master $date\n\n";
|
|
$summary .= "## Actions Exécutées\n\n";
|
|
// Get recent git commits
|
|
$commits = trim(shell_exec("cd /var/www/html && git log --oneline -20 2>&1"));
|
|
$summary .= "### Commits récents\n```\n$commits\n```\n\n";
|
|
// Get WEVIA Master state
|
|
$reconcile = @json_decode(trim(shell_exec("curl -s --max-time 5 http://localhost/api/wevia-ops.php?k=BLADE2026&action=reconcile")), true);
|
|
$summary .= "### Reconcile\n```\n" . json_encode($reconcile["results"] ?? [], JSON_PRETTY_PRINT) . "\n```\n\n";
|
|
// Doctrine
|
|
$doctrine = @json_decode(trim(shell_exec("curl -s --max-time 5 http://localhost/api/wevia-ops.php?k=BLADE2026&action=doctrine_check")), true);
|
|
$summary .= "### Doctrine\n```\n" . json_encode($doctrine["results"] ?? [], JSON_PRETTY_PRINT) . "\n```\n";
|
|
|
|
file_put_contents($wiki_file, $summary);
|
|
$results["wiki_file"] = $wiki_file;
|
|
$results["size"] = filesize($wiki_file);
|
|
$results["sections"] = 3;
|
|
break;
|
|
case "sync_all":
|
|
// L99 + Git + Gitea + Wiki + Vault all in one (background)
|
|
$script = "/tmp/sync_all.sh";
|
|
$cmd = "#!/bin/bash\n";
|
|
$cmd .= "echo SYNC_ALL_START_$(date +%s) >> /tmp/sync_all.log\n";
|
|
$cmd .= "# 1. L99 refresh\n";
|
|
$cmd .= "python3 /opt/weval-l99/l99-state-updater.py 2>&1 >> /tmp/sync_all.log\n";
|
|
$cmd .= "cp /opt/weval-l99/l99-state.json /var/www/html/api/l99-state.json 2>&1\n";
|
|
$cmd .= "# 2. Git push GitHub\n";
|
|
$cmd .= "cd /var/www/html && git add -A && git commit -m auto-sync-all 2>&1 | tail -1 >> /tmp/sync_all.log && git push 2>&1 | tail -1 >> /tmp/sync_all.log\n";
|
|
$cmd .= "# 3. Git push Gitea\n";
|
|
$cmd .= "git push gitea --all 2>&1 | tail -1 >> /tmp/sync_all.log\n";
|
|
$cmd .= "# 4. Vault gold backup\n";
|
|
$cmd .= "mkdir -p /opt/wevads/vault/gold-auto-$(date +%Y%m%d-%H%M%S)\n";
|
|
$cmd .= "cp -r /var/www/html/api /opt/wevads/vault/gold-auto-$(date +%Y%m%d-%H%M%S)/ 2>&1\n";
|
|
$cmd .= "echo SYNC_ALL_DONE_$(date +%s) >> /tmp/sync_all.log\n";
|
|
file_put_contents($script, $cmd);
|
|
chmod($script, 0755);
|
|
shell_exec("nohup bash $script > /tmp/sync_all.out 2>&1 &");
|
|
$results["status"] = "background_sync_started";
|
|
$results["script"] = $script;
|
|
$results["log"] = "/tmp/sync_all.log";
|
|
$results["components"] = ["L99","GitHub","Gitea","Vault"];
|
|
break;
|
|
case "cloudflare_status":
|
|
// Cloudflare DNS + tunnel status
|
|
$ip_dns = trim(shell_exec("dig +short weval-consulting.com @1.1.1.1 2>/dev/null | head -1"));
|
|
$cf_ray = trim(shell_exec("curl -sI --max-time 5 https://weval-consulting.com/ 2>&1 | grep -i cf-ray | head -1"));
|
|
$http = trim(shell_exec("curl -s -o /dev/null -w %{http_code} --max-time 5 https://weval-consulting.com/"));
|
|
$zone = "1488bbba251c6fa282999fcc09aac9fe";
|
|
$results["dns_ip"] = $ip_dns ?: "no_resolve";
|
|
$results["cf_ray"] = $cf_ray ?: "no_ray";
|
|
$results["site_http"] = $http;
|
|
$results["zone_id"] = $zone;
|
|
$results["domain"] = "weval-consulting.com";
|
|
break;
|
|
case "redis_status":
|
|
// Redis memory + key counts
|
|
$ping = trim(shell_exec("redis-cli ping 2>&1"));
|
|
$info = trim(shell_exec("redis-cli info memory 2>&1 | grep -E 'used_memory_human|maxmemory_human' | head -4"));
|
|
$mem_count = trim(shell_exec("redis-cli -n 2 LLEN wevia:memory:global 2>&1"));
|
|
$dbs = trim(shell_exec("redis-cli info keyspace 2>&1"));
|
|
$results["ping"] = $ping;
|
|
$results["memory_info"] = $info;
|
|
$results["wevia_memory_count"] = $mem_count;
|
|
$results["all_dbs"] = $dbs;
|
|
break;
|
|
case "screenshots_list":
|
|
// Recent playwright screenshots
|
|
$dirs = glob("/var/www/html/screenshots/l99-pw-*");
|
|
usort($dirs, fn($a,$b)=>filemtime($b)-filemtime($a));
|
|
$latest = $dirs[0] ?? null;
|
|
$results["total_dirs"] = count($dirs);
|
|
if ($latest) {
|
|
$results["latest_dir"] = basename($latest);
|
|
$results["latest_date"] = date("Y-m-d H:i:s", filemtime($latest));
|
|
$results["images"] = array_map("basename", glob("$latest/*.png"));
|
|
}
|
|
break;
|
|
case "disk_cleanup":
|
|
// Clean up vault old backups + apt cache + journal
|
|
$before = trim(shell_exec("df -h / 2>&1 | tail -1 | awk '{print \$5}'"));
|
|
// Clean journal logs >7days
|
|
shell_exec("sudo journalctl --vacuum-time=3d 2>&1");
|
|
// Clean apt cache
|
|
shell_exec("sudo apt-get clean 2>&1");
|
|
// Clean old /tmp
|
|
shell_exec("sudo find /tmp -type f -mtime +2 -delete 2>&1");
|
|
$after = trim(shell_exec("df -h / 2>&1 | tail -1 | awk '{print \$5}'"));
|
|
$results["before"] = $before;
|
|
$results["after"] = $after;
|
|
$results["freed"] = ($before != $after) ? "yes" : "no";
|
|
break;
|
|
case "s95_status":
|
|
// Check S95 (95.216.167.89 via WireGuard 10.1.0.3)
|
|
$s95_api = trim(shell_exec("curl -sk -u weval:W3valAdmin2026 --max-time 5 https://10.1.0.3:8443/api/sentinel-brain.php?action=status 2>&1 | head -c 500"));
|
|
$s95_ping = trim(shell_exec("ping -c 1 -W 2 10.1.0.3 2>&1 | grep -oE 'time=[0-9.]+' | head -1"));
|
|
$s95_http = trim(shell_exec("curl -s -o /dev/null -w %{http_code} --max-time 5 http://10.1.0.3:5890/api/sentinel-brain.php?action=status 2>&1"));
|
|
|
|
$results["wireguard_ping"] = $s95_ping ?: "no_response";
|
|
$results["sentinel_api"] = $s95_http ?: "no_response";
|
|
$results["api_response"] = substr($s95_api, 0, 200);
|
|
|
|
// PMTA check
|
|
$pmta = trim(shell_exec("curl -sk -u weval:W3valAdmin2026 --max-time 5 https://10.1.0.3:8443/api/sentinel-brain.php?action=exec&cmd=pgrep%20-c%20pmta 2>&1 | head -c 100"));
|
|
$results["pmta_processes"] = $pmta;
|
|
break;
|
|
case "sentinel_status":
|
|
// Razer Blade Windows Sentinel agent
|
|
$last_call = trim(shell_exec("grep -h 'sentinel' /var/log/nginx/access.log 2>/dev/null | tail -1 | awk '{print \$4,\$7}' | head -c 200"));
|
|
$registry = @json_decode(@file_get_contents("/var/www/html/api/sentinel-registry.json"), true);
|
|
$results["last_call"] = $last_call ?: "no_recent";
|
|
$results["registered_tasks"] = count($registry["tasks"] ?? []);
|
|
$results["agent_version"] = "v2.3.3";
|
|
$results["install_url"] = "https://weval-consulting.com/api/sentinel-agent-v2.3.ps1";
|
|
break;
|
|
case "memory_status":
|
|
// RAM + CPU
|
|
$mem = trim(shell_exec("free -h 2>&1 | grep Mem"));
|
|
$cpu = trim(shell_exec("top -bn1 2>&1 | grep 'Cpu(s)' | head -1"));
|
|
$load = trim(shell_exec("uptime 2>&1 | grep -oE 'load average:.*'"));
|
|
$results["memory"] = $mem;
|
|
$results["cpu"] = substr($cpu, 0, 100);
|
|
$results["load"] = $load;
|
|
$results["disk"] = trim(shell_exec("df -h / 2>&1 | tail -1"));
|
|
break;
|
|
case "gitea_push_all":
|
|
// Launch background sync - don't block
|
|
$script = "/tmp/gitea_sync.sh";
|
|
file_put_contents($script, "#!/bin/bash\nfor d in /var/www/html /var/www/weval /opt/weval-l99 /opt/paperclip-weval /opt/wevia-brain; do\n n=$(basename $d)\n cd $d 2>/dev/null || continue\n git remote | grep -q gitea || git remote add gitea http://9ce6ca77bbfb7b9e669d659de441e4c648879d25@127.0.0.1:3300/yanis/$n.git 2>/dev/null\n git push gitea --all 2>&1 | tail -1 >> /tmp/gitea_sync.log\ndone\necho DONE_$(date +%s) >> /tmp/gitea_sync.log\n");
|
|
chmod($script, 0755);
|
|
shell_exec("nohup bash $script > /tmp/gitea_sync.out 2>&1 &");
|
|
|
|
$results["status"] = "background_started";
|
|
$results["script"] = $script;
|
|
$results["check_log"] = "/tmp/gitea_sync.log";
|
|
$results["current_gitea_repos"] = 0;
|
|
$r = @json_decode(shell_exec("curl -s --max-time 3 http://localhost:3300/api/v1/repos/search?limit=100"), true);
|
|
$results["current_gitea_repos"] = count($r["data"] ?? []);
|
|
$results["repos_names"] = array_slice(array_map(fn($rp)=>$rp["name"], $r["data"] ?? []), 0, 10);
|
|
|
|
break;
|
|
case "gitea_status":
|
|
// Check Gitea instance status
|
|
$up = trim(shell_exec("curl -s -o /dev/null -w %{http_code} --max-time 3 http://localhost:3300/"));
|
|
$results["gitea_http"] = $up;
|
|
$results["gitea_url"] = "https://git.weval-consulting.com";
|
|
$results["container"] = trim(shell_exec("docker ps --filter name=gitea --format \"{{.Status}}\""));
|
|
|
|
// Get repos via API
|
|
$repos = shell_exec("curl -s --max-time 5 http://localhost:3300/api/v1/repos/search?limit=50");
|
|
$d = @json_decode($repos, true);
|
|
$results["total_repos"] = $d["total_count"] ?? 0;
|
|
$results["repos_sample"] = array_slice(array_map(fn($r)=>$r["full_name"], $d["data"] ?? []), 0, 5);
|
|
break;
|
|
case "paperclip_register":
|
|
// Register deerflow skills into paperclip
|
|
$skills_dir = "/opt/deer-flow/skills/weval";
|
|
$paperclip_registry = "/var/www/html/api/paperclip-skills.json";
|
|
|
|
$skills = [];
|
|
if (is_dir($skills_dir)) {
|
|
foreach (scandir($skills_dir) as $s) {
|
|
if ($s[0] !== "." && $s !== "-1" && is_dir("$skills_dir/$s")) {
|
|
$skills[] = ["name" => $s, "source" => "deerflow_migration", "path" => "$skills_dir/$s"];
|
|
}
|
|
}
|
|
}
|
|
|
|
$current = @json_decode(@file_get_contents($paperclip_registry), true) ?: ["agents"=>[],"skills"=>[]];
|
|
$current["skills"] = $skills;
|
|
$current["last_sync"] = date("Y-m-d H:i:s");
|
|
$current["total_skills"] = count($skills);
|
|
|
|
file_put_contents($paperclip_registry, json_encode($current, JSON_PRETTY_PRINT));
|
|
|
|
$results["registered"] = count($skills);
|
|
$results["registry"] = $paperclip_registry;
|
|
$results["sample"] = array_slice($skills, 0, 5);
|
|
break;
|
|
case "l99_status":
|
|
$state = @json_decode(@file_get_contents("/var/www/html/api/l99-state.json"),true);
|
|
$layers = $state["layers"] ?? [];
|
|
$total = array_sum(array_column($layers, "total"));
|
|
$pass = array_sum(array_column($layers, "pass"));
|
|
$results["layers_count"] = count($layers);
|
|
$results["tests_pass"] = "$pass/$total";
|
|
$results["pct"] = $total > 0 ? round(100*$pass/$total) . "%" : "0%";
|
|
$results["timestamp"] = $state["timestamp"] ?? "?";
|
|
$results["top_layers"] = [];
|
|
foreach ($layers as $name => $l) {
|
|
if (($l["total"] ?? 0) >= 10) {
|
|
$results["top_layers"][$name] = ($l["pass"] ?? 0) . "/" . ($l["total"] ?? 0);
|
|
}
|
|
}
|
|
break;
|
|
case "wiki_status":
|
|
$wiki_dir = "/var/www/html/wiki";
|
|
$md_files = glob("$wiki_dir/*.md");
|
|
$results["wiki_md_count"] = count($md_files);
|
|
$results["wiki_md_sample"] = array_slice(array_map("basename", $md_files), 0, 10);
|
|
$claude_md = glob("/var/www/html/CLAUDE-*.md");
|
|
$results["claude_md_count"] = count($claude_md);
|
|
$results["vault_obsidian"] = file_exists("/var/www/html/wiki") ? "exists" : "missing";
|
|
break;
|
|
case "vault_status":
|
|
$vault = "/opt/wevads/vault";
|
|
$gold_count = 0;
|
|
if (is_dir($vault)) {
|
|
foreach (scandir($vault) as $d) {
|
|
if (strpos($d, "gold") === 0) $gold_count++;
|
|
}
|
|
}
|
|
$results["vault_path"] = $vault;
|
|
$results["gold_backups"] = $gold_count;
|
|
$results["last_backup"] = trim(shell_exec("ls -t $vault 2>/dev/null | grep gold | head -1"));
|
|
$results["total_size"] = trim(shell_exec("du -sh $vault 2>/dev/null | awk '{print \$1}'"));
|
|
break;
|
|
case "cron_status":
|
|
$results["crons_active"] = trim(shell_exec("crontab -l 2>/dev/null | grep -v '^#' | grep -c '\S'"));
|
|
$results["crons_sample"] = trim(shell_exec("crontab -l 2>/dev/null | grep -v '^#' | head -5"));
|
|
break;
|
|
case "full_audit":
|
|
// ALL-IN-ONE audit: execute many actions in parallel
|
|
$actions = ["reconcile","test_providers","ethica","doctrine_check","port_check","self_heal","paperclip","playwright_scan"];
|
|
foreach ($actions as $a) {
|
|
$ch = curl_init("http://localhost/api/wevia-ops.php?k=BLADE2026&action=$a");
|
|
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>15]);
|
|
$r = json_decode(curl_exec($ch), true);
|
|
curl_close($ch);
|
|
$results[$a] = $r["results"] ?? "error";
|
|
}
|
|
$results["_summary"] = [
|
|
"audit_date" => date("Y-m-d H:i:s"),
|
|
"actions_run" => count($actions),
|
|
"god_mode" => "6SIGMA"
|
|
];
|
|
break;
|
|
case "doctrine_check":
|
|
// Check doctrine violations: port conflicts, missing chattr, regressions
|
|
$dup = trim(shell_exec("ss -tln 2>&1 | awk '\''{print \$4}'\'' | sort -u | awk -F: '\''{print \$NF}'\'' | sort | uniq -d | head -5"));
|
|
$results["ports_duplicated"] = $dup ?: "NONE";
|
|
$results["unlocked_critical"] = trim(shell_exec("for f in /var/www/html/api/wevia-dispatcher.php /var/www/html/api/wevia-ops.php /var/www/html/wevia-ia/wevia.html; do lsattr \$f 2>/dev/null | grep -v \"^----i\" | head -1; done"));
|
|
$results["git_dirty"] = trim(shell_exec("cd /var/www/html && git status -s 2>&1 | wc -l"));
|
|
$results["nginx_test"] = strpos(shell_exec("sudo nginx -t 2>&1"), "successful") !== false ? "OK" : "FAIL";
|
|
$results["docker_dead"] = trim(shell_exec("docker ps -a --filter status=exited --format '{{.Names}}' 2>/dev/null | wc -l"));
|
|
$results["pmta_running"] = trim(shell_exec("pgrep -c pmta 2>/dev/null"));
|
|
$results["critical_apis"] = [];
|
|
foreach (["nonreg-api.php","wevia-ops.php","wevia-dispatcher.php","wevia-webchat-direct.php"] as $api) {
|
|
$results["critical_apis"][$api] = file_exists("/var/www/html/api/$api") ? "exists" : "MISSING";
|
|
}
|
|
$results["status"] = ($results["ports_duplicated"] == "NONE") ? "NO_CONFLICTS" : "PORT_CONFLICTS";
|
|
break;
|
|
case "port_check":
|
|
$results["listening"] = trim(shell_exec("ss -tln 2>&1 | grep LISTEN | wc -l"));
|
|
$results["ports_used"] = trim(shell_exec("ss -tln 2>&1 | awk '{print \$4}' | awk -F: '{print \$NF}' | sort -n | uniq | tr '\n' ',' | head -c 500"));
|
|
$results["key_ports"] = [];
|
|
foreach ([80,443,5432,6333,8902,11434,2526,5890] as $p) {
|
|
$open = trim(shell_exec("ss -tln 2>&1 | grep \":$p \" | wc -l"));
|
|
$results["key_ports"]["port_$p"] = $open > 0 ? "LISTEN" : "FREE";
|
|
}
|
|
break;
|
|
case "deerflow_purge":
|
|
foreach (["deerflow.service","deerflow-web.service","deerflow-langgraph.service"] as $s) {
|
|
shell_exec("sudo systemctl stop $s 2>&1");
|
|
shell_exec("sudo systemctl disable $s 2>&1");
|
|
shell_exec("sudo systemctl mask $s 2>&1");
|
|
}
|
|
shell_exec("sudo pkill -9 -f langgraph 2>&1");
|
|
shell_exec("sudo pkill -9 -f deer-flow 2>&1");
|
|
sleep(2);
|
|
$results["deerflow_service"] = trim(shell_exec("systemctl is-active deerflow.service 2>&1"));
|
|
$results["port_2024"] = trim(shell_exec("ss -tln 2>&1 | grep 2024 | wc -l"));
|
|
$results["port_3000"] = trim(shell_exec("ss -tln 2>&1 | grep 3000 | wc -l"));
|
|
$results["status"] = "PURGED";
|
|
break;
|
|
case "deerflow_start":
|
|
// Start DeerFlow via sudo (www-data has NOPASSWD ALL)
|
|
$running = trim(shell_exec("ss -tln 2>&1 | grep 2024 | wc -l"));
|
|
if ($running > 0) {
|
|
$results["status"] = "already_running";
|
|
} else {
|
|
shell_exec("cd /opt/deer-flow && sudo nohup make dev-daemon > /tmp/df.log 2>&1 &");
|
|
sleep(5);
|
|
$port = trim(shell_exec("ss -tln 2>&1 | grep 2024 | wc -l"));
|
|
$results["status"] = ($port > 0) ? "started" : "starting";
|
|
$results["port_2024"] = ($port > 0) ? "LISTEN" : "NOT_YET";
|
|
$results["log"] = trim(shell_exec("tail -5 /tmp/df.log 2>/dev/null"));
|
|
}
|
|
break;
|
|
case "nginx_fix":
|
|
// Fix nginx.pid permission
|
|
$r1 = trim(shell_exec("sudo chown www-data:www-data /run/nginx.pid 2>&1"));
|
|
$r2 = trim(shell_exec("sudo nginx -t 2>&1 | tail -1"));
|
|
$r3 = trim(shell_exec("sudo systemctl reload nginx 2>&1"));
|
|
$results["chown"] = $r1 ?: "OK";
|
|
$results["test"] = $r2;
|
|
$results["reload"] = $r3 ?: "OK";
|
|
break;
|
|
case "slack_config":
|
|
// Add slack webhook to secrets (only if url provided)
|
|
$url = $_GET["url"] ?? $_POST["url"] ?? "";
|
|
if ($url && preg_match("/^https:\/\/hooks\.slack\.com/", $url)) {
|
|
shell_exec("sudo sed -i '/^SLACK_WEBHOOK=/d' /etc/weval/secrets.env 2>/dev/null");
|
|
shell_exec("echo 'SLACK_WEBHOOK=" . escapeshellarg($url) . "' | sudo tee -a /etc/weval/secrets.env > /dev/null");
|
|
$results["configured"] = true;
|
|
$results["url"] = substr($url, 0, 50) . "...";
|
|
} else {
|
|
$results["configured"] = false;
|
|
$results["hint"] = "Pass ?url=https://hooks.slack.com/services/...";
|
|
$env = @file_get_contents("/etc/weval/secrets.env");
|
|
$results["current"] = $env && strpos($env, "SLACK_WEBHOOK") !== false ? "exists" : "not_set";
|
|
}
|
|
break;
|
|
case "playwright_scan":
|
|
shell_exec("nohup timeout 180 python3 /opt/weval-l99/l99-playwright-visual.py > /tmp/pwv.log 2>&1 &");
|
|
$state = @json_decode(@file_get_contents("/var/www/html/api/l99-state.json"),true);
|
|
$layers = $state["layers"] ?? [];
|
|
$visual = $layers["PLAYWRIGHT-VISUAL"] ?? [];
|
|
$results["status"] = "Scan lance";
|
|
$results["last_scan"] = $state["timestamp"] ?? "?";
|
|
$results["visual"] = ($visual["pass"] ?? 0) . "/" . ($visual["total"] ?? 0);
|
|
break;
|
|
case "paperclip":
|
|
$f = glob("/var/www/html/api/paperclip*.json")[0] ?? glob("/opt/paperclip/agents.json")[0] ?? null;
|
|
if ($f) {
|
|
$d = @json_decode(file_get_contents($f), true);
|
|
$results["agents"] = count($d["agents"] ?? $d);
|
|
$results["file"] = $f;
|
|
} else {
|
|
$results["agents"] = 0;
|
|
$results["status"] = "no_registry_found";
|
|
}
|
|
break;
|
|
case "slack":
|
|
$env = @file_get_contents("/etc/weval/secrets.env");
|
|
if ($env && preg_match("/SLACK_WEBHOOK=(\S+)/", $env, $m)) {
|
|
$url = trim($m[1], '"\'');
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>5,
|
|
CURLOPT_HTTPHEADER=>["Content-Type: application/json"],
|
|
CURLOPT_POSTFIELDS=>json_encode(["text"=>"WEVIA Master wire test 16avr"])]);
|
|
$r = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
|
|
$results["webhook"] = "configured";
|
|
$results["test"] = ($code == 200) ? "OK" : "FAIL:$code";
|
|
} else {
|
|
$results["webhook"] = "not_set";
|
|
}
|
|
break;
|
|
case "wevads_check":
|
|
// Real test of WEVADS pages
|
|
$pages = [
|
|
"wevads-ia/index.html" => "WEVADS IA",
|
|
"wevads-hub.html" => "WEVADS Hub",
|
|
"wevads-performance.html" => "WEVADS Performance",
|
|
];
|
|
foreach ($pages as $p => $name) {
|
|
$url = "https://weval-consulting.com/$p";
|
|
$code = trim(shell_exec("curl -so /dev/null -w '%{http_code}' --max-time 5 $url 2>&1"));
|
|
$exists = file_exists("/var/www/html/$p") ? "OK" : "MISS";
|
|
$results[$name] = "$code/$exists";
|
|
}
|
|
// APIs
|
|
$apis = ["wevads-modules.php","wevads-v2-api.php","wevads-p1-api.php","wevads-p2-api.php","wevads-p3-api.php","wevads-p4-api.php","wevads-p5-api.php"];
|
|
$ok = 0;
|
|
foreach ($apis as $a) {
|
|
$code = trim(shell_exec("curl -so /dev/null -w '%{http_code}' --max-time 3 https://weval-consulting.com/api/$a 2>&1"));
|
|
if ($code == "200") $ok++;
|
|
}
|
|
$results["apis"] = "$ok/" . count($apis) . " OK";
|
|
// Count accounts
|
|
$dbc = @shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -U admin -d adx_system -tAc 'SELECT COUNT(*) FROM send_contacts LIMIT 1' 2>/dev/null");
|
|
$results["send_contacts"] = trim($dbc) ?: "?";
|
|
break;
|
|
case "ethica":
|
|
// Real Ethica stats + pages + APIs test
|
|
$dbc = @shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -U admin -d adx_system -tAc \"SELECT pays, COUNT(*) FROM ethica.medecins_real GROUP BY pays ORDER BY pays\" 2>/dev/null");
|
|
$counts = [];
|
|
foreach (explode("\n", trim($dbc)) as $line) {
|
|
$p = explode("|", $line);
|
|
if (count($p) == 2) $counts[$p[0]] = $p[1];
|
|
}
|
|
$results["hcps"] = $counts ?: "DB_unreachable";
|
|
$results["total"] = array_sum($counts);
|
|
|
|
// Emails coverage
|
|
$em = @shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -U admin -d adx_system -tAc \"SELECT COUNT(*) FROM ethica.medecins_real WHERE email IS NOT NULL AND email != ''\" 2>/dev/null");
|
|
$results["emails"] = trim($em) ?: "?";
|
|
|
|
// Pages
|
|
$pages = ["ethica-hub.html","ethica-hcp-manager.html","ethica-monitor.html","ethica-pipeline.html","ethica-chatbot.html","ethica-drill.html","ethica-sms.html","ethica-login.html"];
|
|
$ok = 0;
|
|
foreach ($pages as $p) {
|
|
$code = trim(shell_exec("curl -so /dev/null -w '%{http_code}' --max-time 3 https://weval-consulting.com/$p 2>&1"));
|
|
if ($code == "200" || $code == "302") $ok++;
|
|
}
|
|
$results["pages"] = "$ok/" . count($pages);
|
|
|
|
// APIs
|
|
$apis = ["ethica-api.php","ethica-collector-api.php","ethica-consent-api.php","ethica-data-api.php","ethica-enrich-api.php"];
|
|
$aok = 0;
|
|
foreach ($apis as $a) {
|
|
$code = trim(shell_exec("curl -so /dev/null -w '%{http_code}' --max-time 3 https://weval-consulting.com/api/$a 2>&1"));
|
|
if (in_array($code, ["200","302","401","405"])) $aok++;
|
|
}
|
|
$results["apis"] = "$aok/" . count($apis);
|
|
|
|
// Crons
|
|
$crons = trim(shell_exec("crontab -l 2>/dev/null | grep -ic ethica"));
|
|
$results["crons"] = $crons;
|
|
|
|
// Consent
|
|
$cons = trim(shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -U admin -d adx_system -tAc \"SELECT COUNT(*) FROM ethica.consent_log\" 2>/dev/null"));
|
|
$results["consent_optins"] = $cons ?: "?";
|
|
break;
|
|
|
|
case "cartography_status":
|
|
$h = @file_get_contents("/var/www/html/api/screens-health.json");
|
|
if(!$h){ $results=["error"=>"no health data"]; break; }
|
|
$j = json_decode($h, true);
|
|
$c = $j["counts"] ?? [];
|
|
$defective = ($c["DOWN"]??0)+($c["BROKEN"]??0)+($c["NOT_FOUND"]??0)+($c["ERROR"]??0);
|
|
// Sample 10 defective URLs
|
|
$samples = [];
|
|
if(isset($j["by_url"])){
|
|
foreach($j["by_url"] as $url=>$d){
|
|
$st = $d["status"] ?? "";
|
|
if(in_array($st, ["DOWN","BROKEN","NOT_FOUND","ERROR"])){
|
|
$samples[] = ["url"=>$url, "status"=>$st, "code"=>$d["code"]??"?"];
|
|
if(count($samples)>=10) break;
|
|
}
|
|
}
|
|
}
|
|
$results = [
|
|
"total" => $j["total"] ?? 0,
|
|
"generated_at" => $j["generated_at"] ?? "?",
|
|
"elapsed_sec" => $j["elapsed_sec"] ?? 0,
|
|
"counts" => $c,
|
|
"defective_total" => $defective,
|
|
"sample_defective" => $samples,
|
|
"filter_url" => "https://weval-consulting.com/cartographie-screens.html (clic sur DEFECTUEUX)"
|
|
];
|
|
break;
|
|
|
|
|
|
case "smart_classify":
|
|
// Run smart classifier (re-probe with POST)
|
|
$log = "/tmp/smart_classify.log";
|
|
$cmd = "nohup python3 /var/www/html/api/screens-health-smart.py > $log 2>&1 &";
|
|
exec($cmd);
|
|
// If smart json already exists, return summary
|
|
$sf = "/var/www/html/api/screens-health-smart.json";
|
|
if (file_exists($sf)) {
|
|
$sj = json_decode(file_get_contents($sf), true);
|
|
$results = [
|
|
"status" => "smart_classifier_started_background",
|
|
"previous_smart_run" => $sj["generated_at"] ?? "none",
|
|
"smart_counts" => $sj["smart_counts"] ?? [],
|
|
"rechecked" => $sj["rechecked"] ?? 0,
|
|
"real_problems_count" => count($sj["real_problems"] ?? []),
|
|
"sample_real_problems" => array_slice($sj["real_problems"] ?? [], 0, 8),
|
|
"log" => $log
|
|
];
|
|
} else {
|
|
$results = ["status" => "smart_classifier_started_first_time", "log" => $log, "wait_seconds" => 30];
|
|
}
|
|
break;
|
|
|
|
|
|
case "find_watchdog":
|
|
$r = shell_exec("python3 /var/www/html/api/find-watchdog.py 2>&1 | head -c 5000");
|
|
$results = json_decode(trim($r), true) ?: ["raw"=>$r, "parse_error"=>true];
|
|
break;
|
|
case "smart_classify_safe":
|
|
$log = "/tmp/smart_safe.log";
|
|
exec("nohup python3 /var/www/html/api/screens-health-smart-safe.py > $log 2>&1 &");
|
|
$sf = "/var/www/html/api/screens-health-smart.json";
|
|
if (file_exists($sf)) {
|
|
$sj = json_decode(file_get_contents($sf), true);
|
|
$results = ["status"=>"safe_classifier_running_bg", "previous_run"=>$sj["generated_at"]??"none",
|
|
"smart_counts"=>$sj["smart_counts"]??[], "rechecked"=>$sj["rechecked"]??0,
|
|
"false_positives_count"=>count($sj["false_positives"]??[]),
|
|
"real_problems_count"=>count($sj["real_problems"]??[]),
|
|
"log"=>$log, "workers"=>"5 (safe)"];
|
|
} else {
|
|
$results = ["status"=>"safe_classifier_first_run","wait_seconds"=>120, "log"=>$log];
|
|
}
|
|
break;
|
|
case "investigate_500":
|
|
$r = shell_exec("python3 /var/www/html/api/investigate-500.py 2>&1 | head -c 5000");
|
|
$results = json_decode(trim($r), true) ?: ["raw"=>$r, "parse_error"=>true];
|
|
break;
|
|
case "reclassify_health":
|
|
$r = shell_exec("sudo python3 /var/www/html/api/reclassify-health.py 2>&1 | head -c 3000");
|
|
$results = json_decode(trim($r), true) ?: ["raw"=>$r, "parse_error"=>true];
|
|
break;
|
|
|
|
default:
|
|
$results=["actions"=>["test_providers","webchat","nonreg","reconcile","git_push","ethica","docker_list","git_log","disk","ports","crons","services","playwright_scan","paperclip","slack"]];
|
|
}
|
|
echo json_encode(["ok"=>true,"action"=>$action,"results"=>$results]);
|