feat: restrict backup archive download to primary admin and hide admin-hidden projects from other admins
DevPlace CI / test (push) Failing after 22m57s
DevPlace CI / test (push) Failing after 22m57s
- Add `get_admin_uids()` and `get_primary_admin_uid()` to database.py for resolving the earliest-created admin - Modify `can_view_project()` in content.py so a project hidden by an admin is invisible to other admins (both web UI and REST API) - Update `_download_url()` and `_backup_payload()` in admin/backups.py to accept a `can_download` flag, gating the download endpoint with `is_primary_admin()` - Remove `role` from `_user_facts()` in docs_live.py to avoid leaking admin status in live docs - Update doc summaries in docs_api.py to reflect the new admin-visibility and backup-download semantics
This commit is contained in:
@@ -1,8 +1,52 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import time
|
||||
import requests
|
||||
from tests.conftest import BASE_URL
|
||||
from devplacepy.database import get_table, refresh_snapshot
|
||||
from devplacepy.utils import clear_user_cache
|
||||
|
||||
_counter_search = [0]
|
||||
|
||||
|
||||
def _signup_search():
|
||||
_counter_search[0] += 1
|
||||
name = f"cas{int(time.time() * 1000)}{_counter_search[0]}"
|
||||
requests.post(
|
||||
f"{BASE_URL}/auth/signup",
|
||||
data={
|
||||
"username": name,
|
||||
"email": f"{name}@t.dev",
|
||||
"password": "secret123",
|
||||
"confirm_password": "secret123",
|
||||
},
|
||||
allow_redirects=True,
|
||||
)
|
||||
row = get_table("users").find_one(username=name)
|
||||
return name, row["uid"], row["api_key"]
|
||||
|
||||
|
||||
def _make_admin_search():
|
||||
name, uid, key = _signup_search()
|
||||
get_table("users").update({"uid": uid, "role": "Admin"}, ["uid"])
|
||||
clear_user_cache(uid)
|
||||
return name, uid, key
|
||||
|
||||
|
||||
def _create_private_project(key, title):
|
||||
r = requests.post(
|
||||
f"{BASE_URL}/projects/create",
|
||||
headers={"X-API-KEY": key, "Accept": "application/json"},
|
||||
data={
|
||||
"title": title,
|
||||
"description": "search test",
|
||||
"project_type": "software",
|
||||
"status": "In Development",
|
||||
"is_private": "on",
|
||||
},
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
return r.json()["data"]["slug"]
|
||||
|
||||
|
||||
def _admin_session():
|
||||
@@ -33,3 +77,21 @@ def test_project_search_empty_query(app_server, seeded_db):
|
||||
r = s.get(f"{BASE_URL}/admin/containers/projects/search?q=")
|
||||
assert r.status_code == 200
|
||||
assert r.json()["results"] == []
|
||||
|
||||
|
||||
def test_project_search_hides_other_admin_private_project(app_server):
|
||||
_, _, owner_key = _make_admin_search()
|
||||
_, _, other_admin_key = _make_admin_search()
|
||||
title = f"SearchHidden{int(time.time() * 1000)}"
|
||||
slug = _create_private_project(owner_key, title)
|
||||
|
||||
other = requests.Session()
|
||||
other.headers.update({"X-API-KEY": other_admin_key})
|
||||
r = other.get(f"{BASE_URL}/admin/containers/projects/search?q={title}")
|
||||
assert r.status_code == 200
|
||||
assert slug not in [row["slug"] for row in r.json()["results"]]
|
||||
|
||||
owner = requests.Session()
|
||||
owner.headers.update({"X-API-KEY": owner_key})
|
||||
r = owner.get(f"{BASE_URL}/admin/containers/projects/search?q={title}")
|
||||
assert slug in [row["slug"] for row in r.json()["results"]]
|
||||
|
||||
Reference in New Issue
Block a user