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.
62 lines
2.7 KiB
Python
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")
|