Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled
The previous commit added apikey to _create_base_client headers, but supabase-py already sets apikey from the key arg → two apikey headers → Kong rejected every as-user call with 401 'Duplicate API key found' (exam API 502'd on auth). Revert to Authorization-only; fix the two header unit tests to assert the real contract (apikey via the key arg; options.headers carries only the user Authorization). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
110 lines
3.7 KiB
Python
110 lines
3.7 KiB
Python
import pytest
|
|
from fastapi import HTTPException
|
|
|
|
|
|
def test_classes_school_students_route_registered_before_dynamic_class_id():
|
|
from routers.database.tools.classes_router import router
|
|
|
|
paths = [route.path for route in router.routes]
|
|
assert paths.index('/school/students') < paths.index('/{class_id}')
|
|
|
|
|
|
def test_supabase_anon_for_user_sets_user_authorization_header(monkeypatch):
|
|
from modules.database.supabase.utils import client as client_module
|
|
|
|
captured = {}
|
|
|
|
def fake_create_client(url, key, options=None):
|
|
captured['url'] = url
|
|
captured['key'] = key
|
|
captured['options'] = options
|
|
return object()
|
|
|
|
monkeypatch.setenv('SUPABASE_URL', 'http://supabase.test')
|
|
monkeypatch.setenv('ANON_KEY', 'anon-key')
|
|
monkeypatch.setattr(client_module, 'create_client', fake_create_client)
|
|
|
|
client_module.SupabaseAnonClient.for_user('Bearer user-jwt')
|
|
|
|
# apikey comes from the `key` arg (supabase-py sets the apikey header); options.headers must
|
|
# carry only the user Authorization override. A second apikey here → Kong "Duplicate API key".
|
|
assert captured['key'] == 'anon-key'
|
|
assert 'apikey' not in captured['options'].headers
|
|
assert captured['options'].headers['Authorization'] == 'Bearer user-jwt'
|
|
|
|
|
|
@pytest.mark.parametrize('token', ['', ' '])
|
|
def test_supabase_anon_for_user_requires_token(token):
|
|
from modules.database.supabase.utils.client import SupabaseAnonClient
|
|
|
|
with pytest.raises(ValueError):
|
|
SupabaseAnonClient.for_user(token)
|
|
|
|
|
|
def test_tldraw_malformed_snapshot_falls_back_to_default():
|
|
from routers.database.tools import tldraw_supabase_storage as storage
|
|
|
|
assert not storage._is_valid_tldraw_snapshot({'document': {}, 'session': {}})
|
|
default = storage.create_default_tldraw_content()
|
|
assert storage._is_valid_tldraw_snapshot(default)
|
|
assert default['document']['schema']['schemaVersion'] == 2
|
|
|
|
|
|
def test_tldraw_rejects_cross_tenant_snapshot_db(monkeypatch):
|
|
from routers.database.tools import tldraw_supabase_storage as storage
|
|
|
|
monkeypatch.setattr(storage, '_user_scope', lambda user_id: {
|
|
'user_id': user_id,
|
|
'teacher_db': f"cc.users.teacher.{user_id.replace('-', '')}",
|
|
'institute_id': 'school-1',
|
|
'institute_db': 'cc.institutes.allowed',
|
|
'curriculum_db': 'cc.institutes.allowed.curriculum',
|
|
})
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
storage._authorize_snapshot_path(
|
|
'cc.public.snapshots/School/other-school',
|
|
'cc.institutes.other',
|
|
{'sub': 'user-1'},
|
|
write=False,
|
|
)
|
|
assert exc.value.status_code == 403
|
|
|
|
|
|
def test_graph_node_children_rejects_unscoped_db(monkeypatch):
|
|
from routers.database.tools import graph_tree_router
|
|
|
|
monkeypatch.setattr(graph_tree_router, '_allowed_neo4j_dbs', lambda user_id, email: {'cc.users.teacher.user1'})
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
graph_tree_router._require_allowed_neo4j_db(
|
|
'cc.institutes.not-mine',
|
|
'SubjectClass',
|
|
'classes',
|
|
'user-1',
|
|
'teacher@example.test',
|
|
)
|
|
assert exc.value.status_code == 403
|
|
|
|
|
|
def test_graph_node_children_allows_global_calendar_only():
|
|
from routers.database.tools import graph_tree_router
|
|
|
|
graph_tree_router._require_allowed_neo4j_db(
|
|
'classroomcopilot',
|
|
'CalendarYear',
|
|
'',
|
|
'user-1',
|
|
'teacher@example.test',
|
|
)
|
|
|
|
with pytest.raises(HTTPException) as exc:
|
|
graph_tree_router._require_allowed_neo4j_db(
|
|
'classroomcopilot',
|
|
'School',
|
|
'school',
|
|
'user-1',
|
|
'teacher@example.test',
|
|
)
|
|
assert exc.value.status_code == 403
|