Dashboard: KPIs DMZ + patching 2026 depuis patch_history
- Stats DMZ (cliquable vers filtre zone) - Patched 2026, never patched, last week (depuis patch_history Excel) - Couverture patching = patched / patchable - KPIs cards cliquables (lien vers /servers filtre pre-applique) - Fix alias stats.eol -> stats.obsolete
This commit is contained in:
parent
ec82a7cd1e
commit
6ec1c4575d
@ -28,6 +28,27 @@ async def dashboard(request: Request, db=Depends(get_db)):
|
||||
stats["qualys_active"] = db.execute(text("SELECT COUNT(*) FROM qualys_assets WHERE agent_status ILIKE '%active%' AND agent_status NOT ILIKE '%inactive%'")).scalar()
|
||||
stats["qualys_inactive"] = db.execute(text("SELECT COUNT(*) FROM qualys_assets WHERE agent_status ILIKE '%inactive%'")).scalar()
|
||||
stats["qualys_no_agent"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE etat='Production' AND NOT EXISTS (SELECT 1 FROM qualys_assets qa WHERE LOWER(qa.hostname) = LOWER(servers.hostname))")).scalar()
|
||||
# Alias : template utilise stats.eol
|
||||
stats["eol"] = stats["obsolete"]
|
||||
# Zone DMZ
|
||||
stats["dmz"] = db.execute(text("SELECT COUNT(*) FROM servers WHERE zone_id = (SELECT id FROM zones WHERE is_dmz=true LIMIT 1)")).scalar()
|
||||
# Patching depuis patch_history (Excel 2026)
|
||||
stats["patched_history_2026"] = db.execute(text(
|
||||
"SELECT COUNT(DISTINCT server_id) FROM patch_history WHERE EXTRACT(YEAR FROM date_patch)=2026"
|
||||
)).scalar()
|
||||
stats["patch_events_2026"] = db.execute(text(
|
||||
"SELECT COUNT(*) FROM patch_history WHERE EXTRACT(YEAR FROM date_patch)=2026"
|
||||
)).scalar()
|
||||
stats["never_patched_2026"] = db.execute(text("""
|
||||
SELECT COUNT(*) FROM servers s
|
||||
WHERE s.etat='Production' AND s.patch_os_owner='secops'
|
||||
AND NOT EXISTS (SELECT 1 FROM patch_history ph
|
||||
WHERE ph.server_id=s.id AND EXTRACT(YEAR FROM ph.date_patch)=2026)
|
||||
""")).scalar()
|
||||
# Semaine la plus recente
|
||||
stats["last_patch_week"] = db.execute(text(
|
||||
"SELECT MAX(TO_CHAR(date_patch, 'IW')) FROM patch_history WHERE EXTRACT(YEAR FROM date_patch)=2026"
|
||||
)).scalar()
|
||||
|
||||
# Par domaine
|
||||
domains = db.execute(text("""
|
||||
|
||||
@ -4,15 +4,26 @@
|
||||
<h2 class="text-xl font-bold text-cyber-accent mb-4">Dashboard</h2>
|
||||
|
||||
<!-- KPIs generaux -->
|
||||
<div style="display:flex;flex-wrap:nowrap;gap:8px;margin-bottom:16px;">
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-accent">{{ stats.total_servers }}</div><div class="text-xs text-gray-500">Serveurs</div></div>
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-green">{{ stats.patchable }}</div><div class="text-xs text-gray-500">Patchables SecOps</div></div>
|
||||
<div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px;">
|
||||
<a href="/servers" class="card p-3 text-center hover:bg-cyber-hover" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-accent">{{ stats.total_servers }}</div><div class="text-xs text-gray-500">Serveurs</div></a>
|
||||
<a href="/servers?owner=secops&etat=Production" class="card p-3 text-center hover:bg-cyber-hover" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-green">{{ stats.patchable }}</div><div class="text-xs text-gray-500">Patchables SecOps</div></a>
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold text-white">{{ stats.linux }} / {{ stats.windows }}</div><div class="text-xs text-gray-500">Linux / Windows</div></div>
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-green">{{ stats.qualys_active }}</div><div class="text-xs text-gray-500">Agents actifs</div></div>
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold {% if stats.qualys_no_agent > 0 %}text-cyber-red{% else %}text-cyber-green{% endif %}">{{ stats.qualys_no_agent }}</div><div class="text-xs text-gray-500">Sans agent</div></div>
|
||||
<a href="/servers?zone=DMZ" class="card p-3 text-center hover:bg-cyber-hover" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-red">{{ stats.dmz }}</div><div class="text-xs text-gray-500">DMZ</div></a>
|
||||
<a href="/qualys/agents" class="card p-3 text-center hover:bg-cyber-hover" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-green">{{ stats.qualys_active }}</div><div class="text-xs text-gray-500">Agents actifs</div></a>
|
||||
<a href="/qualys/agents" class="card p-3 text-center hover:bg-cyber-hover" style="flex:1;min-width:0"><div class="text-2xl font-bold {% if stats.qualys_no_agent > 0 %}text-cyber-red{% else %}text-cyber-green{% endif %}">{{ stats.qualys_no_agent }}</div><div class="text-xs text-gray-500">Sans agent</div></a>
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-red">{{ stats.eol }}</div><div class="text-xs text-gray-500">EOL</div></div>
|
||||
</div>
|
||||
|
||||
<!-- KPI Patching depuis patch_history (Excel Plan de Patching 2026) -->
|
||||
<div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px;">
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-green">{{ stats.patched_history_2026 }}</div><div class="text-xs text-gray-500">Serveurs patchés 2026</div></div>
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-accent">{{ stats.patch_events_2026 }}</div><div class="text-xs text-gray-500">Events patching 2026</div></div>
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold {% if stats.never_patched_2026 > 0 %}text-cyber-red{% else %}text-cyber-green{% endif %}">{{ stats.never_patched_2026 }}</div><div class="text-xs text-gray-500">Jamais patchés 2026 (prod)</div></div>
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold text-cyber-yellow">S{{ stats.last_patch_week or '-' }}</div><div class="text-xs text-gray-500">Dernière semaine</div></div>
|
||||
{% set pct_patched = (stats.patched_history_2026 / stats.patchable * 100)|int if stats.patchable > 0 else 0 %}
|
||||
<div class="card p-3 text-center" style="flex:1;min-width:0"><div class="text-2xl font-bold {% if pct_patched >= 80 %}text-cyber-green{% elif pct_patched >= 50 %}text-cyber-yellow{% else %}text-cyber-red{% endif %}">{{ pct_patched }}%</div><div class="text-xs text-gray-500">Couverture 2026</div></div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════ PATCHING 2026 ═══════ -->
|
||||
{% if patch_stats %}
|
||||
<div class="card p-4 mb-4">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user