Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/improve mapping inference additional information #1070

Merged
78 changes: 59 additions & 19 deletions backend/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2778,48 +2778,71 @@ def compute_requirement_assessments_results(
) -> list["RequirementAssessment"]:
requirement_assessments: list[RequirementAssessment] = []
result_order = (
RequirementAssessment.Result.NOT_ASSESSED,
RequirementAssessment.Result.NOT_APPLICABLE,
RequirementAssessment.Result.NON_COMPLIANT,
RequirementAssessment.Result.PARTIALLY_COMPLIANT,
RequirementAssessment.Result.COMPLIANT,
)

def assign_attributes(target, attributes):
"""
Helper function to assign attributes to a target object.
Only assigns if the attribute is not None.
"""
keys = ["result", "status", "score", "is_scored", "observation"]
for key, value in zip(keys, attributes):
if value is not None:
setattr(target, key, value)

for requirement_assessment in self.requirement_assessments.all():
mappings = mapping_set.mappings.filter(
target_requirement=requirement_assessment.requirement
)
inferences = []
refs = []

# Filter for full coverage relationships if applicable
if mappings.filter(
relationship__in=RequirementMapping.FULL_COVERAGE_RELATIONSHIPS
).exists():
mappings = mappings.filter(
relationship__in=RequirementMapping.FULL_COVERAGE_RELATIONSHIPS
)

