# -*- coding: utf-8 -*-
"""Generate SANEF Qualys V3 - resume execution + points de vigilance.docx"""
from docx import Document
from docx.shared import Pt, RGBColor, Inches, Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH

doc = Document()

style = doc.styles['Normal']
style.font.name = 'Calibri'
style.font.size = Pt(10)

# ===== Cover =====
title = doc.add_heading('SANEF â€” Qualys Taxonomie V3', 0)
title.alignment = WD_ALIGN_PARAGRAPH.CENTER

sub = doc.add_paragraph()
sub.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = sub.add_run('RÃ©sumÃ© d\'exÃ©cution + points de vigilance')
r.font.size = Pt(14)
r.italic = True

meta = doc.add_paragraph()
meta.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = meta.add_run('Date : 22 avril 2026\nRÃ©dacteur : Khalid MOUTAOUAKIL â€” SECOPS\nVersion : 1.0')
r.font.size = Pt(11)

doc.add_paragraph()
doc.add_paragraph('_' * 80)
doc.add_paragraph()

# ===== 1. RÃ©sumÃ© =====
doc.add_heading('1. RÃ©sumÃ© de la session', level=1)
doc.add_paragraph(
    "Cette session a consistÃ© Ã  dÃ©ployer la taxonomie V3 des tags Qualys SANEF, "
    "dÃ©finie dans le document Â« Processus d'affectation des Tags Qualys â€” Nomenclature V3 Â». "
    "L'ensemble des rÃ¨gles a Ã©tÃ© crÃ©Ã© directement dans la console Qualys (module Asset Inventory) "
    "et appliquÃ© sur le parc actif (~3,22k assets sur 6,24k au total)."
)

doc.add_heading('1.1 Tags crÃ©Ã©s', level=2)
doc.add_paragraph('5 parents (containers organisationnels statiques) :', style='List Bullet')
for p in ['OS', 'EQT', 'ENV', 'POS', 'TAG']:
    doc.add_paragraph(p, style='List Bullet 2')

doc.add_paragraph('23 tags dynamiques (Asset Inventory rule engine) :', style='List Bullet')
for line in [
    'OS-LIN-SRV (729), OS-WIN-SRV (505), OS-WIN-WKS (~2056), OS-MAC (7), OS-ESX (2)',
    'EQT-VIR (956), EQT-SRV (307), EQT-SWI (72)',
    'ENV-PRD (~772), ENV-REC (~302), ENV-PPR (~76), ENV-TST (83), ENV-DEV (~21)',
    'POS-FL, POS-INF, POS-PEA, POS-TRA, POS-BI, POS-GES (counts variables, voir console)',
    'NOM-LEGACY (219) â€” KPI dette de conformitÃ© V3',
    'TAG-EMV (~34) â€” zone PCI-DSS',
    'TAG-OBS (~190+) â€” OS EOL liste explicite',
]:
    doc.add_paragraph(line, style='List Bullet 2')

doc.add_paragraph('Tags statiques (bulk SQATM) :', style='List Bullet')
for line in [
    'TAG-SED (10) â€” exposition directe Internet',
    'TAG-SEI (22) â€” exposition indirecte derriÃ¨re frontal',
    'TAG-ELS (vide) â€” extension de licence (exclusion EOL)',
    'TAG-DEC, TAG-INT, TAG-SIC, TAG-SIA â€” statiques manuels',
]:
    doc.add_paragraph(line, style='List Bullet 2')

