Skip to content

Commit

Permalink
fix: Audit Log integrations are triggered when integration config is …
Browse files Browse the repository at this point in the history
…soft deleted (#5128)
  • Loading branch information
khvn26 authored Feb 18, 2025
1 parent e7b1adc commit a81d22e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 12 deletions.
40 changes: 28 additions & 12 deletions api/audit/signals.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import typing

from django.conf import settings
from django.db.models.signals import post_save
Expand All @@ -18,6 +19,33 @@
logger = logging.getLogger(__name__)


AuditLogIntegrationAttrName = typing.Literal[
"data_dog_config",
"dynatrace_config",
"grafana_config",
"new_relic_config",
"slack_config",
]


def _get_integration_config(
instance: AuditLog,
integration_name: AuditLogIntegrationAttrName,
) -> IntegrationsModel | None:
for relation_name in ("project", "environment", "organisation"):
if hasattr(
related_object := getattr(instance, relation_name),
integration_name,
):
integration_config: IntegrationsModel = getattr(
related_object,
integration_name,
)
if not integration_config.deleted:
return integration_config
return None


@receiver(post_save, sender=AuditLog)
def call_webhooks(sender, instance, **kwargs): # type: ignore[no-untyped-def]
if settings.DISABLE_WEBHOOKS:
Expand All @@ -42,18 +70,6 @@ def call_webhooks(sender, instance, **kwargs): # type: ignore[no-untyped-def]
)


def _get_integration_config(
instance: AuditLog, integration_name: str
) -> IntegrationsModel | None:
if hasattr(project := instance.project, integration_name):
return getattr(project, integration_name) # type: ignore[no-any-return]
if hasattr(environment := instance.environment, integration_name):
return getattr(environment, integration_name) # type: ignore[no-any-return]
if hasattr(organisation := instance.organisation, integration_name):
return getattr(organisation, integration_name) # type: ignore[no-any-return]
return None


def track_only_feature_related_events(signal_function): # type: ignore[no-untyped-def]
def signal_wrapper(sender, instance, **kwargs): # type: ignore[no-untyped-def]
# Only handle Feature related changes
Expand Down
26 changes: 26 additions & 0 deletions api/tests/unit/audit/test_unit_audit_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,32 @@ def test_send_audit_log_event_to_grafana__organisation_grafana_config__calls_exp
)


def test_send_audit_log_event_to_grafana__organisation_grafana_config__deleted__doesnt_call(
mocker: MockerFixture,
organisation: Organisation,
project: Project,
) -> None:
# Given
audit_log_record = AuditLog.objects.create(
project=project,
related_object_type=RelatedObjectType.FEATURE.name,
)
grafana_wrapper_mock = mocker.patch("audit.signals.GrafanaWrapper", autospec=True)

grafana_config = GrafanaOrganisationConfiguration.objects.create(
organisation=organisation,
base_url="test.com",
api_key="test",
)
grafana_config.delete()

# When
send_audit_log_event_to_grafana(AuditLog, audit_log_record)

# Then
grafana_wrapper_mock.assert_not_called()


@responses.activate
def test_send_environment_feature_version_audit_log_event_to_grafana(
tagged_feature: Feature,
Expand Down

0 comments on commit a81d22e

Please sign in to comment.