You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

60 lines
2.5 KiB
Python

# backend/tests/test_multiuser_isolation.py — per-user 격리(IDOR 404 + 도메인 스코프). 가장 중요.
import pytest
def _login(c, email, pw="demo-1234"):
return c.post("/api/auth/login", json={"email": email, "password": pw})
def test_user_b_cannot_see_user_a_task(client_auth):
_login(client_auth, "jiwoo@lumi.co")
a_task = client_auth.post(
"/api/tasks", json={"title": "A의 비밀 작업", "project_id": "me"}
).json()
client_auth.post("/api/auth/logout")
_login(client_auth, "hyunwoo@lumi.co")
# 직접 id 조회 → 404(존재 숨김)
assert client_auth.get(f"/api/tasks/{a_task['id']}").status_code == 404
# B 의 목록(스코프=현우, 데이터 없음)에 A 작업 없음
flat = client_auth.get("/api/tasks").json()
assert all(t["id"] != a_task["id"] for t in flat)
def test_create_owner_is_current_user_not_body(client_auth):
# 바디에 user_id 를 넣어도 무시(질량 할당/IDOR 방어) — current_user 가 소유자
_login(client_auth, "hyunwoo@lumi.co")
t = client_auth.post(
"/api/tasks", json={"title": "현우 작업", "project_id": "me", "user_id": "jiwoo"}
).json()
# 현우 목록엔 보이고
assert any(x["id"] == t["id"] for x in client_auth.get("/api/tasks").json())
# 지우 목록엔 없음
client_auth.post("/api/auth/logout")
_login(client_auth, "jiwoo@lumi.co")
assert all(x["id"] != t["id"] for x in client_auth.get("/api/tasks").json())
def test_b_starts_empty_a_full(client_auth):
# phase-16+: 작업 시드 제거 → A(지우)가 작업을 만들면 A 만 보이고 B(현우)는 빈 상태
_login(client_auth, "jiwoo@lumi.co")
client_auth.post("/api/tasks", json={"title": "지우 작업", "project_id": "me"})
assert len(client_auth.get("/api/tasks").json()) > 0 # 지우는 자기 작업 보임
client_auth.post("/api/auth/logout")
_login(client_auth, "hyunwoo@lumi.co")
assert client_auth.get("/api/tasks").json() == []
assert client_auth.get("/api/inbox").json() == []
assert client_auth.get("/api/mail").json() == []
notif = client_auth.get("/api/notifications").json()
assert notif["now"] == [] and notif["later"] == [] and notif["held"] == []
@pytest.mark.parametrize(
"path", ["/api/tasks", "/api/inbox", "/api/mail", "/api/notifications"]
)
def test_b_lists_scoped_no_a_leak(client_auth, path):
_login(client_auth, "hyunwoo@lumi.co")
r = client_auth.get(path)
assert r.status_code == 200 # 빈 스코프여도 200(빈 응답)