patchcenter/app/templates/audit_realtime_results.html
Khalid MOUTAOUAKIL 8e62b1fb11 Qualys complet, contacts, audit refactoré, bulk serveurs
Qualys:
- Recherche API temps réel + cache 24h base locale
- Tags: liste DYN/STAT, mapping V3 (DOM-*, TYP-*, APP-*), nb assets cliquable
- CRUD tags: créer STAT, supprimer, resync API
- Détail asset: infos + décodage nomenclature V3 + tags assignés
- Ajout/retrait tag unitaire avec autocomplete filtrable
- Bulk add/remove tag en masse avec dropdown filtrable
- Tags retirer: charge dynamiquement les STAT assignés aux assets sélectionnés
- Resync assets sélectionnés + retour même recherche

Contacts:
- 50 contacts importés avec 93 scopes (domaine/app/serveur/zone par env)
- 13 rôles (responsable_domaine, ra_prod, ra_recette, referent_technique...)
- Recherche par nom/email/serveur (affiche contacts liés)
- CRUD complet: éditer, scopes, activer/désactiver, supprimer
- Serveurs liés calculés dynamiquement depuis les scopes

Audit:
- Restructuré: Audit général + sous-menu Spécifique
- Dernier audit global affiché avec date
- Lancer audit général avec exclusions (domaines/zones) et parallélisme
- KPIs Qualys KO et S1 KO cliquables
- Export CSV

Serveurs:
- Actions groupées bulk (domaine, env, tier, état, owner, licence)
- Dashboard: KPI EOL ajouté
- Filtre état: EOL + en décommissionnement ajoutés
- 138 serveurs EOL importés depuis Qualys (owner=na, hors périmètre)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:47:26 +02:00

121 lines
6.1 KiB
HTML

