infrasynth-backend-kit/tests/test_audit/test_middleware.py
2026-08-28 14:38:47 -05:00

147 lines
5.4 KiB
Python

import json
import pytest
from django.conf import settings
from django.http import JsonResponse
from django.test import RequestFactory, override_settings
from rest_framework.response import Response
from infrasynth.audit.middleware import AuditAPIMiddleware
from infrasynth.audit.models import APIInteractionLog
def audit_config(**overrides):
return {**settings.INFRASYNTH_AUDIT, **overrides}
@pytest.fixture
def middleware():
return AuditAPIMiddleware(get_response=lambda request: None)
def run_request(middleware, request, response):
middleware.process_request(request)
return middleware.process_response(request, response)
class TestAPILogging:
def test_logs_api_interaction(self, middleware, db):
request = RequestFactory().get("/api/features/active/")
response = JsonResponse({"ok": True})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/features/active/")
assert log.method == "GET"
assert log.status_code == 200
assert log.request_id
assert log.duration_ms >= 0
def test_logs_request_body(self, middleware, db):
request = RequestFactory().post(
"/api/auth/login/",
data=json.dumps({"username": "a@b.com"}),
content_type="application/json",
)
response = JsonResponse({"detail": "ok"})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/auth/login/")
assert log.request_body == {"username": "a@b.com"}
def test_logs_response_body(self, middleware, db):
request = RequestFactory().get("/api/audit/changes/")
response = Response({"count": 3, "results": []})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/audit/changes/")
assert log.response_body == {"count": 3, "results": []}
def test_captures_ip_and_user_agent(self, middleware, db):
request = RequestFactory().get("/api/audit/changes/", HTTP_USER_AGENT="pytest-agent", REMOTE_ADDR="10.0.0.5")
response = JsonResponse({})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/audit/changes/")
assert log.ip_address == "10.0.0.5"
assert log.user_agent == "pytest-agent"
class TestSensitiveData:
def test_sensitive_request_body_not_stored(self, middleware, db):
request = RequestFactory().post(
"/api/auth/login/",
data=json.dumps({"username": "a@b.com", "password": "supersecret"}),
content_type="application/json",
)
response = JsonResponse({})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/auth/login/")
assert log.request_body is None
@override_settings(INFRASYNTH_AUDIT=audit_config(SENSITIVE_KEYS=["password", "my_secret"]))
def test_custom_sensitive_keys(self, db):
middleware = AuditAPIMiddleware(get_response=lambda request: None)
request = RequestFactory().post(
"/api/test/",
data=json.dumps({"my_secret": "abc", "other": 1}),
content_type="application/json",
)
response = JsonResponse({})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/test/")
assert log.request_body is None
class TestConfiguration:
def test_admin_path_not_logged(self, middleware, db):
request = RequestFactory().get("/admin/auth/user/")
response = JsonResponse({})
run_request(middleware, request, response)
assert not APIInteractionLog.objects.filter(path="/admin/auth/user/").exists()
@override_settings(INFRASYNTH_AUDIT=audit_config(ENABLE_API_LOGGING=False))
def test_api_logging_disabled(self, db):
middleware = AuditAPIMiddleware(get_response=lambda request: None)
request = RequestFactory().get("/api/features/active/")
response = JsonResponse({})
run_request(middleware, request, response)
assert not APIInteractionLog.objects.exists()
@override_settings(INFRASYNTH_AUDIT=audit_config(MAX_BODY_SIZE_BYTES=10))
def test_large_body_truncated(self, db):
middleware = AuditAPIMiddleware(get_response=lambda request: None)
big_payload = {"data": "x" * 100}
request = RequestFactory().post(
"/api/test/",
data=json.dumps(big_payload),
content_type="application/json",
)
response = JsonResponse({})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/test/")
assert log.request_body is None
class TestActorCapture:
def test_captures_authenticated_actor(self, middleware, db, user):
request = RequestFactory().get("/api/audit/changes/")
request.user = user
response = JsonResponse({})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/audit/changes/")
assert log.actor == user
def test_anonymous_actor_null(self, middleware, db, user):
request = RequestFactory().get("/api/audit/changes/")
request.user = type("AnonUser", (), {"is_authenticated": False})()
response = JsonResponse({})
run_request(middleware, request, response)
log = APIInteractionLog.objects.get(path="/api/audit/changes/")
assert log.actor is None