doc.add_heading('1.2 DÃ©couvertes techniques majeures', level=2)
findings = [
    ("Limites QQL Tag rule engine",
     "Le moteur Asset Inventory pour la crÃ©ation de rÃ¨gles n'accepte que la syntaxe starts-with "
     "(asset.name:vp*). Les opÃ©rateurs CONTAINS (*X*) et les guillemets (\"X\") Ã©chouent. La clÃ© "
     "tags.name peut Ãªtre utilisÃ©e dans les recherches interactives mais PAS dans la crÃ©ation de "
     "rÃ¨gles dynamiques (l'API rejette le commit avec Â« Error while committing transaction Â»)."),
    ("FQDN .sanef.groupe non env-spÃ©cifique",
     "DÃ©couverte initialement supposÃ©e comme indicateur Production, le domaine AD interne "
     ".sanef.groupe est en rÃ©alitÃ© utilisÃ© par tous les serveurs SANEF (PRD, REC, PPR, TST, DEV). "
     "Utiliser comme filtre broad provoque des overlaps massifs entre tags ENV. Solution adoptÃ©e : "
     "scoper FQDN par pattern hostname prÃ©cis (ex : vmm*.sanef-int.adds pour les Win11 prod uniquement)."),
    ("Conflits de prÃ©fixes 5-char entre POS",
     "Plusieurs prÃ©fixes hostname appartiennent Ã  des domaines diffÃ©rents selon contexte applicatif "
     "(ex : vppea* = FL pour BOOST + PEA pour SVP). RÃ©solution par Ã©numÃ©ration 7-char spÃ©cifique "
     "(vppeaab* BOOST = FL, vppeaaa*/ar*/ae* SVP = PEA) et clauses NOT exclusives."),
    ("Zone DMZ multi-subnet",
     "La DMZ SANEF est segmentÃ©e en 15 sous-rÃ©seaux /24 diffÃ©rents. Pas de CIDR unique. "
     "Impossible de faire une rÃ¨gle dynamique simple par IP. Tagging actuel TAG-SED/SEI en static "
     "via SQATM bulk."),
    ("Tag built-in Qualys Â« Obsolete Â»",
     "Qualys maintient automatiquement un tag Â« Obsolete Â» basÃ© sur sa dÃ©tection EOL. ~190 assets "
     "SANEF sont taggÃ©s. Ce tag NE peut PAS Ãªtre rÃ©fÃ©rencÃ© dans une rÃ¨gle de tag custom (limitation "
     "Qualys). On utilise une liste OS explicite pour TAG-OBS."),
    ("Postes Superviseur PÃ©age (svp*) â€” exclusion ENV-TST et EQT-SRV",
     "Le prÃ©fixe sv* visait initialement les serveurs physiques de test (svboomcla2, etc.). "
     "DÃ©couverte : ~100 postes de travail Windows 11 (HP Elite Mini desktops SVP2xxxx + HP EliteBook "
     "SVP1xxxx) commencent aussi par svp* â€” ce sont des postes Superviseur PÃ©age, pas des serveurs. "
     "Sans exclusion explicite, ils Ã©taient ramassÃ©s par ENV-TST (~180 au lieu de 83) et "
     "potentiellement par EQT-SRV. Correction : ajout de Â« and not asset.name:svp* Â» sur les deux "
     "rÃ¨gles. ENV-TST passe Ã  83 assets, cohÃ©rent avec le pÃ©rimÃ¨tre attendu."),
]
for h, t in findings:
    p = doc.add_paragraph()
    p.add_run(h + ' : ').bold = True
    p.add_run(t)

# ===== 2. Points de vigilance =====
doc.add_page_break()
doc.add_heading('2. Points de vigilance', level=1)
doc.add_paragraph(
    "Les Ã©lÃ©ments suivants nÃ©cessitent une surveillance ou des actions futures pour maintenir "
    "la cohÃ©rence et l'exhaustivitÃ© de la taxonomie V3."
)

