fix(gui): fail-close si CamemBERT-bio indisponible (P0-1, anti-fuite PII)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-25 17:44:04 +02:00
parent f3e6cdb980
commit dc0554e694
2 changed files with 81 additions and 1 deletions

View File

@@ -0,0 +1,63 @@
"""Tests fail-close P0-1 : le moteur ne doit JAMAIS être invoqué si CamemBERT-bio
est indisponible et que use_local_ner=True.
Garantie de sécurité : EngineUnavailableError est levée AVANT l'appel du moteur,
ce qui empêche la production d'un document potentiellement non anonymisé.
"""
from pathlib import Path
import pytest
from gui_v6.engine_bridge import (
EngineSettings,
EngineUnavailableError,
NerManagers,
make_process_fn,
)
def _managers_with_broken_camembert(settings):
def boom():
raise RuntimeError("model.onnx absent")
return NerManagers(
settings,
factories={"camembert": boom, "eds": boom, "gliner": boom},
caps_provider=lambda: {},
)
def test_process_fn_raises_when_mandatory_ner_unavailable():
settings = EngineSettings(use_local_ner=True)
managers = _managers_with_broken_camembert(settings)
called = {"engine": False}
def fake_engine(*a, **k):
called["engine"] = True
return {"pdf": "x"}
fn = make_process_fn(settings, managers=managers, engine=fake_engine)
with pytest.raises(EngineUnavailableError):
fn(Path("doc.pdf"), Path("/tmp/out"))
assert called["engine"] is False
def test_process_fn_runs_when_ner_ok():
settings = EngineSettings(use_local_ner=True)
managers = NerManagers(
settings,
factories={"camembert": lambda: object(), "eds": lambda: None, "gliner": lambda: None},
caps_provider=lambda: {},
)
fn = make_process_fn(settings, managers=managers, engine=lambda *a, **k: {"pdf": "ok"})
assert fn(Path("d.pdf"), Path("/tmp/out")) == {"pdf": "ok"}
def test_process_fn_skips_ner_guard_when_local_ner_disabled():
# use_local_ner=False : on ne charge pas le NER et on NE bloque PAS,
# même si les factories échoueraient (symétrique du garde-fou fail-close).
settings = EngineSettings(use_local_ner=False)
managers = _managers_with_broken_camembert(settings)
fn = make_process_fn(settings, managers=managers, engine=lambda *a, **k: {"pdf": "ok"})
assert fn(Path("d.pdf"), Path("/tmp/out")) == {"pdf": "ok"}