Skip to content

Commit 403838b

Browse files
committed
decouple notification from the rules
Signed-off-by: tdruez <tdruez@aboutcode.org>
1 parent 8055350 commit 403838b

7 files changed

Lines changed: 10 additions & 80 deletions

File tree

policy/admin.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def download_license_dump_view(self, request):
167167
@admin.register(PolicyRule, site=dejacode_site)
168168
class PolicyRuleAdmin(DataspacedAdmin):
169169
form = PolicyRuleForm
170-
list_display = ("name", "rule_type", "threshold", "is_active", "event_name", "get_dataspace")
170+
list_display = ("name", "rule_type", "threshold", "is_active", "get_dataspace")
171171
list_filter = DataspacedAdmin.list_filter + ("rule_type", "is_active")
172172
readonly_fields = DataspacedAdmin.readonly_fields + ("parameters_schema_hint",)
173173
activity_log = False
@@ -183,11 +183,9 @@ class PolicyRuleAdmin(DataspacedAdmin):
183183
long_description = linebreaksbr(
184184
"A Policy Rule defines a type of automated check to run against your products. "
185185
"When the number of detected issues exceeds the configured threshold, a "
186-
"ProductPolicyViolation is recorded and an optional notification event is fired.\n"
187-
"Set the rule type to match a registered evaluation handler, configure the "
188-
"threshold (0 means any violation triggers the rule), and select a notification "
189-
"event to dispatch alerts across all registered channels when violations are "
190-
"detected or resolved."
186+
"ProductPolicyViolation is recorded.\n"
187+
"Set the rule type to match a registered evaluation handler and configure the "
188+
"threshold (0 means any violation triggers the rule). "
191189
)
192190

193191
def parameters_schema_hint(self, obj):

policy/engine.py

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from django.utils import timezone
1010

11-
from policy.events import fire_event
1211
from policy.models import PolicyRule
1312
from policy.rules import RULE_REGISTRY
1413
from product_portfolio.models import ProductPolicyViolation
@@ -17,13 +16,12 @@
1716
def evaluate_rule(policy_rule, product):
1817
"""
1918
Evaluate a single PolicyRule against a product, create or update the
20-
ProductPolicyViolation record, and fire the notification event on new violations
21-
or resolutions.
19+
ProductPolicyViolation record.
2220
Returns the ProductPolicyViolation instance, or None if no violation exists.
2321
"""
2422
rule_handler = RULE_REGISTRY.get(policy_rule.rule_type)
2523
if not rule_handler:
26-
return None
24+
return
2725

2826
violation_count = rule_handler.count_violations(policy_rule, product)
2927

@@ -37,17 +35,13 @@ def evaluate_rule(policy_rule, product):
3735
if not created:
3836
violation.violation_count = violation_count
3937
violation.save()
40-
if created and policy_rule.event_name:
41-
fire_violation_event(policy_rule, product, violation_count)
4238
return violation
4339
else:
44-
resolved_count = ProductPolicyViolation.objects.filter(**lookup).update(
40+
ProductPolicyViolation.objects.filter(**lookup).update(
4541
resolved=True,
4642
resolved_date=timezone.now(),
4743
)
48-
if resolved_count and policy_rule.event_name:
49-
fire_resolution_event(policy_rule, product)
50-
return None
44+
return
5145

5246

5347
def evaluate_rules(product):
@@ -62,28 +56,3 @@ def evaluate_rules(product):
6256
violations.append(violation)
6357

6458
return violations
65-
66-
67-
def fire_violation_event(policy_rule, product, violation_count):
68-
fire_event(
69-
policy_rule.event_name,
70-
dataspace=policy_rule.dataspace,
71-
payload={
72-
"rule": policy_rule.name,
73-
"rule_type": policy_rule.rule_type,
74-
"violation_count": violation_count,
75-
"product": str(product),
76-
},
77-
)
78-
79-
80-
def fire_resolution_event(policy_rule, product):
81-
fire_event(
82-
policy_rule.event_name,
83-
dataspace=policy_rule.dataspace,
84-
payload={
85-
"rule": policy_rule.name,
86-
"status": "resolved",
87-
"product": str(product),
88-
},
89-
)

policy/events.py

Lines changed: 0 additions & 20 deletions
This file was deleted.

policy/forms.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88

99
from django import forms
1010
from django.contrib.contenttypes.models import ContentType
11-
from django.db.models import BLANK_CHOICE_DASH
1211

1312
from dje.forms import ColorCodeFormMixin
1413
from dje.forms import DataspacedAdminForm
15-
from policy.events import POLICY_EVENTS
1614
from policy.models import PolicyRule
1715
from policy.rules import RULE_REGISTRY
1816

@@ -108,18 +106,9 @@ def __init__(self, *args, **kwargs):
108106
self.fields["rule_type"].widget = forms.Select(
109107
choices=[(key, handler.label) for key, handler in RULE_REGISTRY.items()]
110108
)
111-
self.fields["event_name"].widget = forms.Select(
112-
choices=BLANK_CHOICE_DASH + list(POLICY_EVENTS.items())
113-
)
114109

115110
def clean_rule_type(self):
116111
value = self.cleaned_data["rule_type"]
117112
if value not in RULE_REGISTRY:
118113
raise forms.ValidationError(f"Unknown rule type: {value}")
119114
return value
120-
121-
def clean_event_name(self):
122-
value = self.cleaned_data.get("event_name")
123-
if value and value not in POLICY_EVENTS:
124-
raise forms.ValidationError(f"Unknown event: {value}")
125-
return value

policy/migrations/0003_policyrule.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generated by Django 6.0.6 on 2026-07-07 04:49
1+
# Generated by Django 6.0.6 on 2026-07-08 08:39
22

33
import django.db.models.deletion
44
import dje.models
@@ -23,7 +23,6 @@ class Migration(migrations.Migration):
2323
('rule_type', models.CharField(help_text='The type of evaluation performed by this rule.', max_length=50)),
2424
('threshold', models.PositiveIntegerField(default=0, help_text='Minimum number of violations required to trigger this rule (0 means any).')),
2525
('is_active', models.BooleanField(default=True, help_text='Only active rules are evaluated.')),
26-
('event_name', models.CharField(blank=True, help_text='Notification event to fire when violations are detected.', max_length=100)),
2726
('parameters', models.JSONField(blank=True, default=dict, help_text='Optional rule-specific parameters as a JSON object. Supported keys depend on the chosen rule type.')),
2827
('dataspace', models.ForeignKey(editable=False, help_text='A Dataspace is an independent, exclusive set of DejaCode data, which can be either nexB master reference data or installation-specific data.', on_delete=django.db.models.deletion.PROTECT, to='dje.dataspace')),
2928
],

policy/models.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,6 @@ class PolicyRule(DataspacedModel):
268268
default=True,
269269
help_text=_("Only active rules are evaluated."),
270270
)
271-
event_name = models.CharField(
272-
max_length=100,
273-
blank=True,
274-
help_text=_("Notification event to fire when violations are detected."),
275-
)
276271
parameters = models.JSONField(
277272
blank=True,
278273
default=dict,

product_portfolio/migrations/0018_productpolicyviolation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generated by Django 6.0.6 on 2026-07-07 04:49
1+
# Generated by Django 6.0.6 on 2026-07-08 08:39
22

33
import django.db.models.deletion
44
import dje.models

0 commit comments

Comments
 (0)