doc.add_heading("2.1 POS-DMZ â€” Ã  adapter une fois la DMZ normalisÃ©e", level=2)
doc.add_paragraph(
    "Statut actuel : pas de tag POS-DMZ crÃ©Ã©. La gestion DMZ est faite via TAG-SED (10 frontaux) "
    "et TAG-SEI (22 backends), tous statiques."
)
p = doc.add_paragraph()
p.add_run('ProblÃ¨me : ').bold = True
p.add_run(
    "la DMZ SANEF s'Ã©tend sur 15 sous-rÃ©seaux /24 diffÃ©rents (192.168.2/24, 192.168.20/24, "
    "192.168.31/24, 10.41.20/24, 10.42.30/24, 10.205.0/24, etc.). Aucun CIDR unique ne permet "
    "actuellement une rÃ¨gle dynamique simple."
)
p = doc.add_paragraph()
p.add_run('Action requise : ').bold = True
p.add_run(
    "demander Ã  l'Ã©quipe rÃ©seau SANEF de fournir soit (a) le CIDR DMZ consolidÃ© (si rÃ©organisation "
    "envisagÃ©e), soit (b) une nomenclature IP DMZ-spÃ©cifique (par exemple un /20 dÃ©diÃ©). Une fois "
    "obtenu, basculer TAG-SED et TAG-SEI en rÃ¨gles dynamiques basÃ©es sur "
    "asset.interface:(address: <CIDR>)."
)
p = doc.add_paragraph()
p.add_run('Alternative : ').bold = True
p.add_run(
    "si la DMZ reste multi-subnet, garder TAG-SED/TAG-SEI en static. Documenter dans la procÃ©dure "
    "patcheur SECOPS : tout nouveau serveur en zone DMZ doit Ãªtre taggÃ© manuellement via SQATM "
    "selon son rÃ´le (frontal = SED, backend = SEI)."
)
p = doc.add_paragraph()
p.add_run('Plages publiques connues pour TAG-SED dynamique : ').bold = True
p.add_run("83.68.96.0/24 (Juniper firewalls), 83.68.99.0/24 (F5 BIG-IP). Ces plages peuvent Ãªtre "
         "utilisÃ©es pour basculer TAG-SED en dynamique partiel dÃ¨s aujourd'hui :")
doc.add_paragraph(
    "asset.interface:(address: 83.68.96.0/24) or asset.interface:(address: 83.68.99.0/24)",
    style='Intense Quote'
)

doc.add_heading('2.2 TAG-ELS â€” saisie manuelle au cas par cas', level=2)
doc.add_paragraph(
    "TAG-ELS (Extended Life License) identifie les serveurs sous contrat de support sÃ©curitÃ© "
    "Ã©tendu payÃ© (Microsoft ESU, Red Hat ELS, etc.). Ces serveurs ne doivent PAS Ãªtre considÃ©rÃ©s "
    "comme TAG-OBS car ils reÃ§oivent encore des correctifs de sÃ©curitÃ©."
)
p = doc.add_paragraph()
p.add_run('Statut actuel : ').bold = True
p.add_run("TAG-ELS crÃ©Ã© (statique, vide). Aucun asset tagguÃ©.")
p = doc.add_paragraph()
p.add_run('Action requise : ').bold = True
p.add_run(
    "lister les serveurs SANEF sous contrats ELS (vÃ©rifier avec la DSI / responsables applicatifs / "
    "renouvellements de licence Microsoft/RedHat). Saisir manuellement via SQATM avec le tag TAG-ELS "
    "sur chaque asset concernÃ©."
)
p = doc.add_paragraph()
p.add_run('Workflow opÃ©rationnel : ').bold = True
p.add_run(
    "lorsqu'un asset est ajoutÃ© Ã  TAG-ELS, retirer manuellement TAG-OBS si prÃ©sent (les deux tags "
    "ne doivent pas coexister). Limitation : la chaÃ®ne de tag (tag rule excluant un autre tag) "
    "n'est pas supportÃ©e par Qualys, donc le double-tagging doit Ãªtre nettoyÃ© manuellement."
)
p = doc.add_paragraph()
p.add_run('Reporting recommandÃ© : ').bold = True
p.add_run("crÃ©er une Â« Saved Search Â» Qualys pour le reporting opÃ©rationnel :")
doc.add_paragraph('tags.name:"TAG-OBS" and not tags.name:"TAG-ELS"', style='Intense Quote')
doc.add_paragraph("Cette query, valide en recherche interactive, donne les Â« vrais EOL Ã  patcher Â» "
                 "et est utilisable dans les dashboards.")

