Bugs Correction

This commit is contained in:
Johnny
2026-04-06 06:07:02 +02:00
parent 751dc8892c
commit 4980d8cf3c
34 changed files with 20541 additions and 35 deletions

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import curses
import re
import textwrap
from collections import defaultdict
from dataclasses import dataclass
@@ -333,10 +334,17 @@ class SecureCheckTUI:
class RunSummaryTUI:
ANSI_RE = re.compile(r"\x1b\[[0-?]*[ -/]*[@-~]")
def __init__(self, results: list[TaskResult], status_items: list[StatusItem], run_log_path: str) -> None:
self.results = results
self.status_items = status_items
self.run_log_path = run_log_path
self.scroll_offset = 0
@classmethod
def _clean(cls, text: str) -> str:
return cls.ANSI_RE.sub("", text)
def run(self) -> None:
curses.wrapper(self._main)
@@ -344,48 +352,73 @@ class RunSummaryTUI:
def _main(self, stdscr: curses.window) -> None:
curses.curs_set(0)
stdscr.keypad(True)
stdscr.timeout(5000)
_setup_colors()
while True:
self._draw(stdscr)
key = stdscr.getch()
if key == -1 or key in (ord("q"), 27, 10, 13, ord("m"), ord(" ")):
if key in (ord("q"), 27, 10, 13, ord("m"), ord(" ")):
return
if key == curses.KEY_UP and self.scroll_offset > 0:
self.scroll_offset -= 1
elif key == curses.KEY_DOWN:
self.scroll_offset += 1
def _draw(self, stdscr: curses.window) -> None:
stdscr.erase()
height, width = stdscr.getmaxyx()
ok_count = sum(1 for result in self.results if result.success)
ko_count = len(self.results) - ok_count
self._draw_box(stdscr, 0, 1, height - 1, width - 2, "Résumé d'exécution")
stdscr.addnstr(1, 3, f"OK: {ok_count} | ECHEC: {ko_count} | Retour menu auto dans 5s", width - 6, curses.color_pair(Palette.HEADER) | curses.A_BOLD)
row = 3
score_lines: list[str] = []
notif_lines: list[str] = []
entries: list[tuple[str, int]] = []
entries.append((f"OK: {ok_count} | ECHEC: {ko_count} | Appuie sur une touche pour revenir", curses.color_pair(Palette.HEADER) | curses.A_BOLD))
for result in self.results:
if row >= height - 6:
break
color = curses.color_pair(Palette.SUCCESS if result.success else Palette.ERROR)
status = "OK" if result.success else "ECHEC"
line = f"{status:<5} {result.label} ({result.duration_seconds:.1f}s)"
stdscr.addnstr(row, 3, line, width - 6, color | curses.A_BOLD)
row += 1
for detail in result.details[:2]:
if row >= height - 6:
break
stdscr.addnstr(row, 6, f"- {detail}", width - 9)
row += 1
if result.error and row < height - 6:
stdscr.addnstr(row, 6, f"- {result.error}", width - 9, curses.color_pair(Palette.ERROR))
row += 1
row += 1
stdscr.addnstr(row, 3, "Etat synthétique:", width - 6, curses.color_pair(Palette.CATEGORY) | curses.A_BOLD)
row += 1
for item in self.status_items[: max(0, height - row - 2)]:
color = curses.color_pair(Palette.SUCCESS if item.ok else Palette.ERROR)
stdscr.addnstr(row, 3, "", 1, color | curses.A_BOLD)
stdscr.addnstr(row, 5, f"[{item.category}] {item.label}: {item.detail}", width - 8)
row += 1
stdscr.addnstr(height - 2, 3, f"Log: {self.run_log_path}", width - 6, curses.color_pair(Palette.MUTED))
color = curses.color_pair(Palette.SUCCESS if result.success else Palette.ERROR)
entries.append((f"{status:<4} {result.label} ({result.duration_seconds:.1f}s)", color | curses.A_BOLD))
for detail in result.details:
clean = self._clean(detail)
if clean.startswith("Score Lynis") or clean.startswith("Hardening index"):
score_lines.append(clean)
continue
if clean.startswith("Modifications") or clean.strip().startswith(""):
notif_lines.append(clean)
continue
wrapped = textwrap.wrap(clean, width - 9) or [""]
for line in wrapped:
entries.append((f" - {line}", 0))
if result.error:
entries.append((f" - {result.error}", curses.color_pair(Palette.ERROR)))
if score_lines:
entries.insert(1, ("Lynis", curses.color_pair(Palette.CATEGORY) | curses.A_BOLD))
for idx, line in enumerate(score_lines, start=2):
entries.insert(idx, (f" {line}", curses.color_pair(Palette.SUCCESS)))
entries.append((("", 0)))
entries.append(("Etat synthétique:", curses.color_pair(Palette.CATEGORY) | curses.A_BOLD))
for item in self.status_items:
attr = curses.color_pair(Palette.SUCCESS if item.ok else Palette.ERROR) | curses.A_BOLD
entries.append((f"● [{item.category}] {item.label}: {item.detail}", attr))
if notif_lines:
entries.append((("", 0)))
entries.append(("Modifications recommandées:", curses.color_pair(Palette.ERROR) | curses.A_BOLD))
for line in notif_lines:
clean = self._clean(line)
bullet = "" if clean.strip().startswith("") else "-"
entries.append((f" {bullet} {clean.lstrip('').strip()}", curses.color_pair(Palette.MUTED)))
entries.append(("", 0))
entries.append((f"Log: {self.run_log_path}", curses.color_pair(Palette.MUTED)))
available = height - 4
max_offset = max(0, len(entries) - available)
self.scroll_offset = min(max(self.scroll_offset, 0), max_offset)
visible = entries[self.scroll_offset : self.scroll_offset + available]
self._draw_box(stdscr, 0, 1, height - 1, width - 2, "Résumé d'exécution")
for idx, (line, attr) in enumerate(visible):
stdscr.addnstr(2 + idx, 3, line, width - 6, attr)
if max_offset:
bar_pos = int((self.scroll_offset / max_offset) * (available - 1)) if max_offset else 0
stdscr.addch(2 + min(bar_pos, available - 1), width - 3, curses.ACS_CKBOARD)
def _draw_box(self, stdscr: curses.window, top: int, left: int, height: int, width: int, title: str) -> None:
stdscr.attron(curses.color_pair(Palette.PANEL))
stdscr.addch(top, left, curses.ACS_ULCORNER)