Skip to content

Commit

Permalink
addition of has_tags and product/finding sla filters (#8549)
Browse files Browse the repository at this point in the history
* addition of has_tags and product/finding sla filters

* fix failing tests

* fix random flake8 error regarding type()
  • Loading branch information
blakeaowens authored Aug 24, 2023
1 parent d67fdb3 commit 85d3dc8
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 5 deletions.
86 changes: 86 additions & 0 deletions dojo/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,68 @@ def filter(self, qs, value):
return self.options[value][1](self, qs, self.field_name)


class FindingSLAFilter(ChoiceFilter):
def any(self, qs, name):
return qs

def satisfies_sla(self, qs, name):
non_sla_violations = [finding.id for finding in qs if not finding.violates_sla]
return Finding.objects.filter(id__in=non_sla_violations)

def violates_sla(self, qs, name):
sla_violations = [finding.id for finding in qs if finding.violates_sla]
return Finding.objects.filter(id__in=sla_violations)

options = {
None: (_('Any'), any),
0: (_('False'), satisfies_sla),
1: (_('True'), violates_sla),
}

def __init__(self, *args, **kwargs):
kwargs['choices'] = [
(key, value[0]) for key, value in six.iteritems(self.options)]
super(FindingSLAFilter, self).__init__(*args, **kwargs)

def filter(self, qs, value):
try:
value = int(value)
except (ValueError, TypeError):
value = None
return self.options[value][1](self, qs, self.field_name)


class ProductSLAFilter(ChoiceFilter):
def any(self, qs, name):
return qs

def satisfies_sla(self, qs, name):
non_sla_violations = [product.id for product in qs if not product.violates_sla]
return Product.objects.filter(id__in=non_sla_violations)

def violates_sla(self, qs, name):
sla_violations = [product.id for product in qs if product.violates_sla]
return Product.objects.filter(id__in=sla_violations)

options = {
None: (_('Any'), any),
0: (_('False'), satisfies_sla),
1: (_('True'), violates_sla),
}

def __init__(self, *args, **kwargs):
kwargs['choices'] = [
(key, value[0]) for key, value in six.iteritems(self.options)]
super(ProductSLAFilter, self).__init__(*args, **kwargs)

def filter(self, qs, value):
try:
value = int(value)
except (ValueError, TypeError):
value = None
return self.options[value][1](self, qs, self.field_name)


def get_earliest_finding(queryset=None):
if queryset is None: # don't to 'if not queryset' which will trigger the query
queryset = Finding.objects.all()
Expand Down Expand Up @@ -683,6 +745,8 @@ class EngagementDirectFilter(DojoFilter):

not_tag = CharFilter(field_name='tags__name', lookup_expr='icontains', label='Not tag name contains', exclude=True)

has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
fields=(
Expand Down Expand Up @@ -745,6 +809,8 @@ class EngagementFilter(DojoFilter):

not_tag = CharFilter(field_name='tags__name', lookup_expr='icontains', label='Not tag name contains', exclude=True)

has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
fields=(
Expand Down Expand Up @@ -842,6 +908,7 @@ class ApiEngagementFilter(DojoFilter):
lookup_expr='in',
help_text='Comma separated list of exact tags not present on product',
exclude='True')
has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
Expand Down Expand Up @@ -966,6 +1033,10 @@ class ProductFilter(DojoFilter):

not_tag = CharFilter(field_name='tags__name', lookup_expr='icontains', label='Not tag name contains', exclude=True)

outside_of_sla = ProductSLAFilter(label="Outside of SLA")

has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
fields=(
Expand Down Expand Up @@ -1040,6 +1111,8 @@ class ApiProductFilter(DojoFilter):
not_tag = CharFilter(field_name='tags__name', lookup_expr='icontains', help_text='Not Tag name contains', exclude='True')
not_tags = CharFieldInFilter(field_name='tags__name', lookup_expr='in',
help_text='Comma separated list of exact tags not present on product', exclude='True')
has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')
outside_of_sla = extend_schema_field(OpenApiTypes.NUMBER)(ProductSLAFilter())

# DateRangeFilter
created = DateRangeFilter()
Expand Down Expand Up @@ -1166,6 +1239,8 @@ class ApiFindingFilter(DojoFilter):
lookup_expr='in',
help_text='Comma separated list of exact tags not present on product',
exclude='True')
has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')
outside_of_sla = extend_schema_field(OpenApiTypes.NUMBER)(ProductSLAFilter())

o = OrderingFilter(
# tuple-mapping retains order
Expand Down Expand Up @@ -1336,6 +1411,10 @@ class FindingFilter(FindingFilterWithTags):

not_tag = CharFilter(field_name='tags__name', lookup_expr='icontains', label='Not tag name contains', exclude=True)

outside_of_sla = FindingSLAFilter(label="Outside of SLA")

has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
fields=(
Expand Down Expand Up @@ -1770,6 +1849,8 @@ class EndpointFilter(DojoFilter):

not_tag = CharFilter(field_name='tags__name', lookup_expr='icontains', label='Not tag name contains', exclude=True)

has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
fields=(
Expand Down Expand Up @@ -1803,6 +1884,8 @@ class ApiEndpointFilter(DojoFilter):
not_tag = CharFilter(field_name='tags__name', lookup_expr='icontains', help_text='Not Tag name contains', exclude='True')
not_tags = CharFieldInFilter(field_name='tags__name', lookup_expr='in',
help_text='Comma separated list of exact tags not present on model', exclude='True')
has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
fields=(
Expand Down Expand Up @@ -1863,6 +1946,8 @@ class EngagementTestFilter(DojoFilter):

not_tag = CharFilter(field_name='tags__name', lookup_expr='icontains', label='Not tag name contains', exclude=True)

has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
fields=(
Expand Down Expand Up @@ -1914,6 +1999,7 @@ class ApiTestFilter(DojoFilter):
lookup_expr='in',
help_text='Comma separated list of exact tags not present on product',
exclude='True')
has_tags = BooleanFilter(field_name='tags', lookup_expr='isnull', exclude=True, label='Has tags')

o = OrderingFilter(
# tuple-mapping retains order
Expand Down
23 changes: 18 additions & 5 deletions dojo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,8 +1116,7 @@ def get_product_type(self):
@cached_property
def open_findings_list(self):
findings = Finding.objects.filter(test__engagement__product=self,
active=True,
)
active=True)
findings_list = []
for i in findings:
findings_list.append(i.id)
Expand All @@ -1132,6 +1131,15 @@ def get_absolute_url(self):
from django.urls import reverse
return reverse('view_product', args=[str(self.id)])

@property
def violates_sla(self):
findings = Finding.objects.filter(test__engagement__product=self,
active=True)
for f in findings:
if f.violates_sla:
return True
return False


class Product_Member(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
Expand Down Expand Up @@ -3019,6 +3027,11 @@ def inherit_tags(self, potentially_existing_tags):
incoming_inherited_tags = [tag.name for tag in self.test.engagement.product.tags.all()]
_manage_inherited_tags(self, incoming_inherited_tags, potentially_existing_tags=potentially_existing_tags)

@property
def violates_sla(self):
days_remaining = self.sla_days_remaining()
return days_remaining < 0 if days_remaining else False


class FindingAdmin(admin.ModelAdmin):
# For efficiency with large databases, display many-to-many fields with raw
Expand Down Expand Up @@ -3649,11 +3662,11 @@ class JIRA_Issue(models.Model):
help_text=_("The date the linked Jira issue was last modified."))

def set_obj(self, obj):
if type(obj) == Finding:
if isinstance(obj, Finding):
self.finding = obj
elif type(obj) == Finding_Group:
elif isinstance(obj, Finding_Group):
self.finding_group = obj
elif type(obj) == Engagement:
elif isinstance(obj, Engagement):
self.engagement = obj
else:
raise ValueError('unknown object type while creating JIRA_Issue: %s' % to_str_typed(obj))
Expand Down

0 comments on commit 85d3dc8

Please sign in to comment.