doc.add_heading("2.3 TAG-OBS â€” adapter la liste OS quand un nouvel OS devient obsolÃ¨te", level=2)
doc.add_paragraph(
    "TAG-OBS est dÃ©fini en Option A (liste OS explicite) car la chaÃ®ne sur le tag built-in Qualys "
    "Â« Obsolete Â» n'est pas supportÃ©e. La liste actuelle couvre 15 OS / familles."
)
p = doc.add_paragraph()
p.add_run('Liste OS actuelle (Ã  maintenir) : ').bold = True
oses = [
    "Windows XP (EOL 2014-04-08)",
    "Windows Server 2003 (EOL 2015-07-14)",
    "Windows Server 2008 / 2008 R2 (EOL 2020-01-14)",
    "Windows Server 2012 / 2012 R2 (EOL 2023-10-10)",
    "Windows 7 (EOL 2020-01-14)",
    "Red Hat Enterprise Linux 5 (EOL 2017-03-31)",
    "Red Hat Enterprise Linux 6 (EOL 2020-11-30)",
    "CentOS 5 / 6 / 7 (CentOS 7 EOL 2024-06-30)",
    "Ubuntu 14.04 / 16.04 / 18.04 (EOL 2019/2021/2023)",
    "Debian 8 / 9 (EOL 2020/2022)",
]
for o in oses:
    doc.add_paragraph(o, style='List Bullet')

p = doc.add_paragraph()
p.add_run('Surveillance recommandÃ©e : ').bold = True
p.add_run(
    "vÃ©rifier au moins une fois par an (idÃ©alement en dÃ©but d'annÃ©e) si de nouveaux OS sont passÃ©s EOL. "
    "Sources fiables : endoflife.date, sites Ã©diteurs (microsoft.com/lifecycle, redhat.com/support, "
    "ubuntu.com/about/release-cycle)."
)

p = doc.add_paragraph()
p.add_run('OS Ã  surveiller dans les 12-24 mois : ').bold = True
upcoming = [
    "RHEL 7 â€” EOL 2024-06-30 (dÃ©jÃ  Ã  inclure si pas dÃ©jÃ  fait)",
    "Windows Server 2012 R2 ESU â€” EOL 2026-10-13",
    "Ubuntu 20.04 â€” EOL 2025-04 standard, ESM jusqu'Ã  2030",
    "Debian 10 â€” EOL 2024-06-30 standard, LTS jusqu'Ã  2024-06",
    "CentOS Stream 8 â€” EOL 2024-05-31",
]
for o in upcoming:
    doc.add_paragraph(o, style='List Bullet')

p = doc.add_paragraph()
p.add_run('ProcÃ©dure de mise Ã  jour TAG-OBS : ').bold = True
doc.add_paragraph("Ouvrir Qualys Console > AssetView > Configuration > Tags > TAG-OBS > Edit", style='List Number')
doc.add_paragraph('Ajouter la nouvelle clause OR Ã  la query : or operatingSystem:"<nouvel OS>"', style='List Number')
doc.add_paragraph("Cliquer Test pour vÃ©rifier le count", style='List Number')
doc.add_paragraph("Save", style='List Number')
doc.add_paragraph("Mettre Ã  jour le fichier de rÃ©fÃ©rence SANEF_Qualys_Tags_V3_RuleTypes_v2.xlsx", style='List Number')

doc.add_heading("2.4 MÃ©canisme natif Qualys Â« Obsolete Â» (Ã  connaÃ®tre)", level=2)
doc.add_paragraph(
    "Qualys propose un tag systÃ¨me Â« Obsolete Â» auto-appliquÃ© Ã  partir d'une base de connaissance "
    "interne sur les fins de support OS. Ce tag est maintenu par Qualys (pas par SANEF), s'applique "
    "automatiquement aux assets quand leur OS bascule EOL."
)
p = doc.add_paragraph()
p.add_run("Couverture observÃ©e dans le parc SANEF : ").bold = True
p.add_run("~190 assets (181 dans l'export AssetView et 180 dans Cloud Agent au 22 avril 2026).")

