Skip to content

Commit f243e73

Browse files
noamblitzammar92underdarknl
authored
Fix add related, fix manual ooi task list, remove redundant octopoes call (#3421)
Co-authored-by: ammar92 <ammar.abdulamir@gmail.com> Co-authored-by: Jan Klopper <janklopper+underdark@gmail.com>
1 parent 280272c commit f243e73

8 files changed

Lines changed: 86 additions & 73 deletions

File tree

rocky/rocky/locale/django.pot

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ msgid ""
88
msgstr ""
99
"Project-Id-Version: PACKAGE VERSION\n"
1010
"Report-Msgid-Bugs-To: \n"
11-
"POT-Creation-Date: 2024-09-04 14:21+0000\n"
11+
"POT-Creation-Date: 2024-09-05 08:44+0000\n"
1212
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -5271,6 +5271,10 @@ msgstr ""
52715271
msgid "When"
52725272
msgstr ""
52735273

5274+
#: rocky/templates/oois/ooi_detail_origins_observations.html
5275+
msgid "This scan was manually created."
5276+
msgstr ""
5277+
52745278
#: rocky/templates/oois/ooi_detail_origins_observations.html
52755279
msgid "The boefje has since been deleted or disabled."
52765280
msgstr ""

rocky/rocky/templates/oois/ooi_detail_origins_observations.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ <h2>{% translate "Last observed by" %}</h2>
2424
<a href="{% url 'boefje_detail' organization_code=organization.code plugin_id=observation.boefje.id %}"
2525
title="{{ observation.boefje.id }}">{{ observation.boefje.name }}</a>
2626
{% else %}
27-
{% translate "The boefje has since been deleted or disabled." %}
27+
{% if observation.normalizer.raw_data.boefje_meta.boefje.id == "manual" %}
28+
{% translate "This scan was manually created." %}
29+
{% else %}
30+
{% translate "The boefje has since been deleted or disabled." %}
31+
{% endif %}
2832
{% endif %}
2933
</td>
3034
<td>

rocky/rocky/templates/partials/ooi_detail_related_object.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ <h2>{% translate "Related objects" %}</h2>
1212
{% if not ooi_past_due %}
1313
{% if not ooi|is_finding and not ooi|is_finding_type %}
1414
<div class="horizontal-view {% if related %}toolbar{% endif %}">
15-
<a href="{% ooi_url "ooi_add_related" ooi.primary_key organization.code %}&add_ooi_type={{ ooi.get_ooi_type }}"
15+
<a href="{% ooi_url "ooi_add_related" ooi.primary_key organization.code %}"
1616
class="button ghost">{% translate "Add" %}</a>
1717
</div>
1818
{% endif %}

rocky/rocky/views/mixins.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,16 +172,20 @@ def get_origins(
172172
boefje_meta = normalizer_data["raw_data"]["boefje_meta"]
173173
boefje_id = boefje_meta["boefje"]["id"]
174174
if boefje_meta.get("ended_at"):
175-
boefje_meta["ended_at"] = datetime.strptime(boefje_meta["ended_at"], "%Y-%m-%dT%H:%M:%S.%fZ")
175+
try:
176+
boefje_meta["ended_at"] = datetime.strptime(boefje_meta["ended_at"], "%Y-%m-%dT%H:%M:%S.%fZ")
177+
except ValueError:
178+
boefje_meta["ended_at"] = datetime.strptime(boefje_meta["ended_at"], "%Y-%m-%dT%H:%M:%SZ")
176179
origin.normalizer = normalizer_data
177-
try:
178-
origin.boefje = katalogus.get_plugin(boefje_id)
179-
except HTTPError as e:
180-
logger.error(
181-
"Could not load boefje: %s from katalogus, error: %s",
182-
boefje_id,
183-
e,
184-
)
180+
if boefje_id != "manual":
181+
try:
182+
origin.boefje = katalogus.get_plugin(boefje_id)
183+
except HTTPError as e:
184+
logger.error(
185+
"Could not load boefje %s from katalogus: %s",
186+
boefje_id,
187+
e,
188+
)
185189
observations.append(origin)
186190

187191
return results

rocky/rocky/views/ooi_detail.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313

1414
from octopoes.models import Reference
1515
from octopoes.models.ooi.question import Question
16-
from rocky.views.ooi_detail_related_object import OOIFindingManager, OOIRelatedObjectAddView
16+
from rocky.views.ooi_detail_related_object import OOIFindingManager, OOIRelatedObjectManager
1717
from rocky.views.ooi_view import BaseOOIDetailView
1818
from rocky.views.tasks import TaskListView
1919

2020

2121
class OOIDetailView(
2222
BaseOOIDetailView,
23-
OOIRelatedObjectAddView,
23+
OOIRelatedObjectManager,
2424
OOIFindingManager,
2525
TaskListView,
2626
):

rocky/rocky/views/ooi_detail_related_object.py

Lines changed: 49 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.shortcuts import redirect
44
from django.urls import reverse
55
from django.utils.translation import gettext_lazy as _
6+
from django.views.generic.base import TemplateView
67
from tools.ooi_helpers import format_attr_name
78
from tools.view_helpers import existing_ooi_type, get_mandatory_fields, url_with_querystring
89

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

32-
33-
class OOIFindingManager(SingleOOITreeMixin):
34-
def get_findings(self) -> list[Finding]:
35-
findings = []
36-
for relation in self.tree.root.children.values():
37-
for child in relation:
38-
ooi = self.tree.store[str(child.reference)]
39-
if isinstance(ooi, Finding) and ooi.reference != self.tree.root.reference:
40-
findings.append(ooi)
41-
return findings
42-
43-
def count_findings_per_severity(self) -> Counter:
44-
counter = Counter({severity: 0 for severity in RiskLevelSeverity})
45-
for finding in self.get_findings():
46-
finding_type: FindingType | None = self.tree.store.get(str(finding.finding_type), None)
47-
if finding_type is not None and finding_type.risk_severity is not None:
48-
counter.update([finding_type.risk_severity])
49-
else:
50-
counter.update([RiskLevelSeverity.UNKNOWN])
51-
return counter
52-
53-
def get_finding_details_sorted_by_score_desc(self) -> list[tuple[Finding, FindingType]]:
54-
finding_details = self.get_finding_details()
55-
return list(sorted(finding_details, key=lambda x: x[1].risk_score or 0, reverse=True))
56-
57-
def get_finding_details(self) -> list[tuple[Finding, FindingType]]:
58-
return [(finding, self.tree.store[str(finding.finding_type)]) for finding in self.get_findings()]
59-
60-
61-
class OOIRelatedObjectAddView(OOIRelatedObjectManager):
62-
template_name = "oois/ooi_detail_add_related_object.html"
63-
64-
def get(self, request, *args, **kwargs):
65-
if "ooi_id" in request.GET:
66-
self.ooi_id = self.get_ooi(pk=request.GET.get("ooi_id"))
67-
68-
if "add_ooi_type" in request.GET:
69-
ooi_type_choice = self.split_ooi_type_choice(request.GET["add_ooi_type"])
70-
if existing_ooi_type(ooi_type_choice["ooi_type"]):
71-
return redirect(self.ooi_add_url(self.ooi_id, **ooi_type_choice))
72-
73-
if "status_code" in kwargs:
74-
response = super().get(request, *args, **kwargs)
75-
response.status_code = kwargs["status_code"]
76-
return response
77-
78-
return super().get(request, *args, **kwargs)
79-
8033
def split_ooi_type_choice(self, ooi_type_choice) -> dict[str, str]:
8134
ooi_type = ooi_type_choice.split("|", 1)
8235

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

147100
return input_values
148101

102+
103+
class OOIFindingManager(SingleOOITreeMixin):
104+
def get_findings(self) -> list[Finding]:
105+
findings = []
106+
for relation in self.tree.root.children.values():
107+
for child in relation:
108+
ooi = self.tree.store[str(child.reference)]
109+
if isinstance(ooi, Finding) and ooi.reference != self.tree.root.reference:
110+
findings.append(ooi)
111+
return findings
112+
113+
def count_findings_per_severity(self) -> Counter:
114+
counter = Counter({severity: 0 for severity in RiskLevelSeverity})
115+
for finding in self.get_findings():
116+
finding_type: FindingType | None = self.tree.store.get(str(finding.finding_type), None)
117+
if finding_type is not None and finding_type.risk_severity is not None:
118+
counter.update([finding_type.risk_severity])
119+
else:
120+
counter.update([RiskLevelSeverity.UNKNOWN])
121+
return counter
122+
123+
def get_finding_details_sorted_by_score_desc(self) -> list[tuple[Finding, FindingType]]:
124+
finding_details = self.get_finding_details()
125+
return list(sorted(finding_details, key=lambda x: x[1].risk_score or 0, reverse=True))
126+
127+
def get_finding_details(self) -> list[tuple[Finding, FindingType]]:
128+
return [(finding, self.tree.store[str(finding.finding_type)]) for finding in self.get_findings()]
129+
130+
131+
class OOIRelatedObjectAddView(OOIRelatedObjectManager, TemplateView):
132+
template_name = "oois/ooi_detail_add_related_object.html"
133+
134+
def get(self, request, *args, **kwargs):
135+
if "ooi_id" in request.GET:
136+
self.ooi_id = self.get_ooi(pk=request.GET["ooi_id"])
137+
138+
if "add_ooi_type" in request.GET:
139+
ooi_type_choice = self.split_ooi_type_choice(request.GET["add_ooi_type"])
140+
if existing_ooi_type(ooi_type_choice["ooi_type"]):
141+
return redirect(self.ooi_add_url(self.ooi_id, **ooi_type_choice))
142+
143+
if "status_code" in kwargs:
144+
response = super().get(request, *args, **kwargs)
145+
response.status_code = kwargs["status_code"]
146+
return response
147+
148+
return super().get(request, *args, **kwargs)
149+
149150
def get_context_data(self, **kwargs):
150151
context = super().get_context_data(**kwargs)
151152
context["ooi_id"] = self.ooi_id

rocky/tests/objects/test_objects_detail.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def test_ooi_detail(
7171
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)
7272

7373
assert response.status_code == 200
74-
assert mock_organization_view_octopoes().get_tree.call_count == 2
74+
assert mock_organization_view_octopoes().get_tree.call_count == 1
7575
assertContains(response, "Object")
7676
assertContains(response, "Network|testnetwork")
7777

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

111111
assert response.status_code == 200
112-
assert mock_organization_view_octopoes().get_tree.call_count == 2
112+
assert mock_organization_view_octopoes().get_tree.call_count == 1
113113

114114
assertContains(response, "Question")
115115
assertContains(response, "Rendered Question Form")
@@ -142,7 +142,7 @@ def test_answer_question(
142142
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)
143143

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

147147

148148
def test_answer_question_bad_schema(
@@ -217,7 +217,7 @@ def test_ooi_detail_start_scan(
217217
)
218218
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)
219219

220-
assert mock_organization_view_octopoes().get_tree.call_count == 2
220+
assert mock_organization_view_octopoes().get_tree.call_count == 1
221221

222222
assert response.status_code == 200
223223

@@ -263,7 +263,7 @@ def test_ooi_detail_start_scan_no_indemnification(
263263
)
264264
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)
265265

266-
assert mock_organization_view_octopoes().get_tree.call_count == 2
266+
assert mock_organization_view_octopoes().get_tree.call_count == 1
267267
assertContains(response, "Object details")
268268
assertContains(response, "Indemnification not present")
269269

@@ -295,7 +295,7 @@ def test_ooi_detail_start_scan_no_action(
295295
)
296296
response = OOIDetailView.as_view()(request, organization_code=client_member.organization.code)
297297

298-
assert mock_organization_view_octopoes().get_tree.call_count == 2
298+
assert mock_organization_view_octopoes().get_tree.call_count == 1
299299
assertContains(response, "Object details")
300300

301301

rocky/tests/objects/test_objects_scan_profile.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_scan_profile(rf, redteam_member, mock_scheduler, mock_organization_view
5959
response = ScanProfileDetailView.as_view()(request, organization_code=redteam_member.organization.code)
6060

6161
assert response.status_code == 200
62-
assert mock_organization_view_octopoes().get_tree.call_count == 2
62+
assert mock_organization_view_octopoes().get_tree.call_count == 1
6363

6464
assertContains(response, "Set clearance level")
6565

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

127127
assert response.status_code == 200
128-
assert mock_organization_view_octopoes().get_tree.call_count == 2
128+
assert mock_organization_view_octopoes().get_tree.call_count == 1
129129

130130
assertNotContains(response, "Set clearance level")
131131

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

148148
assert response.status_code == 200
149-
assert mock_organization_view_octopoes().get_tree.call_count == 2
149+
assert mock_organization_view_octopoes().get_tree.call_count == 1
150150

151151
assertNotContains(response, "Set clearance level")
152152

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

164164
assert response.status_code == 200
165-
assert mock_organization_view_octopoes().get_tree.call_count == 2
165+
assert mock_organization_view_octopoes().get_tree.call_count == 1
166166

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

185185
assert response.status_code == 302
186-
assert mock_organization_view_octopoes().get_tree.call_count == 2
186+
assert mock_organization_view_octopoes().get_tree.call_count == 1
187187
assert mock_organization_view_octopoes().save_scan_profile.call_count == 1

0 commit comments

Comments
 (0)