Add gen_tags_v3_docx: genere un Word avec tableaux Tag V3/RuleType/Valeur/Couleur

This commit is contained in:
Pierre & Lumière 2026-04-15 10:56:30 +02:00
parent 52e859ba08
commit adc8d40df3

184
tools/gen_tags_v3_docx.py Normal file
View File

@ -0,0 +1,184 @@
"""Genere un fichier Word avec le tableau de correspondance Tag V3 -> Rule Type + QQL/Regex.
Usage:
python tools/gen_tags_v3_docx.py [chemin_sortie.docx]
"""
import sys
from pathlib import Path
try:
from docx import Document
from docx.shared import Pt, RGBColor, Inches, Cm
from docx.enum.table import WD_ALIGN_VERTICAL
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
except ImportError:
print("[ERR] pip install python-docx")
sys.exit(1)
TAGS = [
# (tag, rule_type, value, couleur)
("OS-LIN", "Operating System", "Linux", "#4CAF50"),
("OS-WIN", "Operating System", "Windows", "#2196F3"),
("OS-WIN-SRV", "Operating System", "Windows Server", "#1976D2"),
("OS-ESX", "Operating System", "ESXi", "#9C27B0"),
("ENV-PRD", "Asset Search", 'name: vp* or name: sp* or name: lp* or name: ls-*', "#F44336"),
("ENV-REC", "Asset Search", 'name: vr* or name: sr* or name: lr*', "#FF9800"),
("ENV-PPR", "Asset Search", 'name: vi* or name: si* or name: vo*', "#FFC107"),
("ENV-TST", "Asset Search", 'name: vv* or name: vt*', "#CDDC39"),
("ENV-DEV", "Asset Search", 'name: vd* or name: sd*', "#8BC34A"),
("EQT-VIR", "Asset Search", 'name: v*', "#00BCD4"),
("EQT-SRV", "Asset Search", 'name: l* or name: s*', "#03A9F4"),
("EQT-SWI", "Asset Search", 'name: n*', "#4DD0E1"),
("POS-FL", "Asset Search", 'name: "*bot*" or name: "*boo*" or name: "*boc*" or name: "*afl*" or name: "*sup*"', "#009688"),
("POS-INF", "Asset Search", 'name: "*dsi*" or name: "*cyb*" or name: "*iad*" or name: "*bur*" or name: "*ecm*" or name: "*log*" or name: "*vid*" or name: "*ges*" or name: "*mon*"', "#3F51B5"),
("POS-PEA", "Asset Search", 'name: "*pea*" or name: "*osa*" or name: "*svp*" or name: "*adv*" or name: "*rpa*" or name: "*rpn*" or name: "ls-*"', "#673AB7"),
("POS-TRA", "Asset Search", 'name: "*ame*" or name: "*tra*" or name: "*dai*" or name: "*pat*" or name: "*rau*" or name: "*dep*" or name: "*exp*" or name: "*sig*" or name: "*air*"', "#E91E63"),
("POS-BI", "Asset Search", 'name: "*dec*" or name: "*sas*" or name: "*bip*" or name: "*apt*" or name: "*pbi*" or name: "*rep*"', "#FF5722"),
("POS-GES", "Asset Search", 'name: "*int*" or name: "*agt*" or name: "*pin*" or name: "*ech*"', "#795548"),
("POS-DMZ", "Asset Search", 'name: "*ssi*"', "#607D8B"),
("TAG-OBS", "Operating System", r"Windows Server 2008|Windows Server 2012|CentOS release 6|Red Hat Enterprise Linux Server release 6", "#B71C1C"),
("TAG-EMV", "Asset Search", 'name: "*emv*" or name: "*pci*"', "#D500F9"),
]
STATIC_MANUAL = [
("TAG-SED", "Securite Exposition Directe — IP publique / NAT direct", "#C62828"),
("TAG-SEI", "Securite Exposition Indirecte — derriere frontal", "#EF6C00"),
("TAG-DEC", "Decommissionnement en cours", "#6D4C41"),
("TAG-INT", "Integration / Implementation en cours", "#FDD835"),
("TAG-SIC", "Zone SIC — Systeme Information Classifie", "#1A237E"),
("TAG-SIA", "Zone SIA — Systeme Information Administration", "#283593"),
]
def _shade_cell(cell, hex_color):
"""Ajoute une couleur de fond a une cellule (style surligneur)."""
tc_pr = cell._tc.get_or_add_tcPr()
shd = OxmlElement("w:shd")
shd.set(qn("w:val"), "clear")
shd.set(qn("w:color"), "auto")
shd.set(qn("w:fill"), hex_color.replace("#", ""))
tc_pr.append(shd)
def _set_col_widths(table, widths_cm):
for row in table.rows:
for i, cell in enumerate(row.cells):
if i < len(widths_cm):
cell.width = Cm(widths_cm[i])
def main():
out = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("SANEF_Qualys_Tags_V3_RuleTypes.docx")
doc = Document()
# Marges reduites
for section in doc.sections:
section.left_margin = Cm(1.5)
section.right_margin = Cm(1.5)
section.top_margin = Cm(1.5)
section.bottom_margin = Cm(1.5)
# Titre
h = doc.add_heading("Qualys Tags V3 — Correspondance Rule Type / Valeur", level=1)
p = doc.add_paragraph()
r = p.add_run("Référence : SANEF DSI / Sécurité Opérationnelle — Plan d'action Qualys V3\n")
r.italic = True
r.font.size = Pt(9)
p.add_run("Chemin Qualys : AssetView > Tags > New Tag > cocher Dynamic, "
"puis choisir le Rule Type et copier la valeur.\n").font.size = Pt(10)
# Section 1 : Tags dynamiques
doc.add_heading("1. Tags dynamiques (DYN) — à créer en console Qualys", level=2)
doc.add_paragraph("L'API Qualys ne permet pas de créer des tags dynamiques. "
"Ces 21 tags doivent être créés manuellement via la console web.").runs[0].font.size = Pt(10)
table = doc.add_table(rows=1, cols=4)
table.style = "Light Grid Accent 1"
hdr = table.rows[0].cells
hdr[0].text = "Tag"
hdr[1].text = "Couleur"
hdr[2].text = "Rule Type"
hdr[3].text = "Valeur à saisir"
for c in hdr:
for p in c.paragraphs:
for r in p.runs:
r.bold = True
for tag, rule, value, color in TAGS:
row = table.add_row().cells
row[0].text = tag
row[1].text = color
row[2].text = rule
row[3].text = value
# Font mono pour tag + valeur
for r in row[0].paragraphs[0].runs:
r.font.name = "Consolas"
r.bold = True
for r in row[3].paragraphs[0].runs:
r.font.name = "Consolas"
r.font.size = Pt(9)
_shade_cell(row[1], color)
# Texte couleur en blanc pour cellule sombre
for r in row[1].paragraphs[0].runs:
r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
r.font.size = Pt(9)
_set_col_widths(table, [2.5, 2.0, 3.5, 10.5])
# Section 2 : Tags statiques manuels
doc.add_paragraph()
doc.add_heading("2. Tags statiques manuels (STAT) — création via API ou SQATM", level=2)
doc.add_paragraph("Ces tags sont nominatifs et necessitent une decision humaine. "
"Ils peuvent être créés via PatchCenter (/qualys/tagsv3/gap) "
"ou via SQATM.").runs[0].font.size = Pt(10)
table2 = doc.add_table(rows=1, cols=3)
table2.style = "Light Grid Accent 1"
h2 = table2.rows[0].cells
h2[0].text = "Tag"
h2[1].text = "Couleur"
h2[2].text = "Signification"
for c in h2:
for p in c.paragraphs:
for r in p.runs:
r.bold = True
for tag, desc, color in STATIC_MANUAL:
row = table2.add_row().cells
row[0].text = tag
row[1].text = color
row[2].text = desc
for r in row[0].paragraphs[0].runs:
r.font.name = "Consolas"
r.bold = True
_shade_cell(row[1], color)
for r in row[1].paragraphs[0].runs:
r.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
r.font.size = Pt(9)
_set_col_widths(table2, [2.5, 2.0, 13.5])
# Section 3 : Préfixes statiques à la demande
doc.add_paragraph()
doc.add_heading("3. Préfixes statiques à la demande", level=2)
for prefix, desc in [
("APP-xxx", "Application hebergee — APP-SAT, APP-JIRA, APP-GLPI..."),
("BDD-xxx", "Type de base de donnees — BDD-ORA, BDD-PG, BDD-SQL..."),
("VRF-xxx", "VRF reseau — VRF-TRAFIC, VRF-EMV..."),
("MID-xxx", "Middleware — MID-TOMCAT, MID-HAPROXY..."),
]:
p = doc.add_paragraph(style="List Bullet")
r = p.add_run(f"{prefix} ")
r.font.name = "Consolas"
r.bold = True
p.add_run(f"{desc}")
doc.save(out)
print(f"[OK] Genere: {out.resolve()}")
if __name__ == "__main__":
main()