Files
html/api/wtp-udock-coverage.php
Opus Wire 0d49e735ca
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
fix(wtp-udock-public-doctrine): URGENT remove dock from 38 public pages
DOCTRINE CRITIQUE: WTP_UDOCK_V1 jamais sur pages publiques (vitrine weval-consulting.com)
User signaled dock visible on homepage (index.html) - violation doctrine

Fix:
- 38 pages publiques nettoyees (regex multi-pattern + GOLD backup chacune)
  * Homepage: index.html
  * Landings: landing-industrie, landing-ocp, landing-banque, landing-retail
  * SEO FR: consulting-*, crm-pharma, cyber, digitalisation, erp-pme, finance,
    formation, marketing, offshore, recrutement, transformation, achats, bpm, cloud
  * Corporate: contact, solutions, pricing, cgu, case-studies, use-cases,
    pitch, register, booking, apps, living-proof, faq-techniques/knowledge-base,
    ecosysteme-ia-maroc, candidates-pool, wepredict, ia-france-consulting

- Script Python sudo avec chattr mgmt + regex 3 patterns
- 38 GOLD backups /opt/wevads/vault/gold_*_REMOVEDOCK_*.html
- Syntax OK partout

Endpoint /api/wtp-udock-coverage.php:
- Added $PUBLIC_EXEMPT array (38 pages)
- Skip public pages from count (same pattern que SEO_EXEMPT)
- Coverage now reports pages INTERNES uniquement: 276/276 = 100 pct

Doctrine documentee: WTP_UDOCK uniquement pour outils internes
(admin, WEVIA Master, Orch, WTP platform, dashboards, monitors).
Pages user-facing externes (SEO, vitrine, landings) = JAMAIS de dock.

Zero regression · Zero ecrasement · GOLD backup integral
2026-04-21 14:33:41 +02:00

96 lines
4.8 KiB
PHP

<?php
/* ═══════════════════════════════════════════════════════════════════
WTP UDOCK COVERAGE ENDPOINT · Opus 21-avr tour35
Scans /var/www/html/*.html and returns JSON coverage stats
Usage: GET /api/wtp-udock-coverage.php [?detail=1]
═══════════════════════════════════════════════════════════════════ */
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: public, max-age=60');
header('X-WTP-UDOCK-V', '1');
$DIR = '/var/www/html';
$NAV_PATTERNS = ['wtp-unified-dock.js', 'opus-xlinks', 'wtp-sidebar', 'v130-xnav'];
$EXCLUDE = ['.bak', 'gold_'];
// SEO_VERIFICATION_EXEMPT - files that must NOT have dock (SEO verification tokens)
$SEO_EXEMPT = ['googlecba1a80ba979325c.html', 'google-site-verification.html'];
// PUBLIC_EXEMPT - pages publiques (vitrine weval-consulting.com)
// Doctrine: le dock WTP_UDOCK est UNIQUEMENT pour les pages internes/outils
// JAMAIS sur pages user-facing externes (SEO landings, homepage, contact, etc.)
$PUBLIC_EXEMPT = ['index.html', 'contact.html', 'solutions.html', 'pricing.html', 'landing-industrie.html', 'landing-ocp.html', 'landing-banque.html', 'landing-retail.html', 'case-studies.html', 'use-cases.html', 'pitch.html', 'register.html', 'booking.html', 'apps.html', 'cgu.html', 'living-proof.html', 'ecosysteme-ia-maroc.html', 'intelligence-artificielle-france-consulting.html', 'consulting-intelligence-artificielle-maroc.html', 'consulting-pharma-supply-chain.html', 'consulting-sap-erp-vistex-maroc.html', 'crm-pharma-marketing-pharmaceutique.html', 'cybersécurité-maroc-audit-conseil.html', 'digitalisation-processus-gouvernance-it.html', 'erp-pme-eti-sap-odoo-sage.html', 'finance-controlling-sap-fico.html', 'formation-ia-sap-cloud-maroc.html', 'marketing-digital-maroc.html', 'offshore-nearshore-maroc-france-canada.html', 'recrutement-talent-it-maroc.html', 'transformation-digitale-consulting-france-international.html', 'achats-purchasing-sap-mm-procurement.html', 'bpm-automatisation-processus-métier.html', 'cloud-infrastructure-système-information.html', 'faq-techniques.html', 'faq-knowledge-base.html', 'candidates-pool.html', 'wepredict.html'];
$files = glob($DIR . '/*.html') ?: [];
$total = 0;
$covered = 0;
$by_pattern = array_fill_keys($NAV_PATTERNS, 0);
$uncovered = [];
$chattr_i_count = 0;
$detail = isset($_GET['detail']) && $_GET['detail'] === '1';
foreach ($files as $f) {
$name = basename($f);
$skip = false;
foreach ($EXCLUDE as $ex) { if (strpos($name, $ex) !== false) { $skip = true; break; } }
// SEO exempt: don't count these in total (they must stay minimal)
if (in_array($name, $SEO_EXEMPT)) { $skip = true; }
// Public pages exempt: doctrine "NAV JAMAIS sur pages vitrine publiques"
if (in_array($name, $PUBLIC_EXEMPT)) { $skip = true; }
if ($skip || strpos($name, '_') === 0) continue;
$total++;
$content = @file_get_contents($f);
if ($content === false) continue;
$has_nav = false;
foreach ($NAV_PATTERNS as $pat) {
if (strpos($content, $pat) !== false) {
$by_pattern[$pat]++;
$has_nav = true;
break; // count first matched pattern only (avoid double-count)
}
}
if ($has_nav) {
$covered++;
} else {
// Check if chattr+i
$is_immutable = false;
$lsattr_out = @shell_exec("lsattr " . escapeshellarg($f) . " 2>/dev/null");
if ($lsattr_out && preg_match('/^----i/', $lsattr_out)) {
$is_immutable = true;
$chattr_i_count++;
}
$size = @filesize($f);
$uncovered[] = [
'name' => $name,
'size' => $size,
'immutable' => $is_immutable,
'size_human' => $size ? round($size/1024, 1) . ' KB' : '?'
];
}
}
$response = [
'ts' => date('c'),
'source' => 'wtp-udock-coverage v1',
'total_pages' => $total,
'covered' => $covered,
'uncovered' => count($uncovered),
'coverage_pct' => $total > 0 ? round(100 * $covered / $total, 1) : 0,
'by_pattern' => [
'wtp-unified-dock.js' => $by_pattern['wtp-unified-dock.js'],
'opus-xlinks' => $by_pattern['opus-xlinks'],
'wtp-sidebar' => $by_pattern['wtp-sidebar'],
'v130-xnav' => $by_pattern['v130-xnav']
],
'immutable_blocked' => $chattr_i_count,
'target_100pct_remaining' => $total - $covered
];
if ($detail) {
// Sort uncovered by size desc, take top 30
usort($uncovered, function($a, $b) { return ($b['size'] ?? 0) - ($a['size'] ?? 0); });
$response['uncovered_top30'] = array_slice($uncovered, 0, 30);
}
echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);