{% extends 'base.html' %}
{% block title %}Résultats audit temps réel{% endblock %}
{% block content %}
<div class="flex justify-between items-center mb-4">
<div>
<a href="/audit" class="text-xs text-gray-500 hover:text-gray-300">← Retour audit</a>
<h2 class="text-xl font-bold text-cyber-accent">Résultats audit temps réel</h2>
</div>
<div class="flex gap-2">
<form method="POST" action="/audit/realtime/save">
<button class="btn-primary px-4 py-2 text-sm" onclick="return confirm('Mettre à jour la base avec ces résultats ?')">Mettre à jour la base</button>
</form>
</div>
</div>
<!-- Stats -->
<div class="grid grid-cols-3 gap-3 mb-4">
<div class="card p-3 text-center">
<div class="text-2xl font-bold text-cyber-accent">{{ total }}</div>
<div class="text-xs text-gray-500">Total</div>
</div>
<div class="card p-3 text-center">
<div class="text-2xl font-bold text-cyber-green">{{ ok }}</div>
<div class="text-xs text-gray-500">Connectés</div>
</div>
<div class="card p-3 text-center">
<div class="text-2xl font-bold text-cyber-red">{{ failed }}</div>
<div class="text-xs text-gray-500">Échoués</div>
</div>
</div>
<!-- Résultats -->
<div class="card overflow-x-auto">
<table class="w-full table-cyber text-xs">
<thead><tr>
<th class="text-left p-2">Hostname</th>
<th class="p-2">Statut</th>
<th class="p-2">FQDN résolu</th>
<th class="p-2">OS</th>
<th class="p-2">Kernel</th>
<th class="p-2">Disque</th>
<th class="p-2">Qualys</th>
<th class="p-2">S1</th>
<th class="p-2">Services</th>
<th class="p-2">Sans auto</th>
<th class="p-2">BDD</th>
<th class="p-2">Containers</th>
</tr></thead>
<tbody>
{% for r in results %}
<tr class="{% if r.status != 'OK' %}bg-red-900/10{% elif r.disk_alert %}bg-yellow-900/10{% endif %}">
<td class="p-2 font-mono text-cyber-accent">{{ r.hostname }}</td>
<td class="p-2 text-center"><span class="badge {% if r.status == 'OK' %}badge-green{% else %}badge-red{% endif %}">{{ r.status[:12] }}</span></td>
<td class="p-2 text-center text-gray-400">{{ r.resolved_fqdn or '-' }}</td>
<td class="p-2 text-center text-gray-400" title="{{ r.os_release or '' }}">{{ (r.os_release or '-')[:25] }}</td>
<td class="p-2 text-center text-gray-400">{{ (r.kernel or '-')[:20] }}</td>
<td class="p-2 text-center">
{% if r.disk_alert %}<span class="badge badge-red">ALERTE</span>
{% elif r.status == 'OK' %}<span class="text-cyber-green">OK</span>
{% else %}-{% endif %}
</td>
<td class="p-2 text-center">{% if r.qualys_active %}<span class="text-cyber-green">OK</span>{% elif r.status == 'OK' %}<span class="text-cyber-red">KO</span>{% else %}-{% endif %}</td>
<td class="p-2 text-center">{% if r.sentinelone_active %}<span class="text-cyber-green">OK</span>{% elif r.status == 'OK' %}<span class="text-cyber-red">KO</span>{% else %}-{% endif %}</td>
<td class="p-2 text-center text-gray-400" title="{{ r.services_running or '' }}">{% if r.services_running %}{{ r.services_running.split('\n')|length }}{% else %}-{% endif %}</td>
<td class="p-2 text-center">{% if r.running_not_enabled and r.running_not_enabled != 'none' %}<span class="text-cyber-yellow">{{ r.running_not_enabled.split('\n')|length }}</span>{% else %}-{% endif %}</td>
<td class="p-2 text-center text-gray-400">{{ (r.db_detect or '-')[:15] }}</td>
<td class="p-2 text-center text-gray-400">{{ (r.containers or '-')[:20] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Détail par serveur -->
{% for r in results %}
{% if r.status == 'OK' %}
<details class="card mt-2">
<summary class="p-3 cursor-pointer hover:bg-cyber-border/20 font-mono text-sm text-cyber-accent">{{ r.hostname }} — {{ r.resolved_fqdn or '' }}</summary>
<div class="p-4 grid grid-cols-2 gap-4 text-xs">
<div>
<h4 class="text-cyber-accent font-bold mb-1">Espace disque</h4>
<pre class="bg-cyber-bg p-2 rounded text-gray-400 overflow-x-auto">{{ r.disk_space or 'N/A' }}</pre>
</div>
<div>
<h4 class="text-cyber-accent font-bold mb-1">Applications</h4>
<pre class="bg-cyber-bg p-2 rounded text-gray-400 overflow-x-auto">{{ r.apps_installed or 'N/A' }}</pre>
</div>
<div>
<h4 class="text-cyber-accent font-bold mb-1">Services actifs</h4>
<pre class="bg-cyber-bg p-2 rounded text-gray-400 overflow-x-auto" style="max-height:150px">{{ r.services_running or 'N/A' }}</pre>
</div>
<div>
<h4 class="text-cyber-yellow font-bold mb-1">Sans auto-start</h4>
<pre class="bg-cyber-bg p-2 rounded text-cyber-yellow overflow-x-auto">{{ r.running_not_enabled or 'Aucun' }}</pre>
</div>
<div>
<h4 class="text-cyber-accent font-bold mb-1">Ports</h4>
<pre class="bg-cyber-bg p-2 rounded text-gray-400 overflow-x-auto">{{ r.listening_ports or 'N/A' }}</pre>
</div>
<div>
<h4 class="text-cyber-accent font-bold mb-1">Agents</h4>
<pre class="bg-cyber-bg p-2 rounded text-gray-400">{{ r.agents or 'N/A' }}</pre>
</div>
{% if r.containers and r.containers != 'none' %}
<div class="col-span-2">
<h4 class="text-cyber-accent font-bold mb-1">Containers</h4>
<pre class="bg-cyber-bg p-2 rounded text-gray-400">{{ r.containers }}</pre>
</div>
{% endif %}
{% if r.failed_services and r.failed_services != 'none' %}
<div class="col-span-2">
<h4 class="text-cyber-red font-bold mb-1">Services en échec</h4>
<pre class="bg-red-900/20 p-2 rounded text-cyber-red">{{ r.failed_services }}</pre>
</div>
{% endif %}
</div>
</details>
{% endif %}
{% endfor %}
{% endblock %}