-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Donny Peeters <[email protected]> Co-authored-by: stephanie0x00 <[email protected]> Co-authored-by: Donny Peeters <[email protected]> Co-authored-by: Ammar <[email protected]> Co-authored-by: Jan Klopper <[email protected]>
- Loading branch information
1 parent
3a4242f
commit 9cd33d3
Showing
10 changed files
with
440 additions
and
71 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{% load i18n %} | ||
|
||
<div class="horizontal-scroll"> | ||
{% if data %} | ||
{% include "partials/report_severity_totals.html" with data=data.summary %} | ||
|
||
<h2>{% translate "Findings" %}</h2> | ||
<div class="horizontal-scroll"> | ||
<table> | ||
<caption class="visually-hidden">{% translate "Other findings found:" %}</caption> | ||
<thead> | ||
<tr> | ||
<th scope="col">{% translate "FindingType" %}</th> | ||
<th scope="col">{% translate "Type" %}</th> | ||
<th scope="col">{% translate "Risk level" %}</th> | ||
<th scope="col">{% translate "Occurrences" %}</th> | ||
<th scope="col">{% translate "Details" %}</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{% for info in data.finding_types %} | ||
<tr> | ||
<td>{{ info.finding_type.id }}</td> | ||
<td>{{ info.finding_type.object_type }}</td> | ||
<td> | ||
<span class="{{ info.finding_type.risk_severity }}">{{ info.finding_type.risk_severity|capfirst }}</span> | ||
</td> | ||
<td>{{ info.occurrences|length }}</td> | ||
<td class="actions"> | ||
<button class="expando-button" | ||
data-icon-open-class="icon ti-chevron-down" | ||
data-icon-close-class="icon ti-chevron-up" | ||
data-close-label="{% translate "Close details" %}"> | ||
{% translate "Open details" %} | ||
</button> | ||
</td> | ||
</tr> | ||
<tr class="expando-row"> | ||
<td colspan="5"> | ||
<h2 class="heading-normal">{% translate "Description" %}</h2> | ||
<p>{{ info.finding_type.description }}</p> | ||
<h2 class="heading-normal">{% translate "Impact" %}</h2> | ||
<p>{{ info.finding_type.impact }}</p> | ||
<h2 class="heading-normal">{% translate "Recommendation" %}</h2> | ||
<p>{{ info.finding_type.recommendation }}</p> | ||
<h2 class="heading-normal">{% translate "Occurrences" %}</h2> | ||
<ul class="accordion break-title"> | ||
{% for occurrence in info.occurrences %} | ||
<li> | ||
<button aria-expanded="false">{{ occurrence.finding.ooi.human_readable }}</button> | ||
<div aria-labelledby="finding-details"> | ||
<h2>{% translate "First seen" %}</h2> | ||
<p>{{ occurrence.first_seen }}</p> | ||
<h2>{% translate "Description" %}</h2> | ||
<p>{{ occurrence.finding.description }}</p> | ||
</div> | ||
</li> | ||
{% endfor %} | ||
</ul> | ||
</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
</div> | ||
{% else %} | ||
<p>{% translate "No findings have been found." %}</p> | ||
{% endif %} | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
from datetime import datetime | ||
from logging import getLogger | ||
from typing import Any | ||
|
||
from django.utils.translation import gettext_lazy as _ | ||
|
||
from octopoes.models import Reference | ||
from octopoes.models.exception import ObjectNotFoundException | ||
from octopoes.models.ooi.findings import Finding, RiskLevelSeverity | ||
from octopoes.models.types import ALL_TYPES | ||
from reports.report_types.definitions import Report | ||
|
||
logger = getLogger(__name__) | ||
|
||
TREE_DEPTH = 9 | ||
SEVERITY_OPTIONS = [severity.value for severity in RiskLevelSeverity] | ||
|
||
|
||
class FindingsReport(Report): | ||
id = "findings-report" | ||
name = _("Findings Report") | ||
description = _("Shows all the finding types and their occurrences.") | ||
plugins = {"required": [], "optional": []} | ||
input_ooi_types = ALL_TYPES | ||
template_path = "findings_report/report.html" | ||
|
||
def get_finding_valid_time_history(self, reference: str) -> list[datetime]: | ||
transaction_record = self.octopoes_api_connector.get_history(reference=reference) | ||
valid_time_history = [transaction.valid_time for transaction in transaction_record] | ||
return valid_time_history | ||
|
||
def generate_data(self, input_ooi: str, valid_time: datetime) -> dict[str, Any]: | ||
reference = Reference.from_str(input_ooi) | ||
findings = [] | ||
finding_types: dict[str, Any] = {} | ||
total_by_severity = {} | ||
total_by_severity_per_finding_type = {} | ||
|
||
for severity in SEVERITY_OPTIONS: | ||
total_by_severity[severity] = 0 | ||
total_by_severity_per_finding_type[severity] = 0 | ||
|
||
tree = self.octopoes_api_connector.get_tree( | ||
reference, depth=TREE_DEPTH, types={Finding}, valid_time=valid_time | ||
).store | ||
|
||
for ooi in tree.values(): | ||
if ooi.ooi_type == "Finding": | ||
findings.append(ooi) | ||
|
||
for finding in findings: | ||
try: | ||
finding_type = self.octopoes_api_connector.get(Reference.from_str(finding.finding_type), valid_time) | ||
severity = finding_type.risk_severity.name.lower() | ||
total_by_severity[severity] += 1 | ||
|
||
time_history = self.get_finding_valid_time_history(finding.primary_key) | ||
|
||
if time_history: | ||
first_seen = str(time_history[0]) | ||
|
||
finding = {"finding": finding, "first_seen": first_seen} | ||
|
||
if finding_type.id in finding_types: | ||
finding_types[finding_type.id]["occurrences"].append(finding) | ||
else: | ||
finding_types[finding_type.id] = {"finding_type": finding_type, "occurrences": [finding]} | ||
total_by_severity_per_finding_type[severity] += 1 | ||
|
||
except ObjectNotFoundException: | ||
logger.error("No Finding Type found for Finding '%s' on date %s.", finding, str(valid_time)) | ||
|
||
sorted_finding_types: list[Any] = sorted( | ||
finding_types.values(), key=lambda x: x["finding_type"].risk_score or 0, reverse=True | ||
) | ||
|
||
summary = { | ||
"total_by_severity": total_by_severity, | ||
"total_by_severity_per_finding_type": total_by_severity_per_finding_type, | ||
"total_finding_types": len(sorted_finding_types), | ||
"total_occurrences": sum(total_by_severity.values()), | ||
} | ||
|
||
return {"finding_types": sorted_finding_types, "summary": summary} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
rocky/reports/templates/partials/report_severity_totals.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{% load i18n %} | ||
|
||
<section> | ||
<div> | ||
<h3>{% translate "Findings overview" %}</h3> | ||
<div class="column-2"> | ||
{% include "partials/report_severity_totals_table.html" %} | ||
|
||
</div> | ||
</div> | ||
</section> |
58 changes: 58 additions & 0 deletions
58
rocky/reports/templates/partials/report_severity_totals_table.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
{% load i18n %} | ||
|
||
<div class="horizontal-scroll"> | ||
<table> | ||
<caption class="visually-hidden">{% translate "Total per severity overview:" %}</caption> | ||
<thead> | ||
<tr> | ||
<th>{% translate "Risk level" %}</th> | ||
<th>{% translate "FindingTypes" %}</th> | ||
<th>{% translate "Occurrences" %}</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td> | ||
<span class="critical">Critical</span> | ||
</td> | ||
<td class="number">{{ data.total_by_severity_per_finding_type.critical }}</td> | ||
<td class="number">{{ data.total_by_severity.critical }}</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
<span class="high">High</span> | ||
</td> | ||
<td class="number">{{ data.total_by_severity_per_finding_type.high }}</td> | ||
<td class="number">{{ data.total_by_severity.high }}</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
<span class="medium">Medium</span> | ||
</td> | ||
<td class="number">{{ data.total_by_severity_per_finding_type.medium }}</td> | ||
<td class="number">{{ data.total_by_severity.medium }}</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
<span class="low">Low</span> | ||
</td> | ||
<td class="number">{{ data.total_by_severity_per_finding_type.low }}</td> | ||
<td class="number">{{ data.total_by_severity.low }}</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
<span class="recommendation">Recommendation</span> | ||
</td> | ||
<td class="number">{{ data.total_by_severity_per_finding_type.recommendation }}</td> | ||
<td class="number">{{ data.total_by_severity.recommendation }}</td> | ||
</tr> | ||
<tfoot> | ||
<tr> | ||
<td>Total</td> | ||
<td class="number">{{ data.total_finding_types }}</td> | ||
<td class="number">{{ data.total_occurrences }}</td> | ||
</tr> | ||
</tfoot> | ||
</tbody> | ||
</table> | ||
</div> |
Oops, something went wrong.