Skip to content

Commit

Permalink
Add VulnerabilityAnalysisMixin model #95
Browse files Browse the repository at this point in the history
Signed-off-by: tdruez <tdruez@nexb.com>
  • Loading branch information
tdruez committed Sep 4, 2024
1 parent fdf4cd0 commit 45c59a6
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.0.6 on 2024-09-04 09:15
# Generated by Django 5.0.6 on 2024-09-04 09:22

import django.db.models.deletion
import uuid
Expand Down
99 changes: 99 additions & 0 deletions vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import decimal
import logging

from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.db.models import Count
from django.utils.translation import gettext_lazy as _
Expand Down Expand Up @@ -256,6 +257,104 @@ def as_cyclonedx(self, affected_instances):
)


class VulnerabilityAnalysisMixin(models.Model):
"""Aligned with the cyclonedx.model.vulnerability.VulnerabilityAnalysis"""

# cyclonedx.model.impact_analysis.ImpactAnalysisState
class State(models.TextChoices):
RESOLVED = "resolved"
RESOLVED_WITH_PEDIGREE = "resolved_with_pedigree"
EXPLOITABLE = "exploitable"
IN_TRIAGE = "in_triage"
FALSE_POSITIVE = "false_positive"
NOT_AFFECTED = "not_affected"

# cyclonedx.model.impact_analysis.ImpactAnalysisJustification
class Justification(models.TextChoices):
CODE_NOT_PRESENT = "code_not_present"
CODE_NOT_REACHABLE = "code_not_reachable"
PROTECTED_AT_PERIMITER = "protected_at_perimeter"
PROTECTED_AT_RUNTIME = "protected_at_runtime"
PROTECTED_BY_COMPILER = "protected_by_compiler"
PROTECTED_BY_MITIGATING_CONTROL = "protected_by_mitigating_control"
REQUIRES_CONFIGURATION = "requires_configuration"
REQUIRES_DEPENDENCY = "requires_dependency"
REQUIRES_ENVIRONMENT = "requires_environment"

# cyclonedx.model.impact_analysis.ImpactAnalysisResponse
class Response(models.TextChoices):
CAN_NOT_FIX = "can_not_fix"
ROLLBACK = "rollback"
UPDATE = "update"
WILL_NOT_FIX = "will_not_fix"
WORKAROUND_AVAILABLE = "workaround_available"

state = models.CharField(
max_length=25,
blank=True,
choices=State.choices,
help_text=_(
"Declares the current state of an occurrence of a vulnerability, "
"after automated or manual analysis."
),
)
justification = models.CharField(
max_length=35,
blank=True,
choices=Justification.choices,
help_text=_("The rationale of why the impact analysis state was asserted."),
)
responses = ArrayField(
models.CharField(
max_length=20,
choices=Response.choices,
),
blank=True,
null=True,
help_text=_(
"A response to the vulnerability by the manufacturer, supplier, or project "
"responsible for the affected component or service. "
"More than one response is allowed. "
"Responses are strongly encouraged for vulnerabilities where the analysis "
"state is exploitable."
),
)
detail = models.TextField(
blank=True,
help_text=_(
"Detailed description of the impact including methods used during assessment. "
"If a vulnerability is not exploitable, this field should include specific "
"details on why the component or service is not impacted by this vulnerability."
),
)
first_issued = models.DateTimeField(
auto_now_add=True,
help_text=_("The date and time (timestamp) when the analysis was first issued."),
)
last_updated = models.DateTimeField(
auto_now=True,
help_text=_("The date and time (timestamp) when the analysis was last updated."),
)

class Meta:
abstract = True

def save(self, *args, **kwargs):
# At least one of those fields must be provided.
main_fields = [
self.state,
self.justification,
self.responses,
self.detail,
]
if not any(main_fields):
raise ValueError(
"At least one of state, justification, responses or detail must be provided."
)

super().save(*args, **kwargs)


class AffectedByVulnerabilityRelationship(DataspacedModel):
vulnerability = models.ForeignKey(
to="vulnerabilities.Vulnerability",
Expand Down
2 changes: 1 addition & 1 deletion vulnerabilities/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

from django.test import TestCase

from component_catalog.tests import make_component
from component_catalog.models import Package
from component_catalog.tests import make_component
from component_catalog.tests import make_package
from dejacode_toolkit.vulnerablecode import VulnerableCode
from dje.models import Dataspace
Expand Down

0 comments on commit 45c59a6

Please sign in to comment.