soulsync/tests/test_verification_admin_gate.py
BoulderBadgeDad 17440329c1 #845 follow-up: admin-gate the mutating verification-review endpoints
The merged PR left the review-queue's mutating endpoints ungated. Both now require
admin, matching the Phase 3 destructive-endpoint convention:

- /api/verification/<id>/delete (os.remove + drops the history row) — @admin_only,
  so a non-admin on a login/multi-profile instance can't delete library files.
- /api/verification/<id>/approve (flips verification_status + writes the tag) —
  @admin_only; also wrapped its DB writes in `with db._get_connection()` for
  rollback-on-error + codebase consistency (was a bare conn).

Read/playback endpoints (stream/play/compare/entry/config) stay open — the app's
LAN-read model. Tests: non-admin gets 403 on delete + approve; admin isn't blocked.
2026-06-11 10:43:40 -07:00

45 lines
1.4 KiB
Python

"""#845 follow-up: the mutating verification-review endpoints (delete removes a
file from disk; approve flips verification state) must be admin-only, matching the
Phase 3 destructive-endpoint gating. The read/playback ones stay open."""
from __future__ import annotations
import os
import tempfile
import pytest
_TMP = tempfile.mkdtemp(prefix='soulsync-testdb-vgate-')
os.environ['DATABASE_PATH'] = os.path.join(_TMP, 'v.db')
os.environ['SOULSYNC_TEST_DB_READY'] = '1'
web_server = pytest.importorskip('web_server')
@pytest.fixture
def client():
return web_server.app.test_client()
def _as_nonadmin(client):
pid = web_server.get_database().create_profile(name=f'u_{os.urandom(4).hex()}')
with client.session_transaction() as s:
s['profile_id'] = pid
return pid
def test_delete_is_admin_only(client):
_as_nonadmin(client)
assert client.post('/api/verification/1/delete').status_code == 403
def test_approve_is_admin_only(client):
_as_nonadmin(client)
assert client.post('/api/verification/1/approve').status_code == 403
def test_admin_not_blocked(client):
# default session resolves to admin (profile 1) — must pass the gate (a
# missing history id yields 404, NOT 403).
assert client.post('/api/verification/999999/delete').status_code != 403
assert client.post('/api/verification/999999/approve').status_code != 403