feat: replace inline IP resolution with centralized client_ip utility across routers and audit

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:
2026-07-04 18:07:33 +00:00
parent 244a524b91
commit 3fbac87723
14 changed files with 266 additions and 36 deletions
+99
View File
@@ -0,0 +1,99 @@
# retoor <retoor@molodetz.nl>
import time
import pytest
import requests
from tests.conftest import BASE_URL
from devplacepy.database import get_table, refresh_snapshot
JSON_analytics = {"Accept": "application/json"}
_counter_analytics = [0]
def _db_user(name):
refresh_snapshot()
return get_table("users").find_one(username=name)
def _unique(prefix="an"):
_counter_analytics[0] += 1
return f"{prefix}{int(time.time() * 1000)}{_counter_analytics[0]}"
def _member_key():
name = _unique("anmem")
requests.post(
f"{BASE_URL}/auth/signup",
data={
"username": name,
"email": f"{name}@t.dev",
"password": "secret123",
"confirm_password": "secret123",
},
allow_redirects=True,
)
return _db_user(name)["api_key"]
def _admin_key(seeded_db):
return _db_user("alice_test")["api_key"]
def test_analytics_guest_denied(seeded_db):
assert (
requests.get(
f"{BASE_URL}/admin/analytics", headers=JSON_analytics, allow_redirects=False
).status_code
== 401
)
assert (
requests.get(f"{BASE_URL}/admin/analytics", allow_redirects=False).status_code
== 303
)
def test_analytics_member_denied(seeded_db):
key = _member_key()
assert (
requests.get(
f"{BASE_URL}/admin/analytics",
headers={**JSON_analytics, "X-API-KEY": key},
allow_redirects=False,
).status_code
== 403
)
def test_analytics_admin_ok(seeded_db):
key = _admin_key(seeded_db)
r = requests.get(
f"{BASE_URL}/admin/analytics", headers={**JSON_analytics, "X-API-KEY": key}
)
assert r.status_code == 200
assert isinstance(r.json(), dict)
def test_analytics_denial_is_audited(seeded_db):
key = _member_key()
requests.get(
f"{BASE_URL}/admin/analytics",
headers={**JSON_analytics, "X-API-KEY": key},
allow_redirects=False,
)
admin_key = _admin_key(seeded_db)
hit = False
for _ in range(20):
data = requests.get(
f"{BASE_URL}/admin/audit-log",
headers={**JSON_analytics, "X-API-KEY": admin_key},
params={"event_key": "security.authz.denied"},
).json()
hit = any(
"/admin/analytics" in (entry.get("summary") or "")
or "/admin/analytics" in (entry.get("request_path") or "")
for entry in data["entries"]
)
if hit:
break
time.sleep(0.25)
assert hit, "expected a security.authz.denied audit row for /admin/analytics"
@@ -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"