Skip to content

Commit

Permalink
Add Threats Radar
Browse files Browse the repository at this point in the history
  • Loading branch information
ab-smith committed May 13, 2024
1 parent b5cc5bd commit e9960ef
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 33 deletions.
59 changes: 44 additions & 15 deletions backend/core/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,22 +255,24 @@ def get_sorted_requirement_nodes_rec(
"parent_urn": node.parent_urn,
"ref_id": node.ref_id,
"name": node.name,
"implementation_groups": node.implementation_groups
if node.implementation_groups
else None,
"implementation_groups": (
node.implementation_groups if node.implementation_groups else None
),
"ra_id": str(req_as.id) if requirements_assessed else None,
"status": req_as.status if requirements_assessed else None,
"is_scored": req_as.is_scored if requirements_assessed else None,
"score": req_as.score if requirements_assessed else None,
"max_score": req_as.compliance_assessment.framework.max_score
if requirements_assessed
else None,
"status_display": req_as.get_status_display()
if requirements_assessed
else None,
"status_i18n": camel_case(req_as.status)
if requirements_assessed
else None,
"max_score": (
req_as.compliance_assessment.framework.max_score
if requirements_assessed
else None
),
"status_display": (
req_as.get_status_display() if requirements_assessed else None
),
"status_i18n": (
camel_case(req_as.status) if requirements_assessed else None
),
"node_content": node.display_long,
"style": "node",
"assessable": node.assessable,
Expand All @@ -293,9 +295,11 @@ def get_sorted_requirement_nodes_rec(
{
"urn": req.urn,
"ref_id": req.ref_id,
"implementation_groups": req.implementation_groups
if req.implementation_groups
else None,
"implementation_groups": (
req.implementation_groups
if req.implementation_groups
else None
),
"name": req.name,
"description": req.description,
"ra_id": str(req_as.id),
Expand Down Expand Up @@ -950,3 +954,28 @@ def compile_risk_assessment_for_composer(user, risk_assessment_list: list):
},
"colors": get_risk_color_ordered_list(user, risk_assessment_list),
}


def threats_count_per_name(user: User):
labels = list()
values = list()
(
object_ids_view,
_,
_,
) = RoleAssignment.get_accessible_object_ids(Folder.get_root_folder(), user, Threat)

# expected by echarts to send the threats names in labels and the count of each threat in values

for threat in Threat.objects.filter(id__in=object_ids_view).order_by("name"):
val = RiskScenario.objects.filter(threats=threat).count()
if val > 0:
labels.append({"name": threat.name})
values.append(val)
max_offset = max(values, default=0) # we can add x later on to improve visibility

# update each label to include the max_offset
for label in labels:
label["max"] = max_offset

return {"labels": labels, "values": values}
4 changes: 4 additions & 0 deletions backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ class ThreatViewSet(BaseModelViewSet):
filterset_fields = ["folder", "risk_scenarios"]
search_fields = ["name", "provider", "description"]

@action(detail=False, name="Get threats count")
def threats_count(self, request):
return Response({"results": threats_count_per_name(request.user)})


class AssetViewSet(BaseModelViewSet):
"""
Expand Down
4 changes: 3 additions & 1 deletion frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -513,5 +513,7 @@
"userWillBeDisconnected": "The user will be disconnected and will need to log in again",
"scoresDefinition": "Scores definition",
"selectedImplementationGroups": "Selected implementation groups",
"implementationGroupsDefinition": "Implementation groups definition"
"implementationGroupsDefinition": "Implementation groups definition",
"threatRadarChart": "Threat radar",
"noThreatsMapped": "No threats mapped. Consider attaching threats to your risk scenarios for a better overview."
}
5 changes: 4 additions & 1 deletion frontend/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -513,5 +513,8 @@
"userWillBeDisconnected": "L'utilisateur sera déconnecté et devra se reconnecter",
"scoresDefinition": "Définition des scores",
"selectedImplementationGroups": "Groupes d'implémentation sélectionnés",
"implementationGroupsDefinition": "Définition des groupes d'implémentation"
"implementationGroupsDefinition": "Définition des groupes d'implémentation",
"threatRadarChart": "Radar des menaces",
"noThreatsMapped": "Aucune menace n'a été attachée. Pensez à lier les menaces à vos scénarios de risque pour une meilleure visibilité."

}
4 changes: 3 additions & 1 deletion frontend/messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -513,5 +513,7 @@
"userWillBeDisconnected": "O usuário será desconectado e precisará fazer login novamente",
"scoresDefinition": "Definição de pontuações",
"selectedImplementationGroups": "Grupos de implementação selecionados",
"implementationGroupsDefinition": "Definição de grupos de implementação"
"implementationGroupsDefinition": "Definição de grupos de implementação",
"threatRadarChart": "Radar de ameaças",
"noThreatsMapped": "Nenhuma ameaça mapeada. Considere anexar ameaças aos seus cenários de risco para ter uma visão geral melhor."
}
20 changes: 7 additions & 13 deletions frontend/src/lib/components/Chart/RadarChart.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
export let title = '';
export let values: any[]; // Set the types for these variables later on
export let colors: string[] = [];
export let labels: any[];
for (const index in values) {
if (values[index].localName) {
Expand Down Expand Up @@ -42,24 +43,17 @@
data: ['Allocated Budget', 'Actual Spending']
},
radar: {
//shape: 'circle',
indicator: [
{ name: 'Rogue Admin', },
{ name: 'Unavailability', },
{ name: 'Regulation', },
{ name: 'Data Breach', },
{ name: 'Phishing', },
{ name: 'Ransomware', }
]
shape: 'circle',
indicator: labels
},
series: [
{
name: 'Budget vs spending',
name: s_label,
type: 'radar',
data: [
{
value: [500, 600, 700, 800, 900, 1000],
name: 'Current'
value: values,
name: 'Radar'
},
]
}
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/routes/(app)/analytics/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export const load: PageServerLoad = async ({ locals, fetch }) => {
residual: Record<string, any>[];
} = await req_get_risks_count_per_level.json().then((res) => res.results);

const threats_count = await fetch(`${BASE_API_URL}/threats/threats_count/`).then((res) => res.json());

const req_get_measures_to_review = await fetch(`${BASE_API_URL}/applied-controls/to_review/`);
const measures_to_review = await req_get_measures_to_review.json();

Expand Down Expand Up @@ -194,6 +196,7 @@ export const load: PageServerLoad = async ({ locals, fetch }) => {
complianceAssessmentsPerStatus,
riskScenariosPerStatus,
risks_count_per_level,
threats_count,
measures_to_review: measures_to_review.results,
acceptances_to_review: acceptances_to_review.results,
risk_assessments: risk_assessments.results,
Expand Down
13 changes: 11 additions & 2 deletions frontend/src/routes/(app)/analytics/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,22 @@
</section>
{:else if tabSet === 1}
<!-- Risk tab -->

<section>
{#if (data.threats_count.results.labels.length > 0)}
<div class=" h-96 my-2">
<RadarChart
name="blalba"
title="Risk Radar"
name="threatRadar"
title={m.threatRadarChart()}
labels={data.threats_count.results.labels}
values={data.threats_count.results.values}
/>
</div>
{:else}
<div class="py-4 flex items-center justify-center">
<p class="">{m.noThreatsMapped()}</p>
</div>
{/if}
<div class="flex">
<div class="h-96 flex-1">
<span class="text-sm font-semibold">{m.currentRiskLevelPerScenario()}</span>
Expand Down

0 comments on commit e9960ef

Please sign in to comment.