From cbd0832ca173233ad78258c580d3480b36cd29c9 Mon Sep 17 00:00:00 2001 From: Amir Date: Mon, 12 May 2025 22:48:16 +0200 Subject: [PATCH 1/2] Promenjene vrednosti weight + likelihood --- backend/core/tables.py | 70 ++++++++++++++------------------ backend/core/tests/test_utils.py | 6 +-- backend/core/utils.py | 38 ++++++++--------- backend/settings.py | 3 +- document_template.yml | 30 +++++++------- 5 files changed, 69 insertions(+), 78 deletions(-) diff --git a/backend/core/tables.py b/backend/core/tables.py index 811e01f..ad97d47 100644 --- a/backend/core/tables.py +++ b/backend/core/tables.py @@ -4,56 +4,48 @@ from backend.core.utils import calculate_aggregate_likelihood, calculate_aggrega def risk_matrix_table(): likelihood_labels = [ - "Certain (90-100%)", - "Almost Certain (80-89%)", - "Very Probable (70-79%)", - "Probable (60-69%)", - "Highly Likely (50-59%)", - "Likely (40-49%)", - "Occasional (30-39%)", - "Possible (20-29%)", - "Unlikely (10-19%)", - "Rare (0-9%)" + "Almost Certain (90-100%) (5)", + "Probable (51-89%) (4)", + "Possible (25-50%) (3)", + "Unlikely (11-24%) (2)", + "Rare (0-10%) (1)" ] impact_labels = [ - "Insignificant", - "Minor", - "Moderate", - "Major", - "Severe", - "Catastrophic", - "Critical", - "Extreme", - "Disastrous", - "Unrecoverable" + "Insignificant (1)", + "Significant (2)", + "Severe (3)", + "Material (4)", + "Major (5)" ] color_mapping = { - "Very Low": "green", - "Low": "lightgreen", + "Very Low": "lightgreen", + "Low": "green", "Medium": "yellow", "High": "orange", "Critical": "red" } - table_matrix_risk = [["Impact ↓ / Likelihood →"] + impact_labels] + def get_label(score): + if score <= 2: + return "Very Low" + elif score <= 4: + return "Low" + elif score <= 10: + return "Medium" + elif score <= 16: + return "High" + else: + return "Critical" - for likelihood_index, likelihood_label in enumerate(likelihood_labels, start=1): - reversed_index = 11 - likelihood_index - row = [likelihood_label] - for impact_index in range(1, 11): - score = reversed_index * impact_index - if score <= 20: - label = "Very Low" - elif score <= 40: - label = "Low" - elif score <= 60: - label = "Medium" - elif score <= 80: - label = "High" - else: - label = "Critical" + table_matrix_risk = [["Likelihood ↓ / Impact →"] + impact_labels] + + for likelihood in range(5, 0, -1): + row = [likelihood_labels[5 - likelihood]] + for impact in range(1, 6): + score = likelihood * impact + label = get_label(score) color_class = color_mapping[label] row.append((score, label, color_class)) table_matrix_risk.append(row) @@ -82,7 +74,7 @@ def get_risk_table(document): .values('control', 'control__name', 'weight', 'likelihood') .distinct() ) - max_weight = 10*10 + max_weight = 10*5 total_weight = calculate_aggregate_weight(controls) total_likelihood = calculate_aggregate_likelihood(controls) impact, likelihood = map_weight_to_impact_likelihood(total_weight, total_likelihood, max_weight) diff --git a/backend/core/tests/test_utils.py b/backend/core/tests/test_utils.py index 1048d64..0c68a11 100644 --- a/backend/core/tests/test_utils.py +++ b/backend/core/tests/test_utils.py @@ -71,7 +71,7 @@ class UtilsTests(TestCase): mock_openai.return_value = mock_client mock_response = MagicMock() - control_lines = [f"{i} : 8 : 5" for i in range(1, 11)] + control_lines = [f"{i} : 4 : 3" for i in range(1, 11)] mock_response.choices[0].message.content = "\n".join(control_lines) mock_client.chat.completions.create.return_value = mock_response @@ -100,7 +100,7 @@ class UtilsTests(TestCase): self.assertEqual(calculate_aggregate_likelihood(controls), 6) def test_map_weight_to_impact_likelihood(self): - impact, likelihood = map_weight_to_impact_likelihood(50, 30, 100) + impact, likelihood = map_weight_to_impact_likelihood(50, 30, 50) self.assertAlmostEqual(impact, 5.0) self.assertAlmostEqual(likelihood, 3.0) @@ -123,7 +123,7 @@ class UtilsTests(TestCase): def test_generate_risk_graph(self): risks_with_controls = [ {'risk': {'id': 1}, 'impact': 5.0, 'likelihood': 3.0}, - {'risk': {'id': 2}, 'impact': 7.0, 'likelihood': 4.0} + {'risk': {'id': 2}, 'impact': 4.0, 'likelihood': 4.0} ] graph_data = generate_risk_graph(risks_with_controls) diff --git a/backend/core/utils.py b/backend/core/utils.py index 9f30c0c..1d2ea27 100644 --- a/backend/core/utils.py +++ b/backend/core/utils.py @@ -90,14 +90,14 @@ def get_controls_for_risk(risk, organization): prompt = f""" You are an expert in cybersecurity risk management. Given the risk "{risk.risk_name}" and its associated organization details "{organization_details}", your task is to select **exactly 10 unique controls** from the provided list that best mitigate this risk. Each control should be assigned: - - A weight between **1 and 10** (1 = low impact, 10 = high impact). - - A likelihood score between **1 and 10** (1 = rare occurrence, 10 = highly likely). + - A weight between **1 and 5** (1 = low impact, 5 = high impact). + - A likelihood score between **1 and 5** (1 = rare occurrence, 5 = highly likely). ### Rules: 1. **Each control ID must be unique** (no duplicates). 2. **Only return control IDs, weights, and likelihood scores** in the exact format below. - 3. **Weights must be between 1 and 10** (1 = low impact, 10 = high impact). - 4. **Likelihood scores must be between 1 and 10** (1 = rare occurrence, 10 = highly likely). + 3. **Weights must be between 1 and 5** (1 = low impact, 5 = high impact). + 4. **Likelihood scores must be between 1 and 5** (1 = rare occurrence, 5 = highly likely). 5. **Do NOT add explanations, descriptions, or extra text.** 6. **Ensure that control IDs are randomly distributed and diverse across different categories.** ### Available Controls: @@ -108,8 +108,8 @@ def get_controls_for_risk(risk, organization): : : ### Example Correct Response (NO DUPLICATES): - 12 : 8 : 90 - 45 : 7 : 60 + 12 : 5 : 2 + 45 : 4 : 1 ⚠️ **If you provide duplicate control IDs, your response will be rejected. Ensure all control IDs are unique.** ⚠️ **Follow the response format exactly. Any deviation will be considered invalid.** @@ -138,7 +138,7 @@ def get_controls_for_risk(risk, organization): weight = int(weight_str) likelihood = int(likelihood_str) - if control_id in valid_control_ids and 1 <= weight <= 10 and 1 <= likelihood <= 10 and control_id not in control_ids_seen: + if control_id in valid_control_ids and 1 <= weight <= 5 and 1 <= likelihood <= 5 and control_id not in control_ids_seen: selected_controls.append((control_id, weight, likelihood)) control_ids_seen.add(control_id) except ValueError: @@ -155,14 +155,14 @@ def get_controls_for_risk(risk, organization): retry_prompt = f""" You are an expert in cybersecurity risk management. Given the risk "{risk.risk_name}" and the organization's details "{organization_details}", your task is to select **exactly {missing_count} unique controls** from the provided list that best mitigate this risk. Each control should be assigned: - - A **weight** between **1 and 10** based on its effectiveness in reducing the risk. - - A likelihood score between **1 and 10** (1 = rare occurrence, 10 = highly likely). + - A **weight** between **1 and 5** based on its effectiveness in reducing the risk. + - A likelihood score between **1 and 5** (1 = rare occurrence, 5 = highly likely). ### Rules: 1. **Each control ID must be unique** (no duplicates). 2. **Only return control IDs, weights, and likelihood scores** in the exact format below. - 3. **Weights must be between 1 and 10** (1 = low impact, 10 = high impact). - 4. **Likelihood scores must be between 1 and 10** (1 = rare occurrence, 10 = highly likely). + 3. **Weights must be between 1 and 5** (1 = low impact, 5 = high impact). + 4. **Likelihood scores must be between 1 and 5** (1 = rare occurrence, 5 = highly likely). 5. **Do NOT add explanations, descriptions, or extra text.** 6. **Ensure that control IDs are diverse and well-distributed across different categories.** @@ -174,8 +174,8 @@ def get_controls_for_risk(risk, organization): : : ### Example Correct Response (NO DUPLICATES): - 12 : 8 : 85 - 45 : 7 : 60 + 12 : 4 : 5 + 45 : 5 : 3 ⚠️ **If you provide duplicate control IDs, your response will be rejected. Ensure all control IDs are unique.** ⚠️ **Follow the response format exactly. Any deviation will be considered invalid.** @@ -201,7 +201,7 @@ def get_controls_for_risk(risk, organization): weight = int(weight_str) likelihood = int(likelihood_str) - if control_id in valid_control_ids and 1 <= weight <= 10 and 1 <= likelihood <= 10 and control_id not in control_ids_seen: + if control_id in valid_control_ids and 1 <= weight <= 5 and 1 <= likelihood <= 5 and control_id not in control_ids_seen: selected_controls.append((control_id, weight, likelihood)) control_ids_seen.add(control_id) except ValueError: @@ -243,10 +243,8 @@ def calculate_aggregate_likelihood(controls): return total_likelihood def map_weight_to_impact_likelihood(total_weight, total_likelihood, max_weight): - normalized_weight = total_weight / max_weight - - impact = min(10.0, max(1.0, normalized_weight * 10.0)) - likelihood = min(10.0, max(1.0, total_likelihood / 10.0)) + impact = min(5.0, max(1.0, total_weight / 10.0)) + likelihood = min(5.0, max(1.0, total_likelihood / 10.0)) return impact, likelihood @@ -256,12 +254,12 @@ def generate_risk_graph(risks_with_controls): likelihoods = [risk['likelihood'] for risk in risks_with_controls] risk_ids = [risk['risk']['id'] for risk in risks_with_controls] - bg_img_path = find('img/graph_matrix (3).png') + bg_img_path = find('img/graph_matrix.png') bg_img = mpimg.imread(bg_img_path) fig, ax = plt.subplots(figsize=(10, 8)) - ax.imshow(bg_img, extent=[0, 11.2, 0, 11.2], aspect='auto') + ax.imshow(bg_img, extent=[0.0, 5.4, 0.0, 5.4], aspect='auto') scatter = ax.scatter( likelihoods, impacts, diff --git a/backend/settings.py b/backend/settings.py index 1b5c616..7da5b19 100644 --- a/backend/settings.py +++ b/backend/settings.py @@ -37,7 +37,8 @@ DEBUG = config('DEBUG', default=False, cast=bool) ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv()) -SITE_DOMAIN = "http://64.226.105.114" +#SITE_DOMAIN = "http://64.226.105.114" +SITE_DOMAIN = "http://127.0.0.1:8000" # Application definition diff --git a/document_template.yml b/document_template.yml index 9f96751..6b33e63 100644 --- a/document_template.yml +++ b/document_template.yml @@ -148,26 +148,26 @@ Impact is aslo defined with the following table: headers: ["Level", "Financial Cost", "Reputational Impact", "Management Effort", "Operational Resources", "RPO", "RTO"] rows: - - ["Insignificant (1-2)", "< 0.05% Material", "Normal", "Normal", "Normal", "16 hr", "64 hr"] - - ["Significant (3-4)", "> 0.5% Material", "Minor", "Minor", "Minor", "8 hr", "32 hr"] - - ["Severe (5-6)", "> 10% Material", "Moderate", "Moderate", "Moderate", "4 hr", "16 hr"] - - ["Material (7-8)", "> 50% Material", "Critical", "Critical", "Critical", "2 hr", "8 hr"] - - ["Major (9-10)", "> Material", "Precarious", "Precarious", "Precarious", "1 hr", "4 hr"] + - ["Insignificant (1)", "< 0.05% Material", "Normal", "Normal", "Normal", "16 hr", "64 hr"] + - ["Significant (2)", "> 0.5% Material", "Minor", "Minor", "Minor", "8 hr", "32 hr"] + - ["Severe (3)", "> 10% Material", "Moderate", "Moderate", "Moderate", "4 hr", "16 hr"] + - ["Material (4)", "> 50% Material", "Critical", "Critical", "Critical", "2 hr", "8 hr"] + - ["Major (5)", "> Material", "Precarious", "Precarious", "Precarious", "1 hr", "4 hr"] - segment_type: "list_stack_sights" content: - description: | For determining likelihood, we use StackSight's commonly referenced scale: - - level: 1-2 - description: "0-3% chance of happening in a year" - - level: 3-4 - description: "4-10% chance of happening in a year" - - level: 5-6 - description: "11-50% chance of happening in a year" - - level: 7-8 - description: "51-90% chance of happening in a year" - - level: 9-10 - description: "91-100% chance of happening in a year" + - level: 1 + description: 1. "0-3% chance of happening in a year" + - level: 2 + description: 2. "4-10% chance of happening in a year" + - level: 3 + description: 3. "11-50% chance of happening in a year" + - level: 4 + description: 4. "51-90% chance of happening in a year" + - level: 5 + description: 5. "91-100% chance of happening in a year" - segment_type: "likelihood_table" content: -- 2.47.3 From 6ca57334313a9e037a6c655c170bfd7b066d52c0 Mon Sep 17 00:00:00 2001 From: Amir Date: Mon, 12 May 2025 22:51:59 +0200 Subject: [PATCH 2/2] site-domain quick fix --- backend/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/settings.py b/backend/settings.py index 7da5b19..ecea262 100644 --- a/backend/settings.py +++ b/backend/settings.py @@ -37,8 +37,8 @@ DEBUG = config('DEBUG', default=False, cast=bool) ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv()) -#SITE_DOMAIN = "http://64.226.105.114" -SITE_DOMAIN = "http://127.0.0.1:8000" +SITE_DOMAIN = "http://64.226.105.114" +#SITE_DOMAIN = "http://127.0.0.1:8000" # Application definition -- 2.47.3