468 lines
17 KiB
Python
Raw Normal View History

# retoor <retoor@molodetz.nl>
2026-07-07 15:28:28 +02:00
from datetime import datetime, timedelta, timezone
from devplacepy.content import (
is_owner,
can_view_project,
2026-07-07 15:28:28 +02:00
can_manage_instance,
can_view_instance,
can_view_project_containers,
canonical_redirect,
first_image_url,
enrich_items,
2026-07-07 15:28:28 +02:00
owns_instance,
)
2026-07-07 15:28:28 +02:00
from devplacepy.database import get_table, get_users_by_uids, invalidate_admins_cache
from devplacepy.utils import generate_uid
import time
import pytest
import requests
from tests.conftest import BASE_URL
from devplacepy.database import get_table
from devplacepy.utils import clear_user_cache
from devplacepy import project_files
from devplacepy.project_files import ProjectFileError
from devplacepy.services.devii.actions.dispatcher import (
confirmation_error,
_is_confirmed,
)
_counter_project_visibility = [0]
def _signup_project_visibility():
_counter_project_visibility[0] += 1
name = f"pv{int(time.time() * 1000)}{_counter_project_visibility[0]}"
session = requests.Session()
session.post(
f"{BASE_URL}/auth/signup",
data={
"username": name,
"email": f"{name}@t.dev",
"password": "secret123",
"confirm_password": "secret123",
Add the trust and safety subsystem and the App Store compliance work Implements the moderation and consent obligations a social platform carries, so the web version and any client that speaks to it enforce the same rules. Moderation core (services/moderation/, database/moderation.py): a reportable target registry, the content filter and its choke points, the report queue with atomic resolution, enforcement actions, consent tracking, maturity gating, and account deletion with a grace window. Surfaces: POST /reports plus the member report list, /admin/moderation and the per-report admin view, /workspaces, terms acceptance at /auth/terms, consent and account deletion under /profile, the report button and dialog partials, the maturity gate, and the moderation stylesheet and ReportDialog client. Every user-generated surface stays reportable by construction: new content tables are registered in REPORTABLE_TARGETS or listed in UNREPORTABLE_TABLES with a reason, and the registry test fails the suite on anything left unclassified. Docs: community guidelines, content moderation, intellectual property, privacy, terms, contact, and the admin-only moderation operations page, plus the moderation API group and the Devii moderation actions. Compliance record: applecomp.md is the requirement register, applechanges.md the gap analysis against this codebase, and appleimpl.md the implementation design they resolve to. Tests cover the report flow, admin moderation, consent, account deletion, terms acceptance, workspaces, and the registry invariant across the unit, api, and e2e tiers.
2026-08-09 00:18:20 +02:00
"birth_date": "1990-01-01",
"accept_terms": "1",
},
allow_redirects=True,
)
row = get_table("users").find_one(username=name)
return name, row["uid"], row["api_key"]
def _make_admin_project_visibility():
name, uid, key = _signup_project_visibility()
get_table("users").update({"uid": uid, "role": "Admin"}, ["uid"])
clear_user_cache(uid)
return name, uid, key
def _h_project_visibility(key=None):
headers = {"Accept": "application/json"}
if key:
headers["X-API-KEY"] = key
return headers
def _create_project_project_visibility(key, title, is_private=False):
data = {
"title": title,
"description": "visibility test",
"project_type": "software",
"status": "In Development",
}
if is_private:
data["is_private"] = "on"
r = requests.post(f"{BASE_URL}/projects/create", headers=_h_project_visibility(key), data=data)
assert r.status_code == 200, r.text
return r.json()["data"]
def _project_uid(slug):
return get_table("projects").find_one(slug=slug)["uid"]
def _write_project_visibility(key, slug, path, content):
return requests.post(
f"{BASE_URL}/projects/{slug}/files/write",
headers=_h_project_visibility(key),
data={"path": path, "content": content},
allow_redirects=False,
)
def _set_private(key, slug, value):
return requests.post(
f"{BASE_URL}/projects/{slug}/private",
headers=_h_project_visibility(key),
data={"value": 1 if value else 0},
allow_redirects=False,
)
def _set_readonly(key, slug, value):
return requests.post(
f"{BASE_URL}/projects/{slug}/readonly",
headers=_h_project_visibility(key),
data={"value": 1 if value else 0},
allow_redirects=False,
)
def _list_slugs(key=None, user_uid=None):
params = {"user_uid": user_uid} if user_uid else None
r = requests.get(f"{BASE_URL}/projects", headers=_h_project_visibility(key), params=params)
return [p["slug"] for p in r.json()["projects"]]
def test_is_owner_matches_user_uid():
assert is_owner({"user_uid": "u1"}, {"uid": "u1"}) is True
assert is_owner({"user_uid": "u1"}, {"uid": "u2"}) is False
assert is_owner(None, {"uid": "u1"}) is False
assert is_owner({"user_uid": "u1"}, None) is False
def _make_user(role="Member"):
uid = generate_uid()
username = f"cv_{uid[:8]}"
get_table("users").insert(
{
"uid": uid,
"username": username,
Add the trust and safety subsystem and the App Store compliance work Implements the moderation and consent obligations a social platform carries, so the web version and any client that speaks to it enforce the same rules. Moderation core (services/moderation/, database/moderation.py): a reportable target registry, the content filter and its choke points, the report queue with atomic resolution, enforcement actions, consent tracking, maturity gating, and account deletion with a grace window. Surfaces: POST /reports plus the member report list, /admin/moderation and the per-report admin view, /workspaces, terms acceptance at /auth/terms, consent and account deletion under /profile, the report button and dialog partials, the maturity gate, and the moderation stylesheet and ReportDialog client. Every user-generated surface stays reportable by construction: new content tables are registered in REPORTABLE_TARGETS or listed in UNREPORTABLE_TABLES with a reason, and the registry test fails the suite on anything left unclassified. Docs: community guidelines, content moderation, intellectual property, privacy, terms, contact, and the admin-only moderation operations page, plus the moderation API group and the Devii moderation actions. Compliance record: applecomp.md is the requirement register, applechanges.md the gap analysis against this codebase, and appleimpl.md the implementation design they resolve to. Tests cover the report flow, admin moderation, consent, account deletion, terms acceptance, workspaces, and the registry invariant across the unit, api, and e2e tiers.
2026-08-09 00:18:20 +02:00
"terms_version": "1",
"email": f"{username}@t.dev",
"role": role,
"created_at": datetime.now(timezone.utc).isoformat(),
}
)
return get_table("users").find_one(uid=uid)
def test_can_view_project_public_visible_to_everyone(local_db):
owner = _make_user()
other = _make_user()
admin = _make_user("Admin")
project = {"user_uid": owner["uid"], "is_private": 0}
assert can_view_project(project, owner) is True
assert can_view_project(project, other) is True
assert can_view_project(project, admin) is True
assert can_view_project(project, None) is True
def test_can_view_member_private_visible_to_owner_and_admin(local_db):
owner = _make_user()
other = _make_user()
admin = _make_user("Admin")
project = {"user_uid": owner["uid"], "is_private": 1}
assert can_view_project(project, owner) is True
assert can_view_project(project, admin) is True
assert can_view_project(project, other) is False
assert can_view_project(project, None) is False
def test_can_view_admin_private_visible_to_owner_admin_only(local_db):
owner_admin = _make_user("Admin")
other_admin = _make_user("Admin")
member = _make_user()
project = {"user_uid": owner_admin["uid"], "is_private": 1}
assert can_view_project(project, owner_admin) is True
assert can_view_project(project, other_admin) is False
assert can_view_project(project, member) is False
assert can_view_project(project, None) is False
2026-07-07 15:28:28 +02:00
def _make_user_at(role, created_at):
uid = generate_uid()
username = f"cv_{uid[:8]}"
get_table("users").insert(
{
"uid": uid,
"username": username,
Add the trust and safety subsystem and the App Store compliance work Implements the moderation and consent obligations a social platform carries, so the web version and any client that speaks to it enforce the same rules. Moderation core (services/moderation/, database/moderation.py): a reportable target registry, the content filter and its choke points, the report queue with atomic resolution, enforcement actions, consent tracking, maturity gating, and account deletion with a grace window. Surfaces: POST /reports plus the member report list, /admin/moderation and the per-report admin view, /workspaces, terms acceptance at /auth/terms, consent and account deletion under /profile, the report button and dialog partials, the maturity gate, and the moderation stylesheet and ReportDialog client. Every user-generated surface stays reportable by construction: new content tables are registered in REPORTABLE_TARGETS or listed in UNREPORTABLE_TABLES with a reason, and the registry test fails the suite on anything left unclassified. Docs: community guidelines, content moderation, intellectual property, privacy, terms, contact, and the admin-only moderation operations page, plus the moderation API group and the Devii moderation actions. Compliance record: applecomp.md is the requirement register, applechanges.md the gap analysis against this codebase, and appleimpl.md the implementation design they resolve to. Tests cover the report flow, admin moderation, consent, account deletion, terms acceptance, workspaces, and the registry invariant across the unit, api, and e2e tiers.
2026-08-09 00:18:20 +02:00
"terms_version": "1",
2026-07-07 15:28:28 +02:00
"email": f"{username}@t.dev",
"role": role,
"created_at": created_at.isoformat(),
}
)
invalidate_admins_cache()
return get_table("users").find_one(uid=uid)
def _demote_existing_admins():
existing = [r["uid"] for r in get_table("users").find(role="Admin")]
for uid in existing:
get_table("users").update({"uid": uid, "role": "Member"}, ["uid"])
invalidate_admins_cache()
return existing
def _restore_admins(uids):
for uid in uids:
get_table("users").update({"uid": uid, "role": "Admin"}, ["uid"])
invalidate_admins_cache()
def _purge_users(*rows):
for row in rows:
if row:
get_table("users").delete(uid=row["uid"])
def test_owns_instance_true_for_creator():
owner = {"uid": "cnt-u1"}
other = {"uid": "cnt-u2"}
instance = {"created_by": owner["uid"]}
2026-07-26 14:57:18 +02:00
project = {"user_uid": "cnt-u3"}
2026-07-07 15:28:28 +02:00
assert owns_instance(instance, project, owner) is True
assert owns_instance(instance, project, other) is False
def test_owns_instance_true_for_project_owner():
owner = {"uid": "cnt-u1"}
creator = {"uid": "cnt-u2"}
instance = {"created_by": creator["uid"]}
project = {"user_uid": owner["uid"]}
assert owns_instance(instance, project, owner) is True
def test_owns_instance_false_when_missing_data():
assert owns_instance(None, {}, {"uid": "cnt-u1"}) is False
assert owns_instance({"created_by": "cnt-u1"}, {}, None) is False
assert owns_instance({"created_by": "cnt-u1"}, {}, {}) is False
assert owns_instance({"created_by": "cnt-u1"}, None, {"uid": "cnt-u2"}) is False
def test_can_view_project_containers_requires_admin(local_db):
owner = _make_user()
project = {"user_uid": owner["uid"], "is_private": 0}
try:
assert can_view_project_containers(project, owner) is False
assert can_view_project_containers(project, None) is False
assert can_view_project_containers(None, owner) is False
finally:
_purge_users(owner)
def test_can_view_project_containers_public_visible_to_any_admin(local_db):
restore = _demote_existing_admins()
owner_admin = other_admin = None
try:
base = datetime.now(timezone.utc)
owner_admin = _make_user_at("Admin", base)
other_admin = _make_user_at("Admin", base + timedelta(seconds=1))
project = {"user_uid": owner_admin["uid"], "is_private": 0}
assert can_view_project_containers(project, owner_admin) is True
assert can_view_project_containers(project, other_admin) is True
finally:
_purge_users(owner_admin, other_admin)
_restore_admins(restore)
def test_can_view_project_containers_private_hidden_from_other_admin(local_db):
restore = _demote_existing_admins()
owner_admin = other_admin = None
try:
base = datetime.now(timezone.utc)
owner_admin = _make_user_at("Admin", base)
other_admin = _make_user_at("Admin", base + timedelta(seconds=1))
project = {"user_uid": owner_admin["uid"], "is_private": 1}
assert can_view_project_containers(project, owner_admin) is True
assert can_view_project_containers(project, other_admin) is False
finally:
_purge_users(owner_admin, other_admin)
_restore_admins(restore)
def test_can_view_project_containers_primary_admin_sees_all(local_db):
restore = _demote_existing_admins()
primary = other_admin = None
try:
base = datetime.now(timezone.utc)
primary = _make_user_at("Admin", base)
other_admin = _make_user_at("Admin", base + timedelta(seconds=1))
project = {"user_uid": other_admin["uid"], "is_private": 1}
assert can_view_project_containers(project, primary) is True
finally:
_purge_users(primary, other_admin)
_restore_admins(restore)
def test_can_view_instance_requires_admin(local_db):
owner = _make_user()
instance = {"created_by": owner["uid"], "project_uid": "p1"}
project = {"user_uid": owner["uid"], "is_private": 0}
try:
assert can_view_instance(instance, project, owner) is False
assert can_manage_instance(instance, project, owner) is False
finally:
_purge_users(owner)
def test_can_view_instance_owner_sees_own_private_hidden_from_other_admin(local_db):
restore = _demote_existing_admins()
owner_admin = other_admin = None
try:
base = datetime.now(timezone.utc)
owner_admin = _make_user_at("Admin", base)
other_admin = _make_user_at("Admin", base + timedelta(seconds=1))
project = {"user_uid": owner_admin["uid"], "is_private": 1}
instance = {"created_by": owner_admin["uid"], "project_uid": "p1"}
assert can_view_instance(instance, project, owner_admin) is True
assert can_view_instance(instance, project, other_admin) is False
finally:
_purge_users(owner_admin, other_admin)
_restore_admins(restore)
def test_can_view_instance_public_project_visible_to_any_admin(local_db):
restore = _demote_existing_admins()
creator = other_admin = None
try:
base = datetime.now(timezone.utc)
creator = _make_user_at("Admin", base)
other_admin = _make_user_at("Admin", base + timedelta(seconds=1))
project = {"user_uid": creator["uid"], "is_private": 0}
instance = {"created_by": creator["uid"], "project_uid": "p1"}
assert can_view_instance(instance, project, other_admin) is True
finally:
_purge_users(creator, other_admin)
_restore_admins(restore)
def test_can_view_instance_primary_admin_sees_others_private_instance(local_db):
restore = _demote_existing_admins()
primary = owner_admin = None
try:
base = datetime.now(timezone.utc)
primary = _make_user_at("Admin", base)
owner_admin = _make_user_at("Admin", base + timedelta(seconds=1))
project = {"user_uid": owner_admin["uid"], "is_private": 1}
instance = {"created_by": owner_admin["uid"], "project_uid": "p1"}
assert can_view_instance(instance, project, primary) is True
finally:
_purge_users(primary, owner_admin)
_restore_admins(restore)
def test_can_manage_instance_only_owner_or_primary_admin(local_db):
restore = _demote_existing_admins()
primary = owner_admin = other_admin = None
try:
base = datetime.now(timezone.utc)
primary = _make_user_at("Admin", base)
owner_admin = _make_user_at("Admin", base + timedelta(seconds=1))
other_admin = _make_user_at("Admin", base + timedelta(seconds=2))
project = {"user_uid": owner_admin["uid"], "is_private": 1}
instance = {"created_by": owner_admin["uid"], "project_uid": "p1"}
assert can_manage_instance(instance, project, owner_admin) is True
assert can_manage_instance(instance, project, primary) is True
assert can_manage_instance(instance, project, other_admin) is False
finally:
_purge_users(primary, owner_admin, other_admin)
_restore_admins(restore)
def test_can_manage_instance_other_admin_denied_even_on_public_project(local_db):
restore = _demote_existing_admins()
owner_admin = other_admin = None
try:
base = datetime.now(timezone.utc)
owner_admin = _make_user_at("Admin", base)
other_admin = _make_user_at("Admin", base + timedelta(seconds=1))
project = {"user_uid": owner_admin["uid"], "is_private": 0}
instance = {"created_by": owner_admin["uid"], "project_uid": "p1"}
assert can_view_instance(instance, project, other_admin) is True
assert can_manage_instance(instance, project, other_admin) is False
finally:
_purge_users(owner_admin, other_admin)
_restore_admins(restore)
def test_canonical_redirect_when_slug_differs():
item = {"slug": "abcd1234-title", "uid": "abcd1234"}
assert canonical_redirect("posts", item, "abcd1234-title") is None
response = canonical_redirect("posts", item, "abcd1234")
assert response is not None
assert response.status_code == 301
assert response.headers["location"] == "/posts/abcd1234-title"
def test_first_image_url_prefers_inline():
assert first_image_url({"image": "pic.png"}, None) == "/static/uploads/pic.png"
def test_first_image_url_uses_first_image_attachment():
item = {"image": None}
attachments = [{"is_image": False, "url": "/a"}, {"is_image": True, "url": "/b"}]
assert first_image_url(item, attachments) == "/b"
def test_first_image_url_none_when_absent():
assert first_image_url({}, []) is None
def test_enrich_items_attaches_author_and_extras(local_db):
uid = generate_uid()
username = f"enrich_{uid[:8]}"
get_table("users").insert(
{
"uid": uid,
"username": username,
Add the trust and safety subsystem and the App Store compliance work Implements the moderation and consent obligations a social platform carries, so the web version and any client that speaks to it enforce the same rules. Moderation core (services/moderation/, database/moderation.py): a reportable target registry, the content filter and its choke points, the report queue with atomic resolution, enforcement actions, consent tracking, maturity gating, and account deletion with a grace window. Surfaces: POST /reports plus the member report list, /admin/moderation and the per-report admin view, /workspaces, terms acceptance at /auth/terms, consent and account deletion under /profile, the report button and dialog partials, the maturity gate, and the moderation stylesheet and ReportDialog client. Every user-generated surface stays reportable by construction: new content tables are registered in REPORTABLE_TARGETS or listed in UNREPORTABLE_TABLES with a reason, and the registry test fails the suite on anything left unclassified. Docs: community guidelines, content moderation, intellectual property, privacy, terms, contact, and the admin-only moderation operations page, plus the moderation API group and the Devii moderation actions. Compliance record: applecomp.md is the requirement register, applechanges.md the gap analysis against this codebase, and appleimpl.md the implementation design they resolve to. Tests cover the report flow, admin moderation, consent, account deletion, terms acceptance, workspaces, and the registry invariant across the unit, api, and e2e tiers.
2026-08-09 00:18:20 +02:00
"terms_version": "1",
"email": f"{username}@t.dev",
"created_at": datetime.now(timezone.utc).isoformat(),
}
)
item_uid = generate_uid()
items = [
{
"uid": item_uid,
"user_uid": uid,
"created_at": datetime.now(timezone.utc).isoformat(),
}
]
authors = get_users_by_uids([uid])
enriched = enrich_items(
items,
"post",
authors,
extra_maps={"comment_count": {item_uid: 4}, "flag": lambda item: "ok"},
)
entry = enriched[0]
assert entry["post"] is items[0]
assert entry["author"]["username"] == username
assert entry["time_ago"] == "just now"
assert entry["my_vote"] == 0
assert entry["comment_count"] == 4
assert entry["flag"] == "ok"
def test_readonly_action_requires_confirmation():
assert confirmation_error("project_set_readonly", {}) is not None
assert confirmation_error("project_set_readonly", {"confirm": "false"}) is not None
assert confirmation_error("project_set_readonly", {"confirm": "true"}) is None
def test_private_action_requires_confirmation():
assert confirmation_error("project_set_private", {"value": "true"}) is not None
assert confirmation_error("project_set_private", {"value": "true", "confirm": "true"}) is None
assert confirmation_error("vote", {}) is None
def test_is_confirmed_accepts_common_truthy():
assert _is_confirmed({"confirm": True})
assert _is_confirmed({"confirm": "yes"})
assert not _is_confirmed({"confirm": ""})
assert not _is_confirmed({})
def test_delete_actions_require_confirmation():
assert confirmation_error("project_delete_file", {"path": "a.py"}) is not None
assert confirmation_error("project_delete_file", {"path": "a.py", "confirm": "true"}) is None
assert confirmation_error("delete_project", {"project_slug": "p"}) is not None
assert confirmation_error("delete_project", {"project_slug": "p", "confirm": "true"}) is None
def test_container_delete_requires_confirmation_but_not_other_actions():
assert confirmation_error("container_instance_action", {"action": "delete"}) is not None
assert confirmation_error("container_instance_action", {"action": "restart"}) is None
assert confirmation_error("container_instance_action", {"action": "start"}) is None
def test_destructive_container_exec_requires_confirmation():
assert confirmation_error("container_exec", {"command": "rm -f /app/cms/cms.db"}) is not None
assert confirmation_error("container_exec", {"command": "sudo rm -rf /app"}) is not None
assert confirmation_error("container_exec", {"command": "find . -delete"}) is not None
assert confirmation_error("container_exec", {"command": "echo x > /etc/hosts"}) is not None
assert (
confirmation_error("container_exec", {"command": "rm -rf /app", "confirm": "true"})
is None
)
def test_benign_container_exec_runs_without_confirmation():
assert confirmation_error("container_exec", {"command": "pip install requests"}) is None
assert confirmation_error("container_exec", {"command": "ls -la /app"}) is None
assert confirmation_error("container_exec", {"command": "grep -rm 5 foo ."}) is None