fix: tighten API P0 auth and route handling
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
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')
|
||||
|
||||
assert captured['key'] == 'anon-key'
|
||||
assert captured['options'].headers['apikey'] == 'anon-key'
|
||||
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',
|
||||
'[email protected]',
|
||||
)
|
||||
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',
|
||||
'[email protected]',
|
||||
)
|
||||
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
graph_tree_router._require_allowed_neo4j_db(
|
||||
'classroomcopilot',
|
||||
'School',
|
||||
'school',
|
||||
'user-1',
|
||||
'[email protected]',
|
||||
)
|
||||
assert exc.value.status_code == 403
|
||||
Reference in New Issue
Block a user