p = doc.add_paragraph()
p.add_run("Pourquoi ne pas utiliser uniquement ce tag : ").bold = True
p.add_run(
    "(1) il n'est PAS rÃ©fÃ©renÃ§able dans une rÃ¨gle de tag dynamique custom (limitation Qualys "
    "confirmÃ©e), donc impossible de crÃ©er un TAG-OBS = mirror du tag Qualys ; "
    "(2) il n'inclut pas toujours toutes les variantes EOL (parfois dÃ©calage temporel ou critÃ¨res "
    "diffÃ©rents) ; "
    "(3) il ne permet pas l'exclusion ELS via rÃ¨gle."
)
p = doc.add_paragraph()
p.add_run("Comment l'utiliser malgrÃ© ses limites : ").bold = True
p.add_run(
    "via les Saved Searches dans la console Qualys. Exemple de query Ã  sauvegarder pour le reporting :"
)
doc.add_paragraph('tags.name:"Obsolete" and not tags.name:"TAG-ELS"', style='Intense Quote')
p = doc.add_paragraph()
p.add_run("Comparaison TAG-OBS (Option A) vs Obsolete built-in : ").bold = True
p.add_run(
    "TAG-OBS = liste explicite contrÃ´lÃ©e par SECOPS, plus large potentiellement, mais nÃ©cessite "
    "maintenance. Obsolete built-in = auto-update Qualys, sans maintenance, mais sans contrÃ´le SANEF "
    "et non chaÃ®nable. La meilleure approche est de conserver les deux et de les utiliser en croisant "
    "leur intersection."
)

# ===== 3. Suite Ã  faire =====
doc.add_page_break()
doc.add_heading('3. Suite Ã  faire (TODO)', level=1)
todos = [
    ("Bulk SQATM TAG-SED, TAG-SEI",
     "AppliquÃ© aujourd'hui via SQATM (10 SED, 22 SEI). VÃ©rifier Ã  la prochaine revue qu'aucun nouveau "
     "asset DMZ n'a Ã©tÃ© oubliÃ©."),
    ("RÃ©cupÃ©rer CIDR DMZ auprÃ¨s Ã©quipe rÃ©seau",
     "Pour basculer TAG-SED/TAG-SEI en dynamique IP-based. Voir section 2.1."),
    ("Saisir TAG-ELS sur les serveurs concernÃ©s",
     "Inventaire des contrats ELS Ã  faire avec la DSI. Voir section 2.2."),
    ("Nettoyer tags legacy concurrents dans Qualys",
     "Plusieurs tags concurrents dÃ©tectÃ©s dans les exports : TAG-SRVEXPOSEINTERNET, DMZ, SED, "
     "ZONE-DMZ. DÃ©cision Ã  prendre : garder en parallÃ¨le, supprimer ou consolider sur la nomenclature V3."),
    ("Documenter procÃ©dure SECOPS pour nouveaux serveurs",
     "ProcÃ©dure Ã  intÃ©grer dans le wiki DokuWiki SANEF (page infra:sanef_utiles:sanef_utiles:qualys_tagv3) : "
     "tout nouveau serveur SANEF doit Ãªtre taggÃ© selon V3 dans les 48h aprÃ¨s scan Qualys initial."),
    ("Dashboard Qualys Â« ConformitÃ© V3 Â»",
     "Construire un dashboard avec : count NOM-LEGACY (KPI dette renommage), count TAG-OBS (hors ELS), "
     "% serveurs avec OS-* + ENV-* + POS-* + EQT-* tags prÃ©sents (couverture V3)."),
    ("Surveillance annuelle TAG-OBS",
     "RevÃ©rifier la liste OS EOL en janvier 2027 et ajouter les nouveaux OS passÃ©s EOL. Voir 2.3."),
]
for title_, desc in todos:
    p = doc.add_paragraph(style='List Bullet')
    p.add_run(title_).bold = True
    p.add_run(' : ' + desc)

doc.add_paragraph()
doc.add_paragraph('_' * 80)
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
r = p.add_run("SANEF DSI / SÃ©curitÃ© OpÃ©rationnelle â€” Plan d'action Qualys V3")
r.italic = True
r.font.size = Pt(9)

out = r"C:\Claude\sanef\QL\docs\SANEF_Qualys_V3_Resume_Vigilance.docx"
doc.save(out)
print("Saved:", out)
import os
print("Size:", os.path.getsize(out), "bytes")
