Files
sales-trainer/backend/scripts/test_ip_protection.py
Macky e1d61e1e1e feat(ip): protect persona 'formula' — secret fields only super_admin sees/edits
IP protection so casual copying yields inferior results:
- SECRET_PERSONA_FIELDS (pains/objections/negotiation_levers/opener/tolerance +
  pain rootCause/resolutionConditions): only super_admin can view/edit them.
- list_personas/get_persona/update_persona/get_group strip these for role=admin (and
  hide sales_kit + pain-fit report from admins too).
- update_persona rejects admin attempts to set secret fields (403).
- PersonaForm hides the 'การขาย' recipe section for non-super-admin (shows locked note);
  auth.isSuperAdmin getter added.
Rebuilt dist. Added test_ip_protection.
2026-08-09 07:22:50 +07:00

62 lines
2.7 KiB
Python

"""Test: IP protection — admin cannot see/edit secret persona fields; super_admin can."""
import os, sys, tempfile, warnings
from pathlib import Path
warnings.filterwarnings("ignore")
BACKEND = str(Path(__file__).resolve().parents[1])
sys.path.insert(0, BACKEND)
from app.factory import create_app
from app.config import Config
td = tempfile.mkdtemp()
Config.DATA_DIR = Path(td)
sys.path.insert(0, BACKEND + "/scripts")
from mock_llm import MockLLM
app = create_app()
app.extensions["llm"] = MockLLM()
C = app.test_client()
def tok(u, p): return C.post("/api/auth/login", json={"username": u, "password": p}).get_json()["token"]
AT = tok("admin", "1234"); AH = {"Authorization": f"Bearer {AT}"}
C.post("/api/auth/setup", headers=AH, json={"username": "admin", "email": "a@b.co", "password": "newpass"})
AT = tok("admin", "newpass"); AH = {"Authorization": f"Bearer {AT}"}
gid = C.post("/api/groups", headers=AH, json={"product": "CRM", "segment": "SME", "channel": "line", "language": "th"}).get_json()["group"]["id"]
C.post(f"/api/groups/{gid}/analyze", headers=AH)
personas = C.get(f"/api/groups/{gid}/personas", headers=AH).get_json()["personas"] # super_admin sees all
assert personas and "pains" in personas[0], "super_admin should see secret fields"
print("[ok] super_admin sees secret fields")
# create an admin (not super) user
C.post("/api/admin/users", headers=AH, json={"username": "adm", "name": "Adm", "password": "pppp", "role": "admin"})
AT2 = tok("adm", "pppp"); AH2 = {"Authorization": f"Bearer {AT2}"}
pid = personas[0]["id"]
# admin list_personas: secret fields stripped
admin_list = C.get(f"/api/groups/{gid}/personas", headers=AH2).get_json()["personas"]
assert "pains" not in admin_list[0] and "tolerance" not in admin_list[0], "admin list should strip secrets"
print("[ok] admin list strips secret fields")
# admin update with a secret field -> 403
r = C.put(f"/api/groups/{gid}/personas/{pid}", headers=AH2, json={"name": "X", "tolerance": 1})
assert r.status_code == 403, r.get_json()
print("[ok] admin cannot set secret field (403)")
# admin update of non-secret field -> ok, but response still strips secrets
r = C.put(f"/api/groups/{gid}/personas/{pid}", headers=AH2, json={"name": "Edited Name"})
assert r.status_code == 200, r.get_json()
body = r.get_json()["persona"]
assert body["name"] == "Edited Name"
assert "pains" not in body, "admin update response should strip secrets"
print("[ok] admin can edit non-secret field; response strips secrets")
# super_admin can update secret field
r = C.put(f"/api/groups/{gid}/personas/{pid}", headers=AH, json={"tolerance": 5})
assert r.status_code == 200, r.get_json()
print("[ok] super_admin can edit secret field")
print("ALL IP-PROTECTION TESTS PASSED")