From 831c70c1055778504402a3c0fb9aee39bbbabb37 Mon Sep 17 00:00:00 2001 From: Domi31tls Date: Tue, 2 Jun 2026 16:48:59 +0200 Subject: [PATCH] =?UTF-8?q?feat(admin):=20D-11=20Ollama=20VLM=20cach=C3=A9?= =?UTF-8?q?=20par=20d=C3=A9faut=20+=20module=20admin=5Fmode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Module admin_mode.py Nouveau module qui détecte si l'application tourne en mode admin : - Variable d'environnement `ANON_ADMIN=1` (ou `true`/`yes`/`on`) - OU fichier `.admin` à la racine de l'application Expose : - `is_admin()` — retourne bool, caché en module - `admin_required(feature_name)` — garde qui lève RuntimeError si pas admin Pas de mot de passe — c'est un verrou "interdit aux distraits" pour ne pas exposer au bêta-testeur des options sensibles (envoi à Ollama, conf critique). Le vrai durcissement viendra avec D-13 (mode admin complet). ## GUI — VLM Ollama caché par défaut (D-11) Dans Pseudonymisation_Gui_V5.py, après l'import classique de VlmManager, on force VlmManager = None et VlmConfig = None **si le mode admin n'est pas actif**. Effet : - Bêta-testeur lambda : VLM Ollama complètement invisible et inactif (économise aussi la RAM du modèle CamemBERT-bio + downloads Ollama) - Mode admin activé : comportement actuel inchangé Tests manuels : - import GUI sans env : VlmManager = None ✅ - `ANON_ADMIN=1 python -c "import Pseudonymisation_Gui_V5"` : VlmManager est ✅ ## Reste à faire (D-13) - Mode admin = mot de passe / fingerprint - Cacher dans l'UI les widgets liés au VLM (cases à cocher, etc.) - Cacher d'autres réglages sensibles (stopwords personnalisés, regex_overrides, force_terms) Co-Authored-By: Claude Opus 4.7 (1M context) --- Pseudonymisation_Gui_V5.py | 12 +++++++ admin_mode.py | 73 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 admin_mode.py diff --git a/Pseudonymisation_Gui_V5.py b/Pseudonymisation_Gui_V5.py index c6806b2..e6ea4ce 100644 --- a/Pseudonymisation_Gui_V5.py +++ b/Pseudonymisation_Gui_V5.py @@ -77,6 +77,18 @@ except Exception: VlmManager = None # type: ignore VlmConfig = None # type: ignore +# D-11 : VLM Ollama caché par défaut. Activé seulement en mode admin +# (env ANON_ADMIN=1 ou fichier .admin à côté de l'EXE). Empêche le bêta +# d'envoyer du contenu à Ollama externe sans en avoir conscience. +try: + from admin_mode import is_admin as _is_admin_mode +except Exception: + def _is_admin_mode() -> bool: + return False +if not _is_admin_mode(): + VlmManager = None # type: ignore + VlmConfig = None # type: ignore + try: import yaml except Exception: diff --git a/admin_mode.py b/admin_mode.py new file mode 100644 index 0000000..dc11eee --- /dev/null +++ b/admin_mode.py @@ -0,0 +1,73 @@ +"""Mode admin pour l'application Pseudonymisation (D-13). + +Le mode admin déverrouille des fonctionnalités cachées au bêta-testeur : +- VLM Ollama (D-11) — détection visuelle par LLM local +- Paramètres avancés sensibles (stopwords personnalisés, force_terms, etc.) +- Profils techniques (regex_overrides) + +Activation possible (par ordre de priorité) : +1. Variable d'environnement : `ANON_ADMIN=1` +2. Fichier `.admin` à la racine de l'application (à côté de l'EXE / du module) + +Pour désactiver : supprimer le fichier `.admin` et la variable d'env. + +Aucun mot de passe pour la v1.0 — c'est juste un verrou "interdit aux +distraits" qui empêche le bêta-testeur ou un utilisateur final de tomber +sur des options qui pourraient leak des données (envoi à Ollama externe, +modifications config critique). +""" +from __future__ import annotations + +import os +from pathlib import Path +from typing import Optional + +_ADMIN_CACHED: Optional[bool] = None + + +def _project_root() -> Path: + """Retourne le dossier racine de l'application (compat dev + EXE).""" + try: + return Path(__file__).parent.resolve() + except NameError: + return Path.cwd() + + +def is_admin(force_refresh: bool = False) -> bool: + """Retourne True si le mode admin est actif. + + Résultat caché en module (les vérifications coûtent presque rien mais + `is_admin()` peut être appelé dans des boucles serrées). `force_refresh` + permet de re-vérifier après un changement de configuration. + """ + global _ADMIN_CACHED + if _ADMIN_CACHED is not None and not force_refresh: + return _ADMIN_CACHED + + # Priorité 1 : variable d'env + env_val = os.environ.get("ANON_ADMIN", "").strip().lower() + if env_val in ("1", "true", "yes", "on"): + _ADMIN_CACHED = True + return True + + # Priorité 2 : fichier .admin + admin_file = _project_root() / ".admin" + if admin_file.exists(): + _ADMIN_CACHED = True + return True + + _ADMIN_CACHED = False + return False + + +def admin_required(feature_name: str = "fonctionnalité") -> None: + """Lève RuntimeError si pas admin. + + À utiliser comme garde au début d'une méthode sensible. + """ + if not is_admin(): + raise RuntimeError( + f"Mode admin requis pour {feature_name}. " + f"Activez via ANON_ADMIN=1 ou créez le fichier .admin " + f"à la racine de l'application." + )