Skip to content

Commit 0b3315c

Browse files
committed
add PolicyRule and PolicyViolation models
Signed-off-by: tdruez <tdruez@aboutcode.org>
1 parent 0e6951a commit 0b3315c

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Generated by Django 6.0.6 on 2026-07-07 04:49
2+
3+
import django.db.models.deletion
4+
import dje.models
5+
import uuid
6+
from django.db import migrations, models
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
('dje', '0015_alter_dataspaceconfiguration_purldb_api_key_and_more'),
13+
('policy', '0002_initial'),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='PolicyRule',
19+
fields=[
20+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21+
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='UUID')),
22+
('name', models.CharField(help_text='Descriptive name for this policy rule.', max_length=100)),
23+
('rule_type', models.CharField(help_text='The type of evaluation performed by this rule.', max_length=50)),
24+
('threshold', models.PositiveIntegerField(default=0, help_text='Minimum number of violations required to trigger this rule (0 means any).')),
25+
('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)),
27+
('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')),
28+
],
29+
options={
30+
'ordering': ['name'],
31+
'unique_together': {('dataspace', 'name'), ('dataspace', 'uuid')},
32+
},
33+
bases=(dje.models.DataspaceForeignKeyValidationMixin, models.Model),
34+
),
35+
]

policy/models.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,70 @@ def save(self, *args, **kwargs):
244244
if self.from_policy.content_type == self.to_policy.content_type:
245245
raise AssertionError
246246
super().save(*args, **kwargs)
247+
248+
249+
class PolicyRuleQuerySet(DataspacedQuerySet):
250+
def active(self):
251+
return self.filter(is_active=True)
252+
253+
254+
class PolicyRule(DataspacedModel):
255+
name = models.CharField(
256+
max_length=100,
257+
help_text=_("Descriptive name for this policy rule."),
258+
)
259+
rule_type = models.CharField(
260+
max_length=50,
261+
help_text=_("The type of evaluation performed by this rule."),
262+
)
263+
threshold = models.PositiveIntegerField(
264+
default=0,
265+
help_text=_("Minimum number of violations required to trigger this rule (0 means any)."),
266+
)
267+
is_active = models.BooleanField(
268+
default=True,
269+
help_text=_("Only active rules are evaluated."),
270+
)
271+
event_name = models.CharField(
272+
max_length=100,
273+
blank=True,
274+
help_text=_("Notification event to fire when violations are detected."),
275+
)
276+
277+
objects = PolicyRuleQuerySet.as_manager()
278+
279+
class Meta:
280+
unique_together = (("dataspace", "uuid"), ("dataspace", "name"))
281+
ordering = ["name"]
282+
283+
def __str__(self):
284+
return self.name
285+
286+
287+
class AbstractPolicyViolation(models.Model):
288+
"""Shared fields for all concrete policy violation models. No DB table."""
289+
290+
violation_count = models.PositiveIntegerField(
291+
default=0,
292+
help_text=_("Number of objects currently violating the rule."),
293+
)
294+
detected_date = models.DateTimeField(
295+
auto_now_add=True,
296+
help_text=_("The date and time when this violation was first detected."),
297+
)
298+
last_checked = models.DateTimeField(
299+
auto_now=True,
300+
help_text=_("The date and time of the last evaluation."),
301+
)
302+
resolved = models.BooleanField(
303+
default=False,
304+
help_text=_("Indicates whether this violation has been resolved."),
305+
)
306+
resolved_date = models.DateTimeField(
307+
null=True,
308+
blank=True,
309+
help_text=_("The date and time when this violation was resolved."),
310+
)
311+
312+
class Meta:
313+
abstract = True

0 commit comments

Comments
 (0)