Files
SecureCheck/securecheck/__main__.py
2026-04-05 18:56:26 +02:00

138 lines
5.2 KiB
Python

from __future__ import annotations
import argparse
import sys
from datetime import datetime
from .app import RunSummaryTUI, SecureCheckTUI
from .catalog import builtin_scenarios, task_catalog
from .config import build_paths, ensure_app_dirs
from .executor import ExecutionContext, execute_tasks
from .logging_utils import attach_run_handler, setup_logging
from .status import collect_status
from .storage import ScenarioStore
from .system_info import detect_system
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="SecureCheck - console semi-graphique pour contrôles sécurité Linux")
parser.add_argument("--dry-run", action="store_true", help="Simule les commandes sans modifier le système")
parser.add_argument("--run", action="store_true", help="Lance immédiatement les tâches passées via --tasks ou --scenario")
parser.add_argument("--tasks", help="Liste de tâches séparées par des virgules")
parser.add_argument("--scenario", help="Nom d'un scénario enregistré ou builtin")
parser.add_argument("--list-scenarios", action="store_true", help="Affiche les scénarios disponibles")
return parser.parse_args()
def resolve_task_selection(args: argparse.Namespace, store: ScenarioStore, available_task_keys: set[str]) -> list[str]:
if args.scenario:
scenario = store.get(args.scenario)
if not scenario:
raise SystemExit(f"Scénario inconnu: {args.scenario}")
return [key for key in scenario.task_keys if key in available_task_keys]
if args.tasks:
selected = [key.strip() for key in args.tasks.split(",") if key.strip()]
invalid = [key for key in selected if key not in available_task_keys]
if invalid:
raise SystemExit(f"Tâches inconnues: {', '.join(invalid)}")
return selected
return []
def print_led_dashboard(system) -> None:
print("")
print("=== Etat du système ===")
for item in collect_status(system):
led = "\033[32m●\033[0m" if item.ok else "\033[31m●\033[0m"
print(f"{led} [{item.category}] {item.label}: {item.detail}")
def print_summary(results, run_log_path, system) -> None:
ok_count = sum(1 for result in results if result.success)
ko_count = len(results) - ok_count
print("")
print("=== Résumé ===")
for result in results:
status = "OK" if result.success else "ECHEC"
suffix = f" | erreur: {result.error}" if result.error else ""
print(f"- {status} | {result.label} | {result.duration_seconds:.1f}s{suffix}")
for detail in result.details:
print(f" {detail}")
print_led_dashboard(system)
print(f"Logs d'exécution: {run_log_path}")
print(f"Total OK={ok_count} / ECHEC={ko_count}")
def main() -> int:
args = parse_args()
paths = build_paths()
ensure_app_dirs(paths)
logger = setup_logging(paths.app_log_file)
system = detect_system()
tasks = task_catalog()
task_by_key = {task.key: task for task in tasks}
store = ScenarioStore(paths.scenario_file, builtin_scenarios())
if args.list_scenarios:
for scenario in store.list_all():
print(f"{scenario.name}: {scenario.description}")
return 0
selected_keys = resolve_task_selection(args, store, set(task_by_key))
interactive_mode = not args.run
active_scenario_name = args.scenario
menu_message: str | None = None
while True:
if interactive_mode:
tui = SecureCheckTUI(
system,
tasks,
store,
status_provider=lambda: collect_status(system),
initial_selected=set(selected_keys) if selected_keys else None,
initial_scenario_name=active_scenario_name,
initial_message=menu_message,
)
selection = tui.run()
if selection is None:
return 0
selected_keys = selection.task_keys
active_scenario_name = selection.scenario_name
if not selected_keys:
if interactive_mode:
menu_message = "Aucune tâche sélectionnée."
continue
print("Aucune tâche sélectionnée.")
return 1
selected_tasks = [task_by_key[key] for key in selected_keys]
context = ExecutionContext(paths=paths, system=system, logger=logger, dry_run=args.dry_run)
run_log_path = paths.log_dir / f"run-{datetime.now().strftime('%Y%m%d-%H%M%S')}.log"
run_handler = attach_run_handler(logger, run_log_path)
try:
results = execute_tasks(context, selected_tasks)
finally:
logger.removeHandler(run_handler)
run_handler.close()
if interactive_mode:
status_items = collect_status(system)
RunSummaryTUI(results, status_items, str(run_log_path)).run()
ok_count = sum(1 for result in results if result.success)
ko_count = len(results) - ok_count
menu_message = f"Dernière exécution: {ok_count} OK / {ko_count} ECHEC. Sélection prête pour une nouvelle action."
continue
print_summary(results, run_log_path, system)
return 0 if all(result.success for result in results) else 2
if __name__ == "__main__":
sys.exit(main())