for mapping in mappings:
source_requirement_assessment = RequirementAssessment.objects.get(
compliance_assessment=source_assessment,
requirement=mapping.source_requirement,
)
inferred_result, inferred_status = requirement_assessment.infer_result(
inferred_result = requirement_assessment.infer_result(
mapping=mapping,
source_requirement_assessment=source_requirement_assessment,
)
if inferred_result in result_order:
inferences.append((inferred_result, inferred_status))
if inferred_result.get("result") in result_order:
inferences.append(
(
inferred_result.get("result"),
inferred_result.get("status"),
inferred_result.get("score"),
inferred_result.get("is_scored"),
inferred_result.get("observation"),
)
)
refs.append(source_requirement_assessment)

if inferences:
if len(inferences) == 1:
requirement_assessment.result = inferences[0][0]
if inferences[0][1]:
requirement_assessment.status = inferences[0][1]
selected_inference = inferences[0]
ref = refs[0]
else:
lowest_result = min(
selected_inference = min(
inferences, key=lambda x: result_order.index(x[0])
)
requirement_assessment.result = lowest_result[0]
if lowest_result[1]:
requirement_assessment.status = lowest_result[1]
ref = refs[inferences.index(lowest_result)]
ref = refs[inferences.index(selected_inference)]

assign_attributes(requirement_assessment, selected_inference)

requirement_assessment.mapping_inference = {
"result": requirement_assessment.result,
"source_requirement_assessment": {
Expand All @@ -2829,7 +2852,9 @@ def compute_requirement_assessments_results(
},
# "mappings": [mapping.id for mapping in mappings],
}

requirement_assessments.append(requirement_assessment)

return requirement_assessments

def progress(self) -> int:
Expand Down Expand Up @@ -2927,24 +2952,39 @@ def get_requirement_description(self) -> str:

def infer_result(
self, mapping: RequirementMapping, source_requirement_assessment: Self
) -> str | None:
) -> dict | None:
if mapping.coverage == RequirementMapping.Coverage.FULL:
return (
source_requirement_assessment.result,
source_requirement_assessment.status,
)
if (
source_requirement_assessment.compliance_assessment.min_score
== self.compliance_assessment.min_score
and source_requirement_assessment.compliance_assessment.max_score
== self.compliance_assessment.max_score
):
return {
"result": source_requirement_assessment.result,
"status": source_requirement_assessment.status,
"score": source_requirement_assessment.score,
"is_scored": source_requirement_assessment.is_scored,
"observation": source_requirement_assessment.observation,
}
else:
return {
"result": source_requirement_assessment.result,
"status": source_requirement_assessment.status,
"observation": source_requirement_assessment.observation,
}
if mapping.coverage == RequirementMapping.Coverage.PARTIAL:
if source_requirement_assessment.result in (
RequirementAssessment.Result.COMPLIANT,
RequirementAssessment.Result.PARTIALLY_COMPLIANT,
):
return (RequirementAssessment.Result.PARTIALLY_COMPLIANT, None)
return {"result": RequirementAssessment.Result.PARTIALLY_COMPLIANT}
if (
source_requirement_assessment.result
== RequirementAssessment.Result.NON_COMPLIANT
):
return (RequirementAssessment.Result.NON_COMPLIANT, None)
return (None, None)
return {"result": RequirementAssessment.Result.NON_COMPLIANT}
return {}

def create_applied_controls_from_suggestions(self) -> list[AppliedControl]:
applied_controls: list[AppliedControl] = []
Expand Down
4 changes: 3 additions & 1 deletion frontend/messages/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -857,5 +857,7 @@
"tags": "العلامات",
"addTag": "إضافة علامة",
"tagsHelpText": "تُستخدم العلامات لتصنيف العناصر وتصفيتها. يمكنك إضافة علامات في قسم \"إضافي\"",
"forgotPassword": "هل نسيت كلمة السر"
"forgotPassword": "هل نسيت كلمة السر",
"scoreSemiColon": "نتيجة:",
"mappingInferenceHelpText": "هذه المتغيرات ثابتة ولن تتغير اعتمادًا على المصدر."
}
4 changes: 3 additions & 1 deletion frontend/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "Schlagwörter",
"addTag": "Tag hinzufügen",
"tagsHelpText": "Tags werden zum Kategorisieren und Filtern der Elemente verwendet. Sie können Tags im Abschnitt Extra hinzufügen",
"forgotPassword": "Passwort vergessen"
"forgotPassword": "Passwort vergessen",
"scoreSemiColon": "Punktzahl:",
"mappingInferenceHelpText": "Diese Variablen sind fest und ändern sich je nach Quelle nicht."
}
2 changes: 2 additions & 0 deletions frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,8 @@
"youCanSetPasswordHere": "You can set your password here",
"forgotPassword": "Forgot password",
"ssoSettingsUpdated": "SSO settings updated",
"scoreSemiColon": "Score:",
"mappingInferenceHelpText": "These variables are fixed and will not change depending on the source.",
"priority": "Priority",
"p1": "P1",
"p2": "P2",
Expand Down
4 changes: 3 additions & 1 deletion frontend/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "Etiquetas",
"addTag": "Agregar etiqueta",
"tagsHelpText": "Las etiquetas se utilizan para categorizar y filtrar los elementos. Puedes agregar etiquetas en la sección Extra",
"forgotPassword": "Has olvidado tu contraseña"
"forgotPassword": "Has olvidado tu contraseña",
"scoreSemiColon": "Puntaje:",
"mappingInferenceHelpText": "Estas variables son fijas y no cambiarán dependiendo de la fuente."
}
4 changes: 3 additions & 1 deletion frontend/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -864,5 +864,7 @@
"existingMeasures": "Mesures existantes",
"youCanSetPasswordHere": "Vous pouvez définir votre mot de passe ici",
"forgotPassword": "Mot de passe oublié",
"ssoSettingsUpdated": "Paramètres SSO mis à jour"
"ssoSettingsUpdated": "Paramètres SSO mis à jour",
"scoreSemiColon": "Score:",
"mappingInferenceHelpText": "Ces variables sont fixes et ne changeront pas en fonction de la source."
}
4 changes: 3 additions & 1 deletion frontend/messages/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "टैग",
"addTag": "टैग जोड़ें",
"tagsHelpText": "टैग का उपयोग आइटम को वर्गीकृत और फ़िल्टर करने के लिए किया जाता है। आप अतिरिक्त अनुभाग में टैग जोड़ सकते हैं",
"forgotPassword": "पासवर्ड भूल गए"
"forgotPassword": "पासवर्ड भूल गए",
"scoreSemiColon": "अंक:",
"mappingInferenceHelpText": "ये चर निश्चित हैं और स्रोत के आधार पर परिवर्तित नहीं होंगे।"
}
4 changes: 3 additions & 1 deletion frontend/messages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "Etichette",
"addTag": "Aggiungi tag",
"tagsHelpText": "I tag vengono utilizzati per categorizzare e filtrare gli elementi. Puoi aggiungere tag nella sezione Extra",
"forgotPassword": "Ha dimenticato la password"
"forgotPassword": "Ha dimenticato la password",
"scoreSemiColon": "Punto:",
"mappingInferenceHelpText": "Queste variabili sono fisse e non cambiano a seconda della fonte."
}
4 changes: 3 additions & 1 deletion frontend/messages/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "Labels",
"addTag": "Tag toevoegen",
"tagsHelpText": "Tags worden gebruikt om de items te categoriseren en te filteren. U kunt tags toevoegen in de sectie Extra",
"forgotPassword": "Wachtwoord vergeten"
"forgotPassword": "Wachtwoord vergeten",
"scoreSemiColon": "Punt:",
"mappingInferenceHelpText": "Deze variabelen zijn vast en veranderen niet, afhankelijk van de bron."
}
4 changes: 3 additions & 1 deletion frontend/messages/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "Tagi",
"addTag": "Dodaj tag",
"tagsHelpText": "Tagi służą do kategoryzowania i filtrowania elementów. Możesz dodać tagi w sekcji Extra",
"forgotPassword": "Zapomniałem hasła"
"forgotPassword": "Zapomniałem hasła",
"scoreSemiColon": "Wynik:",
"mappingInferenceHelpText": "Te zmienne są stałe i nie zmieniają się w zależności od źródła."
}
4 changes: 3 additions & 1 deletion frontend/messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "Etiquetas",
"addTag": "Adicionar etiqueta",
"tagsHelpText": "As tags são usadas para categorizar e filtrar os itens. Você pode adicionar tags na seção Extra",
"forgotPassword": "Esqueceu sua senha"
"forgotPassword": "Esqueceu sua senha",
"scoreSemiColon": "Pontuação:",
"mappingInferenceHelpText": "Essas variáveis são fixas e não mudarão dependendo da fonte."
}
4 changes: 3 additions & 1 deletion frontend/messages/ro.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "Etichete",
"addTag": "Adăugați etichetă",
"tagsHelpText": "Etichetele sunt folosite pentru a clasifica și filtra articolele. Puteți adăuga etichete în secțiunea Extra",
"forgotPassword": "Aţi uitat parola"
"forgotPassword": "Aţi uitat parola",
"scoreSemiColon": "Scor:",
"mappingInferenceHelpText": "Aceste variabile sunt fixe și nu se vor modifica în funcție de sursă."
}
4 changes: 3 additions & 1 deletion frontend/messages/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -860,5 +860,7 @@
"existingMeasures": "Befintliga kontroller",
"youCanSetPasswordHere": "Du kan ställa in ditt lösenord här",
"forgotPassword": "Glömt lösenord",
"ssoSettingsUpdated": "SSO-inställningar uppdaterade"
"ssoSettingsUpdated": "SSO-inställningar uppdaterade",
"scoreSemiColon": "Göra:",
"mappingInferenceHelpText": "Dessa variabler är fasta och kommer inte att ändras beroende på källan."
}
4 changes: 3 additions & 1 deletion frontend/messages/ur.json
Original file line number Diff line number Diff line change
Expand Up @@ -856,5 +856,7 @@
"tags": "ٹیگز",
"addTag": "ٹیگ شامل کریں۔",
"tagsHelpText": "ٹیگز اشیاء کی درجہ بندی اور فلٹر کرنے کے لیے استعمال ہوتے ہیں۔ آپ اضافی سیکشن میں ٹیگ شامل کر سکتے ہیں۔",
"forgotPassword": "پاس ورڈ بھول گئے۔"
"forgotPassword": "پاس ورڈ بھول گئے۔",
"scoreSemiColon": "سکور:",
"mappingInferenceHelpText": "یہ متغیرات طے شدہ ہیں اور ماخذ کے لحاظ سے تبدیل نہیں ہوں گے۔"
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@
<i class="fa-solid fa-link" />
{m.mappingInference()}
</p>
<span class="text-xs text-gray-500"
><i class="fa-solid fa-circle-info"></i> {m.mappingInferenceHelpText()}</span
>
<ul class="list-disc ml-4">
<li>
<p>
Expand All @@ -205,7 +208,7 @@
</p>
<p class="whitespace-pre-line py-1">
<span class="italic">{m.coverageColon()}</span>
<span class="badge {classesText} h-fit">
<span class="badge h-fit">
{safeTranslate(
toCamelCase(mappingInference.sourceRequirementAssessment.coverage)
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,9 @@
<i class="fa-solid fa-link" />
{m.mappingInference()}
</p>
<span class="text-xs text-gray-500"
><i class="fa-solid fa-circle-info"></i> {m.mappingInferenceHelpText()}</span
>
<ul class="list-disc ml-4">
<li>
<p>
Expand All @@ -340,7 +343,7 @@
</p>
<p class="whitespace-pre-line py-1">
<span class="italic">{m.coverageColon()}</span>
<span class="badge {classesText} h-fit">
<span class="badge h-fit">
{safeTranslate(mappingInference.sourceRequirementAssessment.coverage)}
</span>
</p>
Expand Down
Loading