from pathlib import Path from argon2 import PasswordHasher from fastapi.testclient import TestClient from app import main from app.auth import COOKIE_NAME from app.config import Settings, UserSeed from app.curator import Curator from app.db import Database WRITE_HEADERS = {"X-Note-Client": "xuxiang-web"} def test_login_isolation_roles_and_debug_privacy( tmp_path: Path, monkeypatch ): hasher = PasswordHasher() admin_key = "key-admin-test" member_key = "key-member-test" users = ( UserSeed( id="admin", label="管理员", role="admin", access_key_hash=hasher.hash(admin_key), ), UserSeed( id="member", label="用户二", role="member", access_key_hash=hasher.hash(member_key), ), ) settings = Settings( data_dir=tmp_path, database_path=tmp_path / "api.sqlite3", users=users, session_secret="session-secret-for-tests", deepseek_api_key=None, deepseek_base_url="https://api.deepseek.com", deepseek_model="deepseek-v4-pro", cookie_secure=False, auth_disabled=False, ) database = Database(settings.database_path) monkeypatch.setattr(main, "settings", settings) monkeypatch.setattr(main, "db", database) monkeypatch.setattr(main, "curator", Curator(database, settings)) with TestClient(main.app) as client: assert client.post( "/api/login", json={"access_key": "wrong"} ).status_code == 401 admin_login = client.post( "/api/login", json={"access_key": admin_key} ) assert admin_login.status_code == 200 assert admin_login.json()["user"]["role"] == "admin" admin_cookie = client.cookies.get(COOKIE_NAME) member_login = client.post( "/api/login", json={"access_key": member_key} ) assert member_login.status_code == 200 member_cookie = client.cookies.get(COOKIE_NAME) client.cookies.set(COOKIE_NAME, admin_cookie) admin_fragment = client.post( "/api/fragments", json={"content": "管理员的记录"}, headers=WRITE_HEADERS, ) assert admin_fragment.status_code == 201 client.cookies.set(COOKIE_NAME, member_cookie) member_fragment = client.post( "/api/fragments", json={"content": "用户二的记录"}, headers=WRITE_HEADERS, ) assert member_fragment.status_code == 201 assert [item["content"] for item in client.get("/api/fragments").json()["items"]] == [ "用户二的记录" ] assert client.get("/api/admin/overview").status_code == 403 run_id = database.start_agent_run( "member", member_fragment.json()["id"], "deepseek-v4-pro", "prompt.v1", "high", ) database.add_agent_event( run_id, "member", "decision_committed", { "standalone": False, "assessments": [{"title": "私密产物", "maturity": 42}], }, ) client.cookies.set(COOKIE_NAME, admin_cookie) assert [item["content"] for item in client.get("/api/fragments").json()["items"]] == [ "管理员的记录" ] redacted = client.get(f"/api/admin/runs/{run_id}").json() assert redacted["fragment"]["content_visible"] is False assert redacted["events"][-1]["payload"] == { "standalone": False, "assessment_count": 1, } client.cookies.set(COOKIE_NAME, member_cookie) shared = client.patch( "/api/account/debug-sharing", json={"enabled": True}, headers=WRITE_HEADERS, ) assert shared.status_code == 200 client.cookies.set(COOKIE_NAME, admin_cookie) visible = client.get(f"/api/admin/runs/{run_id}").json() assert visible["fragment"]["content_visible"] is True assert visible["fragment"]["content"] == "用户二的记录"