Skip to content

Commit

Permalink
Fix add related, fix manual ooi task list, remove redundant octopoes …
Browse files Browse the repository at this point in the history
…call (#3421)

Co-authored-by: ammar92 <ammar.abdulamir@gmail.com>
Co-authored-by: Jan Klopper <janklopper+underdark@gmail.com>
  • Loading branch information
3 people committed Sep 5, 2024
1 parent 280272c commit f243e73
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 73 deletions.
6 changes: 5 additions & 1 deletion rocky/rocky/locale/django.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-09-04 14:21+0000\n"
"POT-Creation-Date: 2024-09-05 08:44+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand Down Expand Up @@ -5271,6 +5271,10 @@ msgstr ""
msgid "When"
msgstr ""

#: rocky/templates/oois/ooi_detail_origins_observations.html
msgid "This scan was manually created."
msgstr ""

#: rocky/templates/oois/ooi_detail_origins_observations.html
msgid "The boefje has since been deleted or disabled."
msgstr ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ <h2>{% translate "Last observed by" %}</h2>
<a href="{% url 'boefje_detail' organization_code=organization.code plugin_id=observation.boefje.id %}"
title="{{ observation.boefje.id }}">{{ observation.boefje.name }}</a>
{% else %}
{% translate "The boefje has since been deleted or disabled." %}
{% if observation.normalizer.raw_data.boefje_meta.boefje.id == "manual" %}
{% translate "This scan was manually created." %}
{% else %}
{% translate "The boefje has since been deleted or disabled." %}
{% endif %}
{% endif %}
</td>
<td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ <h2>{% translate "Related objects" %}</h2>
{% if not ooi_past_due %}
{% if not ooi|is_finding and not ooi|is_finding_type %}
<div class="horizontal-view {% if related %}toolbar{% endif %}">
<a href="{% ooi_url "ooi_add_related" ooi.primary_key organization.code %}&add_ooi_type={{ ooi.get_ooi_type }}"
<a href="{% ooi_url "ooi_add_related" ooi.primary_key organization.code %}"
class="button ghost">{% translate "Add" %}</a>
</div>
{% endif %}
Expand Down
22 changes: 13 additions & 9 deletions rocky/rocky/views/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,20 @@ def get_origins(
boefje_meta = normalizer_data["raw_data"]["boefje_meta"]
boefje_id = boefje_meta["boefje"]["id"]
if boefje_meta.get("ended_at"):
boefje_meta["ended_at"] = datetime.strptime(boefje_meta["ended_at"], "%Y-%m-%dT%H:%M:%S.%fZ")
try:
boefje_meta["ended_at"] = datetime.strptime(boefje_meta["ended_at"], "%Y-%m-%dT%H:%M:%S.%fZ")
except ValueError:
boefje_meta["ended_at"] = datetime.strptime(boefje_meta["ended_at"], "%Y-%m-%dT%H:%M:%SZ")
origin.normalizer = normalizer_data
try:
origin.boefje = katalogus.get_plugin(boefje_id)
except HTTPError as e:
logger.error(
"Could not load boefje: %s from katalogus, error: %s",
boefje_id,
e,
)
if boefje_id != "manual":
try:
origin.boefje = katalogus.get_plugin(boefje_id)
except HTTPError as e:
logger.error(
"Could not load boefje %s from katalogus: %s",
boefje_id,
e,
)
observations.append(origin)

return results
Expand Down
4 changes: 2 additions & 2 deletions rocky/rocky/views/ooi_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@

from octopoes.models import Reference
from octopoes.models.ooi.question import Question
from rocky.views.ooi_detail_related_object import OOIFindingManager, OOIRelatedObjectAddView
from rocky.views.ooi_detail_related_object import OOIFindingManager, OOIRelatedObjectManager
from rocky.views.ooi_view import BaseOOIDetailView
from rocky.views.tasks import TaskListView


class OOIDetailView(
BaseOOIDetailView,
OOIRelatedObjectAddView,
OOIRelatedObjectManager,
OOIFindingManager,
TaskListView,
):
Expand Down
97 changes: 49 additions & 48 deletions rocky/rocky/views/ooi_detail_related_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic.base import TemplateView
from tools.ooi_helpers import format_attr_name
from tools.view_helpers import existing_ooi_type, get_mandatory_fields, url_with_querystring

Expand All @@ -29,54 +30,6 @@ def get_related_objects(self, observed_at):
related.append(rel)
return related


class OOIFindingManager(SingleOOITreeMixin):
def get_findings(self) -> list[Finding]:
findings = []
for relation in self.tree.root.children.values():
for child in relation:
ooi = self.tree.store[str(child.reference)]
if isinstance(ooi, Finding) and ooi.reference != self.tree.root.reference:
findings.append(ooi)
return findings

def count_findings_per_severity(self) -> Counter:
counter = Counter({severity: 0 for severity in RiskLevelSeverity})
for finding in self.get_findings():
finding_type: FindingType | None = self.tree.store.get(str(finding.finding_type), None)
if finding_type is not None and finding_type.risk_severity is not None:
counter.update([finding_type.risk_severity])
else:
counter.update([RiskLevelSeverity.UNKNOWN])
return counter

def get_finding_details_sorted_by_score_desc(self) -> list[tuple[Finding, FindingType]]:
finding_details = self.get_finding_details()
return list(sorted(finding_details, key=lambda x: x[1].risk_score or 0, reverse=True))

def get_finding_details(self) -> list[tuple[Finding, FindingType]]:
return [(finding, self.tree.store[str(finding.finding_type)]) for finding in self.get_findings()]


class OOIRelatedObjectAddView(OOIRelatedObjectManager):
template_name = "oois/ooi_detail_add_related_object.html"

def get(self, request, *args, **kwargs):
if "ooi_id" in request.GET:
self.ooi_id = self.get_ooi(pk=request.GET.get("ooi_id"))

if "add_ooi_type" in request.GET:
ooi_type_choice = self.split_ooi_type_choice(request.GET["add_ooi_type"])
if existing_ooi_type(ooi_type_choice["ooi_type"]):
return redirect(self.ooi_add_url(self.ooi_id, **ooi_type_choice))

if "status_code" in kwargs:
response = super().get(request, *args, **kwargs)
response.status_code = kwargs["status_code"]
return response

return super().get(request, *args, **kwargs)

def split_ooi_type_choice(self, ooi_type_choice) -> dict[str, str]:
ooi_type = ooi_type_choice.split("|", 1)

Expand Down Expand Up @@ -146,6 +99,54 @@ def get_ooi_types_input_values(self, ooi: OOI) -> list[dict[str, str]]:

return input_values


class OOIFindingManager(SingleOOITreeMixin):
def get_findings(self) -> list[Finding]:
findings = []
for relation in self.tree.root.children.values():
for child in relation:
ooi = self.tree.store[str(child.reference)]
if isinstance(ooi, Finding) and ooi.reference != self.tree.root.reference:
findings.append(ooi)
return findings

def count_findings_per_severity(self) -> Counter:
counter = Counter({severity: 0 for severity in RiskLevelSeverity})
for finding in self.get_findings():
finding_type: FindingType | None = self.tree.store.get(str(finding.finding_type), None)
if finding_type is not None and finding_type.risk_severity is not None:
counter.update([finding_type.risk_severity])
else:
counter.update([RiskLevelSeverity.UNKNOWN])
return counter

def get_finding_details_sorted_by_score_desc(self) -> list[tuple[Finding, FindingType]]:
finding_details = self.get_finding_details()
return list(sorted(finding_details, key=lambda x: x[1].risk_score or 0, reverse=True))

def get_finding_details(self) -> list[tuple[Finding, FindingType]]:
return [(finding, self.tree.store[str(finding.finding_type)]) for finding in self.get_findings()]


class OOIRelatedObjectAddView(OOIRelatedObjectManager, TemplateView):
template_name = "oois/ooi_detail_add_related_object.html"

def get(self, request, *args, **kwargs):
if "ooi_id" in request.GET:
self.ooi_id = self.get_ooi(pk=request.GET["ooi_id"])

if "add_ooi_type" in request.GET:
ooi_type_choice = self.split_ooi_type_choice(request.GET["add_ooi_type"])
if existing_ooi_type(ooi_type_choice["ooi_type"]):
return redirect(self.ooi_add_url(self.ooi_id, **ooi_type_choice))

if "status_code" in kwargs:
response = super().get(request, *args, **kwargs)
response.status_code = kwargs["status_code"]
return response

return super().get(request, *args, **kwargs)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["ooi_id"] = self.ooi_id
Expand Down
12 changes: 6 additions & 6 deletions rocky/tests/objects/test_objects_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def test_ooi_detail(
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)

assert response.status_code == 200
assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1
assertContains(response, "Object")
assertContains(response, "Network|testnetwork")

Expand Down Expand Up @@ -109,7 +109,7 @@ def test_question_detail(
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)

assert response.status_code == 200
assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1

assertContains(response, "Question")
assertContains(response, "Rendered Question Form")
Expand Down Expand Up @@ -142,7 +142,7 @@ def test_answer_question(
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)

assertContains(response, "Question has been answered.", status_code=200)
assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1


def test_answer_question_bad_schema(
Expand Down Expand Up @@ -217,7 +217,7 @@ def test_ooi_detail_start_scan(
)
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)

assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1

assert response.status_code == 200

Expand Down Expand Up @@ -263,7 +263,7 @@ def test_ooi_detail_start_scan_no_indemnification(
)
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)

assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1
assertContains(response, "Object details")
assertContains(response, "Indemnification not present")

Expand Down Expand Up @@ -295,7 +295,7 @@ def test_ooi_detail_start_scan_no_action(
)
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)

assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1
assertContains(response, "Object details")


Expand Down
10 changes: 5 additions & 5 deletions rocky/tests/objects/test_objects_scan_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def test_scan_profile(rf, redteam_member, mock_scheduler, mock_organization_view
response = ScanProfileDetailView.as_view()(request, organization_code=redteam_member.organization.code)

assert response.status_code == 200
assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1

assertContains(response, "Set clearance level")

Expand Down Expand Up @@ -125,7 +125,7 @@ def test_scan_profile_no_permissions_acknowledged(
response = ScanProfileDetailView.as_view()(request, organization_code=redteam_member.organization.code)

assert response.status_code == 200
assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1

assertNotContains(response, "Set clearance level")

Expand All @@ -146,7 +146,7 @@ def test_scan_profile_no_permissions_trusted(
response = ScanProfileDetailView.as_view()(request, organization_code=redteam_member.organization.code)

assert response.status_code == 200
assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1

assertNotContains(response, "Set clearance level")

Expand All @@ -162,7 +162,7 @@ def test_scan_profile_reset_view(rf, redteam_member, mock_scheduler, mock_organi
response = ScanProfileResetView.as_view()(request, organization_code=redteam_member.organization.code)

assert response.status_code == 200
assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1

assertContains(response, "Set clearance level")
assertContains(response, "Yes, set to inherit")
Expand All @@ -183,5 +183,5 @@ def test_scan_reset_calls_octopoes(rf, redteam_member, mock_scheduler, mock_orga
response = ScanProfileResetView.as_view()(request, organization_code=redteam_member.organization.code)

assert response.status_code == 302
assert mock_organization_view_octopoes().get_tree.call_count == 2
assert mock_organization_view_octopoes().get_tree.call_count == 1
assert mock_organization_view_octopoes().save_scan_profile.call_count == 1

0 comments on commit f243e73

Please sign in to comment.