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

198 lines
7.4 KiB
Python

from contextlib import contextmanager
from unittest import mock
import pytest
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.db import transaction
from django.dispatch import receiver
from django.test import override_settings
from rest_framework.test import APIClient
from infrasynth.audit.models import ModelChangeLog, SecurityEvent
from infrasynth.audit.signals import security_event_occurred
from infrasynth.features.models import FeatureFlag, FeatureFlagOverride
from infrasynth.features.registry import FeatureRegistry
from infrasynth.features.services import FeatureService
from infrasynth.security.models import Grant, Revoke, Role
from infrasynth.security.services import AuthorizationService
from infrasynth.webhooks.models import (
OutboundDelivery,
OutboundEndpoint,
OutboundSubscription,
)
from infrasynth.webhooks.registry import EventRegistry
from infrasynth.webhooks.signals import outbound_delivery_succeeded
UserModel = get_user_model()
pytestmark = pytest.mark.django_db
@contextmanager
def _emit_and_run_commit_hooks():
with transaction.atomic():
yield
connection = transaction.get_connection()
pending = list(connection.run_on_commit)
connection.run_on_commit = []
for entry in pending:
func = entry[1]
func()
@override_settings(CELERY_TASK_ALWAYS_EAGER=True)
def test_e2e_login_permission_feature_webhook_audit(user, clean_feature_registry):
authz = AuthorizationService()
fs = FeatureService()
# a. Force-authenticate the user and verify the session check endpoint
client = APIClient()
client.force_authenticate(user=user)
resp = client.get("/api/auth/check/")
assert resp.status_code == 200
assert resp.json()["id"] == user.pk
# b. Create Role with specific permissions and assign to user
role = Role.objects.create(
name="Webhook Manager",
slug="webhook-manager",
permissions=["webhooks.manage_endpoints"],
)
role.users.add(user)
# c. Create Grant for an additional permission
Grant.objects.create(user=user, codename="audit.view_logs")
# d. Verify permission resolution via AuthorizationService
assert authz.has_permission(user, "webhooks.manage_endpoints") is True
assert authz.has_permission(user, "audit.view_logs") is True
assert authz.has_permission(user, "unknown.perm") is False
# e. Feature flag registration and DB gating
FeatureRegistry.register("e2e.beta", default=True, name="E2E Beta")
FeatureFlag.objects.create(slug="e2e.beta", is_active=True)
cache.clear()
assert fs.is_enabled("e2e.beta", user=user) is True
assert fs.is_enabled("unknown.feature", user=user) is False
# f. Register event, create outbound endpoint + subscription
EventRegistry.register(
"e2e.test.event",
description="E2E test event",
example_payload={"test_key": "test_value"},
)
endpoint = OutboundEndpoint.objects.create(
name="E2E Target",
url="https://example.com/e2e-hook",
secret="e2e-secret",
)
sub = OutboundSubscription.objects.create(
endpoint=endpoint,
event_name="e2e.test.event",
)
# Connect receiver bridge: outbound_delivery_succeeded -> SecurityEvent
@receiver(outbound_delivery_succeeded)
def bridge_create_audit_event(sender, **kwargs):
security_event_occurred.send(
sender=OutboundDelivery,
event_type="webhook_delivered",
actor=user,
metadata={
"delivery_id": kwargs.get("delivery_id"),
"event_name": kwargs.get("event_name"),
"status_code": kwargs.get("status_code"),
},
)
payload = {"test_key": "test_value"}
with mock.patch("infrasynth.webhooks.dispatch.requests.post") as mock_post:
mock_post.return_value.status_code = 200
mock_post.return_value.text = "ok"
with _emit_and_run_commit_hooks():
EventRegistry.emit("e2e.test.event", payload)
# g. Verify OutboundDelivery was created via Celery eager delivery
assert OutboundDelivery.objects.filter(subscription=sub).exists()
delivery = OutboundDelivery.objects.get(subscription=sub)
assert delivery.status == OutboundDelivery.Status.SUCCESS
assert delivery.payload is not None
assert delivery.response_status == 200
# h. Verify SecurityEvent was created by the signal bridge
assert SecurityEvent.objects.filter(event_type="webhook_delivered").exists()
se = SecurityEvent.objects.get(event_type="webhook_delivered")
assert se.actor == user
assert se.metadata["delivery_id"] == delivery.id
assert se.metadata["event_name"] == "e2e.test.event"
assert se.metadata["status_code"] == 200
# i. Verify ModelChangeLog entries exist for the created models
labels = set(ModelChangeLog.objects.values_list("model_label", flat=True))
expected_labels = [
"infrasynth_security.Role",
"infrasynth_security.Grant",
"infrasynth_webhooks.OutboundEndpoint",
"infrasynth_webhooks.OutboundSubscription",
"infrasynth_webhooks.OutboundDelivery",
]
for label in expected_labels:
assert label in labels, f"Missing ModelChangeLog for {label}"
outbound_delivery_succeeded.disconnect(bridge_create_audit_event)
def test_e2e_permission_chain_resolution(user, admin_user):
authz = AuthorizationService()
# a. Create role + grant + revoke for the same user
role = Role.objects.create(
name="Tester",
slug="tester",
permissions=["perm.role_a", "perm.role_b"],
)
role.users.add(user)
Grant.objects.create(user=user, codename="perm.grant_c")
Revoke.objects.create(user=user, codename="perm.role_a")
# b. Verify Revoke > Grant > Role > Default precedence
assert authz.has_permission(user, "perm.role_a") is False
assert authz.has_permission(user, "perm.role_b") is True
assert authz.has_permission(user, "perm.grant_c") is True
assert authz.has_permission(user, "perm.default") is False
# c. Verify superuser gets ["*"] wildcard
assert authz.has_permission(admin_user, "anything.at.all") is True
assert authz.get_effective_permissions(admin_user) == {"*"}
# d. Verify get_effective_permissions returns union minus revokes
perms = authz.get_effective_permissions(user)
assert "perm.role_a" not in perms
assert "perm.role_b" in perms
assert "perm.grant_c" in perms
assert len(perms) == 2
def test_e2e_feature_flag_with_user_override(user, clean_feature_registry):
fs = FeatureService()
# a. Register feature in registry (default True)
FeatureRegistry.register("e2e.feature", default=True)
assert fs.is_enabled("e2e.feature") is True
# b. Create DB FeatureFlag (is_active=False) — overrides registry default
flag = FeatureFlag.objects.create(slug="e2e.feature", is_active=False)
cache.clear()
assert fs.is_enabled("e2e.feature") is False
# c. Create FeatureFlagOverride for the specific user (is_enabled=True)
FeatureFlagOverride.objects.create(flag=flag, user=user, is_enabled=True)
assert fs.is_enabled("e2e.feature", user=user) is True
# d. Verify the override is user-specific
other_user = UserModel.objects.create_user(
username="other",
email="other@example.com",
password="pass123",
)
assert fs.is_enabled("e2e.feature", user=other_user) is False