feat: replace inline IP resolution with centralized client_ip utility across routers and audit
DevPlace CI / test (push) Failing after 36m45s
DevPlace CI / test (push) Failing after 36m45s
Consolidate scattered `X-Real-IP` / `request.client.host` fallback logic into the single `client_ip()` helper from `utils`, reducing duplication in the rate limiter middleware, project file zip routes, tools shared module, and audit record builder. Also refactor three admin endpoints (`/ai-usage/data`, `/analytics`, `/users/{uid}/ai-usage`) to use the existing `require_admin()` guard instead of repeating manual auth checks, and remove now-unused `get_current_user`/`is_admin` imports from those modules.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import json
|
||||
|
||||
from tests.conftest import run_async
|
||||
from devplacepy.services.devii.actions.catalog import PLATFORM_CATALOG
|
||||
from devplacepy.services.devii.actions.dispatcher import Dispatcher
|
||||
|
||||
|
||||
class _Recorder:
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
|
||||
def record_system(self, event_key, **kwargs):
|
||||
self.calls.append((event_key, kwargs))
|
||||
return "rec"
|
||||
|
||||
|
||||
class _FakeClient:
|
||||
def __init__(self, authenticated=True):
|
||||
self.authenticated = authenticated
|
||||
self.username = "voidwalker"
|
||||
|
||||
|
||||
def _bare_dispatcher(owner_kind, owner_id, *, is_admin=False, is_primary_admin=False):
|
||||
dispatcher = Dispatcher.__new__(Dispatcher)
|
||||
dispatcher._actions = PLATFORM_CATALOG.by_name()
|
||||
dispatcher._virtual_tools = None
|
||||
dispatcher._client = _FakeClient(authenticated=True)
|
||||
dispatcher._is_admin = is_admin
|
||||
dispatcher._is_primary_admin = is_primary_admin
|
||||
dispatcher._owner_kind = owner_kind
|
||||
dispatcher._owner_id = owner_id
|
||||
return dispatcher
|
||||
|
||||
|
||||
def _patch_recorder(monkeypatch):
|
||||
from devplacepy.services.audit import record as audit_record
|
||||
|
||||
recorder = _Recorder()
|
||||
monkeypatch.setattr(audit_record, "record_system", recorder.record_system)
|
||||
return recorder
|
||||
|
||||
|
||||
def test_admin_tool_denied_for_member_is_audited(monkeypatch):
|
||||
recorder = _patch_recorder(monkeypatch)
|
||||
dispatcher = _bare_dispatcher("user", "member-uid-123", is_admin=False)
|
||||
|
||||
result = run_async(
|
||||
dispatcher.dispatch(
|
||||
"admin_set_user_role", {"username": "voidwalker", "role": "Admin"}
|
||||
)
|
||||
)
|
||||
|
||||
assert json.loads(result)["error"] == "auth_required"
|
||||
assert len(recorder.calls) == 1
|
||||
event_key, kwargs = recorder.calls[0]
|
||||
assert event_key == "security.authz.denied"
|
||||
assert kwargs["origin"] == "devii"
|
||||
assert kwargs["via_agent"] == 1
|
||||
assert kwargs["result"] == "denied"
|
||||
assert kwargs["actor_kind"] == "user"
|
||||
assert kwargs["actor_uid"] == "member-uid-123"
|
||||
assert kwargs["actor_role"] == "member"
|
||||
assert kwargs["metadata"]["tool"] == "admin_set_user_role"
|
||||
|
||||
|
||||
def test_admin_tool_denied_for_guest_actor_shape(monkeypatch):
|
||||
recorder = _patch_recorder(monkeypatch)
|
||||
dispatcher = _bare_dispatcher("guest", "cookie-abc", is_admin=False)
|
||||
|
||||
run_async(dispatcher.dispatch("admin_list_users", {}))
|
||||
|
||||
assert len(recorder.calls) == 1
|
||||
_, kwargs = recorder.calls[0]
|
||||
assert kwargs["actor_kind"] == "guest"
|
||||
assert kwargs["actor_uid"] is None
|
||||
assert kwargs["actor_role"] == "guest"
|
||||
|
||||
|
||||
def test_admin_tool_allowed_for_admin_is_not_denial_audited(monkeypatch):
|
||||
recorder = _patch_recorder(monkeypatch)
|
||||
dispatcher = _bare_dispatcher("user", "admin-uid-9", is_admin=True)
|
||||
|
||||
run_async(dispatcher.dispatch("admin_list_users", {}))
|
||||
|
||||
assert all(call[0] != "security.authz.denied" for call in recorder.calls)
|
||||
|
||||
|
||||
def test_primary_admin_tool_denied_for_regular_admin_is_audited(monkeypatch):
|
||||
recorder = _patch_recorder(monkeypatch)
|
||||
dispatcher = _bare_dispatcher(
|
||||
"user", "admin-uid-9", is_admin=True, is_primary_admin=False
|
||||
)
|
||||
|
||||
result = run_async(dispatcher.dispatch("db_list_tables", {}))
|
||||
|
||||
assert json.loads(result)["error"] == "auth_required"
|
||||
assert len(recorder.calls) == 1
|
||||
event_key, kwargs = recorder.calls[0]
|
||||
assert event_key == "security.authz.denied"
|
||||
assert kwargs["metadata"]["tool"] == "db_list_tables"
|
||||
assert kwargs["actor_role"] == "admin"
|
||||
Reference in New Issue
Block a user