"""Tests d'intégration API ↔ store (unlock, labels patients, audit).""" import nacl.pwhash from fastapi.testclient import TestClient from kazeia_central.core.adb import Adb from kazeia_central.core.adb.client import AdbDevice from kazeia_central.app import create_app from kazeia_central.core.store import Store _OPS = nacl.pwhash.argon2id.OPSLIMIT_MIN _MEM = nacl.pwhash.argon2id.MEMLIMIT_MIN class _FakeAdb(Adb): def __init__(self): super().__init__() def devices(self): return [AdbDevice(serial="ABC123", state="device", props={"model": "Pad3"})] def _client(tmp_path): store = Store(tmp_path / "central.db", kdf_ops=_OPS, kdf_mem=_MEM) return TestClient(create_app(adb=_FakeAdb(), store=store, start_autosync=False)) def test_lock_unlock_flow(tmp_path): c = _client(tmp_path) st = c.get("/api/lock-status").json() assert st == {"initialized": False, "unlocked": False} r = c.post("/api/unlock", json={"password": "oppass"}).json() assert r["unlocked"] and r["initialized_now"] assert c.get("/api/lock-status").json()["unlocked"] is True def test_label_requires_unlock_then_persists(tmp_path): c = _client(tmp_path) # verrouillé → 423 assert c.put("/api/devices/ABC123/label", json={"label": "X"}).status_code == 423 c.post("/api/unlock", json={"password": "pw"}) # device listé sans label au départ devs = c.get("/api/devices").json() assert devs[0]["serial"] == "ABC123" and devs[0]["label"] is None # on nomme c.put("/api/devices/ABC123/label", json={"label": "Mme D."}) devs = c.get("/api/devices").json() assert devs[0]["label"] == "Mme D." def test_wrong_password_401(tmp_path): c = _client(tmp_path) c.post("/api/unlock", json={"password": "right"}) # re-lock puis mauvais mdp c.post("/api/lock") assert c.post("/api/unlock", json={"password": "wrong"}).status_code == 401 def test_audit_trace(tmp_path): c = _client(tmp_path) c.post("/api/unlock", json={"password": "pw"}) c.put("/api/devices/ABC123/label", json={"label": "Mme D."}) actions = [a["action"] for a in c.get("/api/audit").json()] assert "store_init" in actions and "set_label" in actions # le label (PII) ne doit PAS apparaître en clair dans l'audit raw = c.get("/api/audit").text assert "Mme D." not in raw def test_locked_hides_labels(tmp_path): c = _client(tmp_path) c.post("/api/unlock", json={"password": "pw"}) c.put("/api/devices/ABC123/label", json={"label": "Secret"}) c.post("/api/lock") devs = c.get("/api/devices").json() assert "label" not in devs[0] # verrouillé → pas d'enrichissement