feat: open source multi-user AI notebook with observability
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
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"] == "用户二的记录"
|
||||
Reference in New Issue
Block a user