ISO-27001-Risk-Management/risks/models/risk.py
2025-09-22 09:44:51 +02:00

100 lines
No EOL
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.db import models
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from multiselectfield import MultiSelectField
from .likelihood_choice import LikelihoodChoice
# ---------------------------------------------------------------------------
# Risk
# ---------------------------------------------------------------------------
class Risk(models.Model):
class Meta:
verbose_name = _("Risk")
verbose_name_plural = _("Risks")
STATUS_CHOICES = [
("open", _("Open")),
("in_progress", _("In Progress")),
("closed", _("Closed")),
("review_required", _("Review required")),
]
IMPACT_CHOICES = [
(1, _("Very Low (< 1,000 € minor operational impact)")),
(2, _("Low (1,0005,000 € local impact)")),
(3, _("High (5,00015,000 € team-level impact)")),
(4, _("Severe (50,000100,000 € regional impact)")),
(5, _("Critical (> 100,000 € existential threat)")),
]
CIA_CHOICES = [
("1", _("Confidentiality")),
("2", _("Integrity")),
("3", _("Availability")),
]
# Basic information
title = models.CharField(_("Title"), max_length=255)
description = models.TextField(_("Description"), max_length=225, blank=True, null=True)
asset = models.CharField(_("Asset"), max_length=255, blank=True, null=True)
process = models.CharField(_("Process"), max_length=255, blank=True, null=True)
category = models.CharField(_("Category"), max_length=255, blank=True, null=True)
created_at = models.DateTimeField(_("Created at"), auto_now_add=True)
updated_at = models.DateTimeField(_("Updated at"), auto_now=True)
effects = models.TextField(_("Effects"), blank=True, null=True)
status = models.CharField(
_("Status"),
max_length=20,
choices=STATUS_CHOICES,
default="open",
db_index=True,
)
# CIA Protection Goals
cia = MultiSelectField(choices=CIA_CHOICES, max_length=100, blank=True, null=True)
# Risk evaluation before controls
likelihood = models.ForeignKey(
LikelihoodChoice,
on_delete=models.PROTECT,
verbose_name=_("Likelihood"),
related_name="risks",
)
impact = models.IntegerField(choices=IMPACT_CHOICES, default=1)
# Calculated fields
score = models.IntegerField(editable=False)
level = models.CharField(max_length=50, editable=False)
# Ownership
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET_NULL,
null=True,
related_name="owned_risks"
)
# Reminder / follow-up date
follow_up = models.DateField(blank=True, null=True)
def save(self, *args, **kwargs):
# Mark for review if likelihood/impact changed
if self.pk:
old = Risk.objects.get(pk=self.pk)
if old.likelihood != self.likelihood or old.impact != self.impact:
self.review_required = True
self.status = "review_required"
# Calculate risk score and level
self.score = self.likelihood.value * self.impact
if self.score <= 4:
self.level = "Low"
elif self.score <= 8:
self.level = "Medium"
elif self.score <= 12:
self.level = "High"
else:
self.level = "Critical"
super().save(*args, **kwargs)
def __str__(self):
return f"{self.title} (Score: {self.score}, Level: {self.level})"