patchcenter/app/templates/safe_patching.html
Khalid MOUTAOUAKIL 49d5658475 Safe Patching wizard, SSE terminal, SSH password fallback, Qualys VMDR testé
Safe Patching Quick Win:
- Wizard 4 steps: Prérequis → Snapshot → Exécution → Post-patch
- Step 1: vérif SSH/disque/satellite par branche, exclure les KO
- Step 2: snapshot vSphere VMs
- Step 3: commande yum éditable, lancer hprod puis prod (100% requis)
- Step 4: vérification post-patch, export CSV
- Terminal SSE live (Server-Sent Events) avec couleurs
- Exclusion serveurs par checkbox dans chaque branche
- Label auto Quick Win SXX YYYY

SSH:
- Fallback password depuis settings si clé SSH absente
- Détection auto root (id -u) → pas de sudo si déjà root
- Testé sur VM doli CentOS 7 (10.0.2.4)

Qualys VMDR:
- API 2.0 testée et fonctionnelle avec compte sanef-ae
- Knowledge Base (CVE/QID/packages) accessible
- Host Detections (vulns par host) accessible
- Migration vers API 4.0 à prévoir (EOL dans 85 jours)

Qualys Agent installé sur doli (activation perso qg2)

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

80 lines
4.3 KiB
HTML

{% extends 'base.html' %}
{% block title %}Safe Patching{% endblock %}
{% block content %}
<h2 class="text-xl font-bold text-cyber-accent mb-4">Safe Patching — Quick Win</h2>
<p class="text-xs text-gray-500 mb-4">Patching sans interruption de service : exclut tout ce qui nécessite un reboot ou un restart de service.</p>
{% if msg %}
<div class="mb-3 p-2 rounded text-sm bg-red-900/30 text-cyber-red">
{% if msg == 'error' %}Erreur à la création (semaine déjà existante ?).{% endif %}
</div>
{% endif %}
<!-- Campagnes Quick Win existantes -->
{% if campaigns %}
<div class="space-y-2 mb-6">
{% for c in campaigns %}
<a href="/safe-patching/{{ c.id }}" class="card p-4 flex items-center justify-between hover:border-cyber-accent/50 block">
<div class="flex items-center gap-4">
<span class="font-bold text-cyber-accent">{{ c.week_code }}</span>
<span class="text-sm text-gray-400">{{ c.label }}</span>
<span class="badge badge-yellow">quickwin</span>
<span class="badge {% if c.status == 'draft' %}badge-gray{% elif c.status == 'in_progress' %}badge-yellow{% elif c.status == 'completed' %}badge-green{% else %}badge-red{% endif %}">{{ c.status }}</span>
</div>
<div class="flex gap-2 text-xs">
<span class="px-2 py-0.5 rounded bg-gray-800 text-gray-400">{{ c.session_count }} srv</span>
<span class="px-2 py-0.5 rounded bg-green-900/30 text-cyber-green">{{ c.patched_count }} ok</span>
</div>
</a>
{% endfor %}
</div>
{% endif %}
<!-- Créer Quick Win -->
{% if can_create %}
<div x-data="{ show: false }" class="card p-5">
<div class="flex justify-between items-center">
<h3 class="text-sm font-bold text-cyber-accent">Nouvelle campagne Quick Win</h3>
<button @click="show = !show" class="btn-sm bg-cyber-border text-cyber-accent" x-text="show ? 'Masquer' : 'Créer'"></button>
</div>
<div x-show="show" class="mt-4">
<form method="POST" action="/safe-patching/create" class="space-y-3">
<div class="grid grid-cols-3 gap-3">
<div>
<label class="text-xs text-gray-500">Label</label>
<input type="text" name="label" id="qw-label" value="Quick Win S{{ '%02d' % current_week }} {{ current_year }}" class="w-full">
</div>
<div>
<label class="text-xs text-gray-500">Semaine</label>
<input type="number" name="week_number" id="qw-week" value="{{ current_week }}" min="1" max="53" class="w-full" required
onchange="document.getElementById('qw-label').value = 'Quick Win S' + String(this.value).padStart(2,'0') + ' ' + document.getElementById('qw-year').value">
</div>
<div>
<label class="text-xs text-gray-500">Année</label>
<input type="number" name="year" id="qw-year" value="{{ current_year }}" class="w-full" required
onchange="document.getElementById('qw-label').value = 'Quick Win S' + String(document.getElementById('qw-week').value).padStart(2,'0') + ' ' + this.value">
</div>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="text-xs text-gray-500">Opérateur lead</label>
<select name="lead_id" class="w-full" required>
{% for o in operators %}<option value="{{ o.id }}">{{ o.display_name }}</option>{% endfor %}
</select>
</div>
<div>
<label class="text-xs text-gray-500">Assistant (optionnel)</label>
<select name="assistant_id" class="w-full">
<option value="">— Pas d'assistant —</option>
{% for o in operators %}<option value="{{ o.id }}">{{ o.display_name }}</option>{% endfor %}
</select>
</div>
</div>
<p class="text-xs text-gray-600">Tous les serveurs Linux en production (secops) seront inclus. Hors-prod patché en premier (J), prod le lendemain (J+1).</p>
<button type="submit" class="btn-primary px-6 py-2 text-sm">Créer la campagne Quick Win</button>
</form>
</div>
</div>
{% endif %}
{% endblock %}