From 2dd31a2db502becda17ece13873de31ae9d2a650 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 20:00:45 +0100
Subject: [PATCH 01/25] feat: add strategic scenario
---
backend/core/startup.py | 4 ++
...ro_to_couple_strategicscenario_and_more.py | 47 +++++++++++++++++++
backend/ebios_rm/models.py | 33 ++++++++++++-
backend/ebios_rm/serializers.py | 19 +++++++-
backend/ebios_rm/urls.py | 2 +
backend/ebios_rm/views.py | 9 ++++
frontend/messages/en.json | 4 +-
.../src/lib/components/Forms/ModelForm.svelte | 3 ++
.../Forms/ModelForm/AttackPathForm.svelte | 15 +++---
.../ModelForm/StrategicScenarioForm.svelte | 34 ++++++++++++++
frontend/src/lib/utils/crud.ts | 24 ++++++----
frontend/src/lib/utils/schemas.ts | 9 +++-
frontend/src/lib/utils/table.ts | 8 +++-
frontend/src/lib/utils/types.ts | 1 +
.../operational-scenario/+page.server.ts | 14 ++++++
.../strategic-scenarios/+page.server.ts | 6 +--
16 files changed, 208 insertions(+), 24 deletions(-)
create mode 100644 backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
create mode 100644 frontend/src/lib/components/Forms/ModelForm/StrategicScenarioForm.svelte
diff --git a/backend/core/startup.py b/backend/core/startup.py
index 3196379e2..2ec1362d4 100644
--- a/backend/core/startup.py
+++ b/backend/core/startup.py
@@ -355,6 +355,10 @@
"view_stakeholder",
"change_stakeholder",
"delete_stakeholder",
+ "add_strategicscenario",
+ "view_strategicscenario",
+ "change_strategicscenario",
+ "delete_strategicscenario",
"add_attackpath",
"view_attackpath",
"change_attackpath",
diff --git a/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py b/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
new file mode 100644
index 000000000..8184e449c
--- /dev/null
+++ b/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
@@ -0,0 +1,47 @@
+# Generated by Django 5.1.4 on 2024-12-17 18:10
+
+import django.db.models.deletion
+import iam.models
+import uuid
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ebios_rm', '0006_alter_attackpath_stakeholders'),
+ ('iam', '0010_user_preferences'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='attackpath',
+ name='ro_to_couple',
+ ),
+ migrations.CreateModel(
+ name='StrategicScenario',
+ fields=[
+ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
+ ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
+ ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
+ ('is_published', models.BooleanField(default=False, verbose_name='published')),
+ ('name', models.CharField(max_length=200, verbose_name='Name')),
+ ('description', models.TextField(blank=True, null=True, verbose_name='Description')),
+ ('ref_id', models.CharField(blank=True, max_length=100)),
+ ('ebios_rm_study', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='strategic_scenarios', to='ebios_rm.ebiosrmstudy', verbose_name='EBIOS RM study')),
+ ('folder', models.ForeignKey(default=iam.models.Folder.get_root_folder_id, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_folder', to='iam.folder')),
+ ('ro_to_couple', models.ForeignKey(help_text='RO/TO couple from which the attach path is derived', on_delete=django.db.models.deletion.CASCADE, to='ebios_rm.roto', verbose_name='RO/TO couple')),
+ ],
+ options={
+ 'verbose_name': 'Strategic Scenario',
+ 'verbose_name_plural': 'Strategic Scenarios',
+ 'ordering': ['created_at'],
+ },
+ ),
+ migrations.AddField(
+ model_name='attackpath',
+ name='strategic_scenario',
+ field=models.ForeignKey(default='', help_text='Strategic scenario from which the attack path is derived', on_delete=django.db.models.deletion.CASCADE, related_name='attack_paths', to='ebios_rm.strategicscenario', verbose_name='Strategic scenario'),
+ preserve_default=False,
+ ),
+ ]
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index 71d6a9db9..295cb7769 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -374,10 +374,11 @@ def residual_criticality(self):
)
-class AttackPath(NameDescriptionMixin, FolderMixin):
+class StrategicScenario(NameDescriptionMixin, FolderMixin):
ebios_rm_study = models.ForeignKey(
EbiosRMStudy,
verbose_name=_("EBIOS RM study"),
+ related_name="strategic_scenarios",
on_delete=models.CASCADE,
)
ro_to_couple = models.ForeignKey(
@@ -386,6 +387,31 @@ class AttackPath(NameDescriptionMixin, FolderMixin):
on_delete=models.CASCADE,
help_text=_("RO/TO couple from which the attach path is derived"),
)
+ ref_id = models.CharField(max_length=100, blank=True)
+
+ class Meta:
+ verbose_name = _("Strategic Scenario")
+ verbose_name_plural = _("Strategic Scenarios")
+ ordering = ["created_at"]
+
+ def save(self, *args, **kwargs):
+ self.folder = self.ebios_rm_study.folder
+ super().save(*args, **kwargs)
+
+
+class AttackPath(NameDescriptionMixin, FolderMixin):
+ ebios_rm_study = models.ForeignKey(
+ EbiosRMStudy,
+ verbose_name=_("EBIOS RM study"),
+ on_delete=models.CASCADE,
+ )
+ strategic_scenario = models.ForeignKey(
+ StrategicScenario,
+ verbose_name=_("Strategic scenario"),
+ on_delete=models.CASCADE,
+ related_name="attack_paths",
+ help_text=_("Strategic scenario from which the attack path is derived"),
+ )
stakeholders = models.ManyToManyField(
Stakeholder,
verbose_name=_("Stakeholders"),
@@ -404,8 +430,13 @@ class Meta:
ordering = ["created_at"]
def save(self, *args, **kwargs):
+ self.ebios_rm_study = self.strategic_scenario.ebios_rm_study
self.folder = self.ebios_rm_study.folder
super().save(*args, **kwargs)
+
+ @property
+ def ro_to_couple(self):
+ return self.strategic_scenario.ro_to_couple
@property
def gravity(self):
diff --git a/backend/ebios_rm/serializers.py b/backend/ebios_rm/serializers.py
index 9e362dae2..9a56bd5d2 100644
--- a/backend/ebios_rm/serializers.py
+++ b/backend/ebios_rm/serializers.py
@@ -8,6 +8,7 @@
FearedEvent,
RoTo,
Stakeholder,
+ StrategicScenario,
AttackPath,
OperationalScenario,
)
@@ -128,10 +129,26 @@ class Meta:
fields = "__all__"
+class StrategicScenarioWriteSerializer(BaseModelSerializer):
+ class Meta:
+ model = StrategicScenario
+ exclude = ["created_at", "updated_at", "folder"]
+
+
+class StrategicScenarioReadSerializer(BaseModelSerializer):
+ ebios_rm_study = FieldsRelatedField()
+ folder = FieldsRelatedField()
+ ro_to_couple = FieldsRelatedField()
+
+ class Meta:
+ model = StrategicScenario
+ fields = "__all__"
+
+
class AttackPathWriteSerializer(BaseModelSerializer):
class Meta:
model = AttackPath
- exclude = ["created_at", "updated_at", "folder"]
+ exclude = ["created_at", "updated_at", "folder", "ebios_rm_study"]
class AttackPathReadSerializer(BaseModelSerializer):
diff --git a/backend/ebios_rm/urls.py b/backend/ebios_rm/urls.py
index 76f7b3e2e..4af4f7096 100644
--- a/backend/ebios_rm/urls.py
+++ b/backend/ebios_rm/urls.py
@@ -6,6 +6,7 @@
FearedEventViewSet,
RoToViewSet,
StakeholderViewSet,
+ StrategicScenarioViewSet,
AttackPathViewSet,
OperationalScenarioViewSet,
)
@@ -16,6 +17,7 @@
router.register(r"feared-events", FearedEventViewSet, basename="feared-events")
router.register(r"ro-to", RoToViewSet, basename="ro-to")
router.register(r"stakeholders", StakeholderViewSet, basename="stakeholders")
+router.register(r"strategic-scenarios", StrategicScenarioViewSet, basename="strategic-scenarios")
router.register(r"attack-paths", AttackPathViewSet, basename="attack-paths")
router.register(
r"operational-scenarios",
diff --git a/backend/ebios_rm/views.py b/backend/ebios_rm/views.py
index 5c9515d04..1c04b7f39 100644
--- a/backend/ebios_rm/views.py
+++ b/backend/ebios_rm/views.py
@@ -7,6 +7,7 @@
FearedEvent,
RoTo,
Stakeholder,
+ StrategicScenario,
AttackPath,
OperationalScenario,
)
@@ -124,6 +125,14 @@ def category(self, request):
return Response(dict(Stakeholder.Category.choices))
+class StrategicScenarioViewSet(BaseModelViewSet):
+ model = StrategicScenario
+
+ filterset_fields = [
+ "ebios_rm_study",
+ ]
+
+
class AttackPathFilter(df.FilterSet):
used = df.BooleanFilter(method="is_used", label="Used")
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index f1854fc09..49abb549f 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -1007,5 +1007,7 @@
"certain": "Certain",
"minor": "Minor",
"operatingModesDescription": "Operating modes description",
- "noStakeholders": "No stakeholders"
+ "noStakeholders": "No stakeholders",
+ "strategicScenario": "Strategic scenario",
+ "strategicScenarios": "Strategic scenarios"
}
diff --git a/frontend/src/lib/components/Forms/ModelForm.svelte b/frontend/src/lib/components/Forms/ModelForm.svelte
index 939955bce..97393bc4b 100644
--- a/frontend/src/lib/components/Forms/ModelForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm.svelte
@@ -47,6 +47,7 @@
import { createModalCache } from '$lib/utils/stores';
import FilteringLabelForm from './ModelForm/FilteringLabelForm.svelte';
import OperationalScenarioForm from './ModelForm/OperationalScenarioForm.svelte';
+ import StrategicScenarioForm from './ModelForm/StrategicScenarioForm.svelte';
export let form: SuperValidated;
export let invalidateAll = true; // set to false to keep form data using muliple forms on a page
@@ -270,6 +271,8 @@
{:else if URLModel === 'stakeholders'}
+ {:else if URLModel === 'strategic-scenarios'}
+
{:else if URLModel === 'attack-paths'}
{:else if URLModel === 'operational-scenarios'}
diff --git a/frontend/src/lib/components/Forms/ModelForm/AttackPathForm.svelte b/frontend/src/lib/components/Forms/ModelForm/AttackPathForm.svelte
index e6d7ab3a6..7619db182 100644
--- a/frontend/src/lib/components/Forms/ModelForm/AttackPathForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm/AttackPathForm.svelte
@@ -12,17 +12,18 @@
export let cacheLocks: Record = {};
export let formDataCache: Record = {};
export let initialData: Record = {};
- export let context: 'create' | 'edit' = 'create';
+ import AutocompleteSelect from '$lib/components/Forms/AutocompleteSelect.svelte';
+ import { getOptions } from '$lib/utils/crud';
+ import type { CacheLock, ModelInfo } from '$lib/utils/types';
+ import * as m from '$paraglide/messages.js';
+ import type { SuperValidated } from 'sveltekit-superforms';
+ import TextField from '../TextArea.svelte';
+
+ export let form: SuperValidated;
+ export let model: ModelInfo;
+ export let cacheLocks: Record = {};
+ export let formDataCache: Record = {};
+ export let initialData: Record = {};
+ export let context: string;
+
+
+{#if context !== 'edit'}
+
+{/if}
+
diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts
index 47f7d15c4..9c6356c25 100644
--- a/frontend/src/lib/utils/crud.ts
+++ b/frontend/src/lib/utils/crud.ts
@@ -669,6 +669,20 @@ export const URL_MODEL_MAP: ModelMap = {
],
selectFields: [{ field: 'category' }]
},
+ 'strategic-scenarios': {
+ endpointUrl: 'ebios-rm/strategic-scenarios',
+ name: 'strategicscenario',
+ localName: 'strategicScenario',
+ localNamePlural: 'strategicScenarios',
+ verboseName: 'Strategic scenario',
+ verboseNamePlural: 'Strategic scenarios',
+ foreignKeyFields: [
+ { field: 'ebios_rm_study', urlModel: 'ebios-rm', endpointUrl: 'ebios-rm/studies' },
+ { field: 'ro_to_couple', urlModel: 'ro-to', endpointUrl: 'ebios-rm/ro-to', urlParams: 'ebios_rm_study=', detail: true },
+ { field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' }
+ ],
+ reverseForeignKeyFields: [{ field: 'strategic_scenario', urlModel: 'attack-paths', endpointUrl: 'ebios-rm/attack-paths' }],
+ },
'attack-paths': {
endpointUrl: 'ebios-rm/attack-paths',
name: 'attackpath',
@@ -678,15 +692,9 @@ export const URL_MODEL_MAP: ModelMap = {
verboseNamePlural: 'Attack paths',
foreignKeyFields: [
{ field: 'stakeholders', urlModel: 'stakeholders', endpointUrl: 'ebios-rm/stakeholders' },
- {
- field: 'ro_to_couple',
- urlModel: 'ro-to',
- endpointUrl: 'ebios-rm/ro-to',
- urlParams: 'ebios_rm_study=',
- detail: true
- },
{ field: 'ebios_rm_study', urlModel: 'ebios-rm', endpointUrl: 'ebios-rm/studies' },
- { field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' }
+ { field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' },
+ { field: 'strategic_scenario', urlModel: 'strategic-scenarios', endpointUrl: 'ebios-rm/strategic-scenarios', urlParams: 'ebios_rm_study=', detail: true }
]
},
'operational-scenarios': {
diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts
index 73715c548..4180029b5 100644
--- a/frontend/src/lib/utils/schemas.ts
+++ b/frontend/src/lib/utils/schemas.ts
@@ -445,10 +445,16 @@ export const StakeholderSchema = z.object({
justification: z.string().optional()
});
+export const StrategicScenarioSchema = z.object({
+ ...NameDescriptionMixin,
+ ro_to_couple: z.string().uuid(),
+ ref_id: z.string().optional(),
+})
+
export const AttackPathSchema = z.object({
...NameDescriptionMixin,
ebios_rm_study: z.string(),
- ro_to_couple: z.string().uuid(),
+ strategic_scenario: z.string().uuid(),
stakeholders: z.string().uuid().optional().array().optional(),
is_selected: z.boolean().optional(),
justification: z.string().optional()
@@ -493,6 +499,7 @@ const SCHEMA_MAP: Record = {
'feared-events': fearedEventsSchema,
'ro-to': roToSchema,
stakeholders: StakeholderSchema,
+ 'strategic-scenarios': StrategicScenarioSchema,
'attack-paths': AttackPathSchema,
'operational-scenarios': operationalScenarioSchema
};
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index cf6e52bd1..6ea344ce9 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -596,9 +596,13 @@ export const listViewFields: ListViewFieldsConfig = {
head: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'],
body: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality']
},
+ 'strategic-scenarios': {
+ head: ['ref_id', 'name', 'description', 'ro_to_couple', 'attackPaths'],
+ body: ['ref_id', 'name', 'description', 'ro_to_couple', 'attack_paths']
+ },
'attack-paths': {
- head: ['is_selected', 'name', 'risk_origin', 'target_objective', 'stakeholders', 'attackPath'],
- body: ['is_selected', 'name', 'risk_origin', 'target_objective', 'stakeholders', 'description']
+ head: ['is_selected', 'name', 'stakeholders', 'description'],
+ body: ['is_selected', 'name', 'stakeholders', 'description']
},
'operational-scenarios': {
head: ['operatingModesDescription', 'threats', 'likelihood'],
diff --git a/frontend/src/lib/utils/types.ts b/frontend/src/lib/utils/types.ts
index c31e6a2fd..5bd08ff3c 100644
--- a/frontend/src/lib/utils/types.ts
+++ b/frontend/src/lib/utils/types.ts
@@ -55,6 +55,7 @@ export const URL_MODEL = [
'feared-events',
'ro-to',
'stakeholders',
+ 'strategic-scenarios',
'attack-paths',
'operational-scenarios'
// 'ebios-rm',
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-four/operational-scenario/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-four/operational-scenario/+page.server.ts
index dc296d006..adc1c8874 100644
--- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-four/operational-scenario/+page.server.ts
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-four/operational-scenario/+page.server.ts
@@ -70,6 +70,20 @@ export const load: PageServerLoad = async ({ params, fetch }) => {
}
}
+ const likelihoodChoicesEndpoint = `${BASE_API_URL}/ebios-rm/studies/${params.id}/likelihood/`;
+ const likelihoodChoicesResponse = await fetch(likelihoodChoicesEndpoint);
+
+ if (likelihoodChoicesResponse.ok) {
+ selectOptions['likelihood'] = await likelihoodChoicesResponse.json().then((data) =>
+ Object.entries(data).map(([key, value]) => ({
+ label: value,
+ value: parseInt(key)
+ }))
+ );
+ } else {
+ console.error(`Failed to fetch data for likelihood: ${likelihoodChoicesResponse.statusText}`);
+ }
+
model['selectOptions'] = selectOptions;
const bodyData = tableSourceMapper(data, listViewFields[URLModel as urlModel].body);
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-three/strategic-scenarios/+page.server.ts b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-three/strategic-scenarios/+page.server.ts
index 94c75806d..c1e15adde 100644
--- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-three/strategic-scenarios/+page.server.ts
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-three/strategic-scenarios/+page.server.ts
@@ -14,7 +14,7 @@ import { tableSourceMapper, type TableSource } from '@skeletonlabs/skeleton';
export const load: PageServerLoad = async ({ params, fetch }) => {
const schema = z.object({ id: z.string().uuid() });
const deleteForm = await superValidate(zod(schema));
- const URLModel = 'attack-paths';
+ const URLModel = 'strategic-scenarios';
const createSchema = modelSchema(URLModel);
const initialData = {
ebios_rm_study: params.id
@@ -95,12 +95,12 @@ export const actions: Actions = {
// const redirectToWrittenObject = Boolean(event.params.model === 'entity-assessments');
return defaultWriteFormAction({
event,
- urlModel: 'attack-paths',
+ urlModel: 'strategic-scenarios',
action: 'create'
// redirectToWrittenObject: redirectToWrittenObject
});
},
delete: async (event) => {
- return defaultDeleteFormAction({ event, urlModel: 'attack-paths' });
+ return defaultDeleteFormAction({ event, urlModel: 'strategic-scenarios' });
}
};
From e32776b79d710178261308371bb3bb875f334e0c Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 20:03:34 +0100
Subject: [PATCH 02/25] chore: format
---
...ro_to_couple_strategicscenario_and_more.py | 94 ++++++++++++++-----
backend/ebios_rm/models.py | 6 +-
backend/ebios_rm/urls.py | 4 +-
.../ModelForm/StrategicScenarioForm.svelte | 20 ++--
frontend/src/lib/utils/crud.ts | 24 ++++-
frontend/src/lib/utils/schemas.ts | 4 +-
6 files changed, 111 insertions(+), 41 deletions(-)
diff --git a/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py b/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
index 8184e449c..ad78b823d 100644
--- a/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
+++ b/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
@@ -7,41 +7,91 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('ebios_rm', '0006_alter_attackpath_stakeholders'),
- ('iam', '0010_user_preferences'),
+ ("ebios_rm", "0006_alter_attackpath_stakeholders"),
+ ("iam", "0010_user_preferences"),
]
operations = [
migrations.RemoveField(
- model_name='attackpath',
- name='ro_to_couple',
+ model_name="attackpath",
+ name="ro_to_couple",
),
migrations.CreateModel(
- name='StrategicScenario',
+ name="StrategicScenario",
fields=[
- ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
- ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
- ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')),
- ('is_published', models.BooleanField(default=False, verbose_name='published')),
- ('name', models.CharField(max_length=200, verbose_name='Name')),
- ('description', models.TextField(blank=True, null=True, verbose_name='Description')),
- ('ref_id', models.CharField(blank=True, max_length=100)),
- ('ebios_rm_study', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='strategic_scenarios', to='ebios_rm.ebiosrmstudy', verbose_name='EBIOS RM study')),
- ('folder', models.ForeignKey(default=iam.models.Folder.get_root_folder_id, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_folder', to='iam.folder')),
- ('ro_to_couple', models.ForeignKey(help_text='RO/TO couple from which the attach path is derived', on_delete=django.db.models.deletion.CASCADE, to='ebios_rm.roto', verbose_name='RO/TO couple')),
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ (
+ "created_at",
+ models.DateTimeField(auto_now_add=True, verbose_name="Created at"),
+ ),
+ (
+ "updated_at",
+ models.DateTimeField(auto_now=True, verbose_name="Updated at"),
+ ),
+ (
+ "is_published",
+ models.BooleanField(default=False, verbose_name="published"),
+ ),
+ ("name", models.CharField(max_length=200, verbose_name="Name")),
+ (
+ "description",
+ models.TextField(blank=True, null=True, verbose_name="Description"),
+ ),
+ ("ref_id", models.CharField(blank=True, max_length=100)),
+ (
+ "ebios_rm_study",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="strategic_scenarios",
+ to="ebios_rm.ebiosrmstudy",
+ verbose_name="EBIOS RM study",
+ ),
+ ),
+ (
+ "folder",
+ models.ForeignKey(
+ default=iam.models.Folder.get_root_folder_id,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="%(class)s_folder",
+ to="iam.folder",
+ ),
+ ),
+ (
+ "ro_to_couple",
+ models.ForeignKey(
+ help_text="RO/TO couple from which the attach path is derived",
+ on_delete=django.db.models.deletion.CASCADE,
+ to="ebios_rm.roto",
+ verbose_name="RO/TO couple",
+ ),
+ ),
],
options={
- 'verbose_name': 'Strategic Scenario',
- 'verbose_name_plural': 'Strategic Scenarios',
- 'ordering': ['created_at'],
+ "verbose_name": "Strategic Scenario",
+ "verbose_name_plural": "Strategic Scenarios",
+ "ordering": ["created_at"],
},
),
migrations.AddField(
- model_name='attackpath',
- name='strategic_scenario',
- field=models.ForeignKey(default='', help_text='Strategic scenario from which the attack path is derived', on_delete=django.db.models.deletion.CASCADE, related_name='attack_paths', to='ebios_rm.strategicscenario', verbose_name='Strategic scenario'),
+ model_name="attackpath",
+ name="strategic_scenario",
+ field=models.ForeignKey(
+ default="",
+ help_text="Strategic scenario from which the attack path is derived",
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="attack_paths",
+ to="ebios_rm.strategicscenario",
+ verbose_name="Strategic scenario",
+ ),
preserve_default=False,
),
]
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index 295cb7769..35361e0db 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -388,12 +388,12 @@ class StrategicScenario(NameDescriptionMixin, FolderMixin):
help_text=_("RO/TO couple from which the attach path is derived"),
)
ref_id = models.CharField(max_length=100, blank=True)
-
+
class Meta:
verbose_name = _("Strategic Scenario")
verbose_name_plural = _("Strategic Scenarios")
ordering = ["created_at"]
-
+
def save(self, *args, **kwargs):
self.folder = self.ebios_rm_study.folder
super().save(*args, **kwargs)
@@ -433,7 +433,7 @@ def save(self, *args, **kwargs):
self.ebios_rm_study = self.strategic_scenario.ebios_rm_study
self.folder = self.ebios_rm_study.folder
super().save(*args, **kwargs)
-
+
@property
def ro_to_couple(self):
return self.strategic_scenario.ro_to_couple
diff --git a/backend/ebios_rm/urls.py b/backend/ebios_rm/urls.py
index 4af4f7096..cf7bcaebf 100644
--- a/backend/ebios_rm/urls.py
+++ b/backend/ebios_rm/urls.py
@@ -17,7 +17,9 @@
router.register(r"feared-events", FearedEventViewSet, basename="feared-events")
router.register(r"ro-to", RoToViewSet, basename="ro-to")
router.register(r"stakeholders", StakeholderViewSet, basename="stakeholders")
-router.register(r"strategic-scenarios", StrategicScenarioViewSet, basename="strategic-scenarios")
+router.register(
+ r"strategic-scenarios", StrategicScenarioViewSet, basename="strategic-scenarios"
+)
router.register(r"attack-paths", AttackPathViewSet, basename="attack-paths")
router.register(
r"operational-scenarios",
diff --git a/frontend/src/lib/components/Forms/ModelForm/StrategicScenarioForm.svelte b/frontend/src/lib/components/Forms/ModelForm/StrategicScenarioForm.svelte
index 581e05148..16fc830f2 100644
--- a/frontend/src/lib/components/Forms/ModelForm/StrategicScenarioForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm/StrategicScenarioForm.svelte
@@ -11,19 +11,19 @@
export let cacheLocks: Record = {};
export let formDataCache: Record = {};
export let initialData: Record = {};
- export let context: string;
+ export let context: string;
{#if context !== 'edit'}
-
+
{/if}
Date: Tue, 17 Dec 2024 20:46:00 +0100
Subject: [PATCH 03/25] feat: add ebios objects scope and fields to check
---
backend/core/base_models.py | 20 ++++++++++++-------
backend/ebios_rm/models.py | 19 ++++++++++++++++++
frontend/src/lib/utils/schemas.ts | 2 +-
.../[id=uuid]/+page.svelte | 2 +-
4 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/backend/core/base_models.py b/backend/core/base_models.py
index 264567870..5e1240797 100644
--- a/backend/core/base_models.py
+++ b/backend/core/base_models.py
@@ -46,13 +46,19 @@ def is_unique_in_scope(self, scope: models.QuerySet, fields_to_check: list) -> b
# to avoid false positives as a result of the object being compared to itself
if self.pk:
scope = scope.exclude(pk=self.pk)
- return not scope.filter(
- **{
- f"{field}__iexact": getattr(self, field)
- for field in fields_to_check
- if hasattr(self, field)
- }
- ).exists()
+ filters = {}
+ for field in fields_to_check:
+ if hasattr(self, field):
+ field_value = getattr(self, field)
+ model_field = self._meta.get_field(field)
+
+ # Use the appropriate lookup based on the field type
+ if isinstance(model_field, models.ForeignKey):
+ filters[f"{field}__exact"] = field_value
+ else:
+ filters[f"{field}__iexact"] = field_value
+
+ return not scope.filter(**filters).exists()
def display_path(self):
pass
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index 35361e0db..af9277a9c 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -126,6 +126,8 @@ class FearedEvent(NameDescriptionMixin, FolderMixin):
gravity = models.SmallIntegerField(default=-1, verbose_name=_("Gravity"))
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
+
+ fields_to_check = ["name", "ref_id"]
class Meta:
verbose_name = _("Feared event")
@@ -223,6 +225,8 @@ class Pertinence(models.IntegerChoices):
)
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
+
+ fields_to_check = ["target_objective", "risk_origin"]
def __str__(self) -> str:
return f"{self.get_risk_origin_display()} - {self.target_objective}"
@@ -334,11 +338,16 @@ class Category(models.TextChoices):
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
+
+ fields_to_check = ["entity", "category"]
class Meta:
verbose_name = _("Stakeholder")
verbose_name_plural = _("Stakeholders")
ordering = ["created_at"]
+
+ def get_scope(self):
+ return self.__class__.objects.filter(ebios_rm_study=self.ebios_rm_study)
def __str__(self):
return f"{self.entity.name} - {self.get_category_display()}"
@@ -388,11 +397,16 @@ class StrategicScenario(NameDescriptionMixin, FolderMixin):
help_text=_("RO/TO couple from which the attach path is derived"),
)
ref_id = models.CharField(max_length=100, blank=True)
+
+ fields_to_check = ["name", "ref_id"]
class Meta:
verbose_name = _("Strategic Scenario")
verbose_name_plural = _("Strategic Scenarios")
ordering = ["created_at"]
+
+ def get_scope(self):
+ return self.__class__.objects.filter(ebios_rm_study=self.ebios_rm_study)
def save(self, *args, **kwargs):
self.folder = self.ebios_rm_study.folder
@@ -423,11 +437,16 @@ class AttackPath(NameDescriptionMixin, FolderMixin):
ref_id = models.CharField(max_length=100, blank=True)
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
+
+ fields_to_check = ["name", "ref_id"]
class Meta:
verbose_name = _("Attack path")
verbose_name_plural = _("Attack paths")
ordering = ["created_at"]
+
+ def get_scope(self):
+ return self.__class__.objects.filter(ebios_rm_study=self.ebios_rm_study)
def save(self, *args, **kwargs):
self.ebios_rm_study = self.strategic_scenario.ebios_rm_study
diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts
index 2d09b8766..ab3c76d21 100644
--- a/frontend/src/lib/utils/schemas.ts
+++ b/frontend/src/lib/utils/schemas.ts
@@ -447,13 +447,13 @@ export const StakeholderSchema = z.object({
export const StrategicScenarioSchema = z.object({
...NameDescriptionMixin,
+ ebios_rm_study: z.string(),
ro_to_couple: z.string().uuid(),
ref_id: z.string().optional()
});
export const AttackPathSchema = z.object({
...NameDescriptionMixin,
- ebios_rm_study: z.string(),
strategic_scenario: z.string().uuid(),
stakeholders: z.string().uuid().optional().array().optional(),
is_selected: z.boolean().optional(),
diff --git a/frontend/src/routes/(app)/(internal)/operational-scenarios/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(internal)/operational-scenarios/[id=uuid]/+page.svelte
index 0a14446a3..cbd6b572f 100644
--- a/frontend/src/routes/(app)/(internal)/operational-scenarios/[id=uuid]/+page.svelte
+++ b/frontend/src/routes/(app)/(internal)/operational-scenarios/[id=uuid]/+page.svelte
@@ -122,7 +122,7 @@
>
{:else}
- {m.noStakeholders()}
+ {m.noStakeholders()}
{/each}
Date: Tue, 17 Dec 2024 20:47:09 +0100
Subject: [PATCH 04/25] chore: format
---
backend/ebios_rm/models.py | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index af9277a9c..42dd525d1 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -126,7 +126,7 @@ class FearedEvent(NameDescriptionMixin, FolderMixin):
gravity = models.SmallIntegerField(default=-1, verbose_name=_("Gravity"))
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
-
+
fields_to_check = ["name", "ref_id"]
class Meta:
@@ -225,7 +225,7 @@ class Pertinence(models.IntegerChoices):
)
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
-
+
fields_to_check = ["target_objective", "risk_origin"]
def __str__(self) -> str:
@@ -338,14 +338,14 @@ class Category(models.TextChoices):
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
-
+
fields_to_check = ["entity", "category"]
class Meta:
verbose_name = _("Stakeholder")
verbose_name_plural = _("Stakeholders")
ordering = ["created_at"]
-
+
def get_scope(self):
return self.__class__.objects.filter(ebios_rm_study=self.ebios_rm_study)
@@ -397,14 +397,14 @@ class StrategicScenario(NameDescriptionMixin, FolderMixin):
help_text=_("RO/TO couple from which the attach path is derived"),
)
ref_id = models.CharField(max_length=100, blank=True)
-
+
fields_to_check = ["name", "ref_id"]
class Meta:
verbose_name = _("Strategic Scenario")
verbose_name_plural = _("Strategic Scenarios")
ordering = ["created_at"]
-
+
def get_scope(self):
return self.__class__.objects.filter(ebios_rm_study=self.ebios_rm_study)
@@ -437,14 +437,14 @@ class AttackPath(NameDescriptionMixin, FolderMixin):
ref_id = models.CharField(max_length=100, blank=True)
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)
-
+
fields_to_check = ["name", "ref_id"]
class Meta:
verbose_name = _("Attack path")
verbose_name_plural = _("Attack paths")
ordering = ["created_at"]
-
+
def get_scope(self):
return self.__class__.objects.filter(ebios_rm_study=self.ebios_rm_study)
From 005ad21271513c098fd4e008607c01ec036b2ef2 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 21:14:12 +0100
Subject: [PATCH 05/25] feat: add feared events filters
---
frontend/src/lib/utils/table.ts | 37 +++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index 6ea344ce9..052856648 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -156,6 +156,33 @@ const ASSET_FILTER: ListViewFilterConfig = {
alwaysDisplay: true
};
+const QUALIFICATION_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.qualifications?.length ? row.qualifications.map((t) => t.str) : null),
+ extraProps: {
+ defaultOptionName: 'qualification'
+ },
+ alwaysDisplay: true
+};
+
+const GRAVITY_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.gravity.name),
+ extraProps: {
+ defaultOptionName: 'gravity'
+ },
+ alwaysDisplay: true
+};
+
+const IS_SELECTED_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.is_selected ? 'true' : 'false'),
+ extraProps: {
+ defaultOptionName: 'is_selected'
+ },
+ alwaysDisplay: true
+};
+
const FRAMEWORK_FILTER: ListViewFilterConfig = {
component: SelectFilter,
getColumn: (row) => row.framework.ref_id,
@@ -571,8 +598,14 @@ export const listViewFields: ListViewFieldsConfig = {
body: ['name', 'description']
},
'feared-events': {
- head: ['selected', 'name', 'assets', 'fearedEvent', 'qualifications', 'gravity'],
- body: ['is_selected', 'name', 'assets', 'description', 'qualifications', 'gravity']
+ head: ['selected', 'name', 'assets', 'description', 'qualifications', 'gravity'],
+ body: ['is_selected', 'name', 'assets', 'description', 'qualifications', 'gravity'],
+ filters: {
+ assets: ASSET_FILTER,
+ qualifications: QUALIFICATION_FILTER,
+ gravity: GRAVITY_FILTER,
+ is_selected: IS_SELECTED_FILTER
+ }
},
'ro-to': {
head: [
From ad4819728058bc67253ab0b06ef6baa49fce81fb Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 21:21:54 +0100
Subject: [PATCH 06/25] feat: add ro-to filters
---
frontend/src/lib/utils/table.ts | 37 ++++++++++++++++++++++++++++++---
1 file changed, 34 insertions(+), 3 deletions(-)
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index 052856648..448899e5f 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -183,6 +183,33 @@ const IS_SELECTED_FILTER: ListViewFilterConfig = {
alwaysDisplay: true
};
+const RISK_ORIGIN_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.risk_origin),
+ extraProps: {
+ defaultOptionName: 'risk_origin'
+ },
+ alwaysDisplay: true
+};
+
+const FEARED_EVENT_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.feared_events?.length ? row.feared_events.map((t) => t.str) : null),
+ extraProps: {
+ defaultOptionName: 'feared_event'
+ },
+ alwaysDisplay: true
+};
+
+const PERTINENCE_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.pertinence),
+ extraProps: {
+ defaultOptionName: 'pertinence'
+ },
+ alwaysDisplay: true
+};
+
const FRAMEWORK_FILTER: ListViewFilterConfig = {
component: SelectFilter,
getColumn: (row) => row.framework.ref_id,
@@ -612,7 +639,6 @@ export const listViewFields: ListViewFieldsConfig = {
'isSelected',
'riskOrigin',
'targetObjective',
- 'motivation',
'fearedEvents',
'pertinence'
],
@@ -620,10 +646,15 @@ export const listViewFields: ListViewFieldsConfig = {
'is_selected',
'risk_origin',
'target_objective',
- 'motivation',
'feared_events',
'pertinence'
- ]
+ ],
+ filters: {
+ is_selected: IS_SELECTED_FILTER,
+ risk_origin: RISK_ORIGIN_FILTER,
+ feared_events: FEARED_EVENT_FILTER,
+ pertinence: PERTINENCE_FILTER
+ }
},
stakeholders: {
head: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'],
From 2fc4387e5261d88f02a1b4c76427c176edcab363 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 21:34:12 +0100
Subject: [PATCH 07/25] feat: add stakeholders filters
---
frontend/src/lib/utils/table.ts | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index 448899e5f..6f8aaa787 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -4,6 +4,7 @@ import SelectFilter from '$lib/components/Filters/SelectFilter.svelte';
import type { ComponentType } from 'svelte';
import { LOCALE_DISPLAY_MAP } from './constants';
import type { Row } from '@vincjo/datatables';
+import { category, entity } from '$paraglide/messages';
interface ListViewFilterConfig {
component: ComponentType;
@@ -210,6 +211,24 @@ const PERTINENCE_FILTER: ListViewFilterConfig = {
alwaysDisplay: true
};
+const ENTITY_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.entity.str),
+ extraProps: {
+ defaultOptionName: 'entity'
+ },
+ alwaysDisplay: true
+};
+
+const APPLIED_CONTROL_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.applied_controls?.length ? row.applied_controls.map((t) => t.str) : null),
+ extraProps: {
+ defaultOptionName: 'applied_control'
+ },
+ alwaysDisplay: true
+};
+
const FRAMEWORK_FILTER: ListViewFilterConfig = {
component: SelectFilter,
getColumn: (row) => row.framework.ref_id,
@@ -657,8 +676,14 @@ export const listViewFields: ListViewFieldsConfig = {
}
},
stakeholders: {
- head: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'],
- body: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality']
+ head: ['is_selected', 'entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'],
+ body: ['is_selected', 'entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'],
+ filters: {
+ is_selected: IS_SELECTED_FILTER,
+ entity: ENTITY_FILTER,
+ category: CATEGORY_FILTER,
+ applied_controls: APPLIED_CONTROL_FILTER
+ }
},
'strategic-scenarios': {
head: ['ref_id', 'name', 'description', 'ro_to_couple', 'attackPaths'],
From 58ad3c4125e48178245f0ebc2668bd8d463c48ac Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 21:49:32 +0100
Subject: [PATCH 08/25] feat: update stakeholders filters
---
frontend/src/lib/utils/table.ts | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index 6f8aaa787..9a85f70f4 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -220,11 +220,20 @@ const ENTITY_FILTER: ListViewFilterConfig = {
alwaysDisplay: true
};
-const APPLIED_CONTROL_FILTER: ListViewFilterConfig = {
+const CURRENT_CRITICALITY_FILTER: ListViewFilterConfig = {
component: SelectFilter,
- getColumn: (row) => (row.applied_controls?.length ? row.applied_controls.map((t) => t.str) : null),
+ getColumn: (row) => (console.log(row), row.current_criticality.toString()),
extraProps: {
- defaultOptionName: 'applied_control'
+ defaultOptionName: 'current_criticality'
+ },
+ alwaysDisplay: true
+};
+
+const RESIDUAL_CRITICALITY_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (console.log(row), row.residual_criticality.toString()),
+ extraProps: {
+ defaultOptionName: 'residual_criticality'
},
alwaysDisplay: true
};
@@ -682,7 +691,8 @@ export const listViewFields: ListViewFieldsConfig = {
is_selected: IS_SELECTED_FILTER,
entity: ENTITY_FILTER,
category: CATEGORY_FILTER,
- applied_controls: APPLIED_CONTROL_FILTER
+ current_criticality: CURRENT_CRITICALITY_FILTER,
+ residual_criticality: RESIDUAL_CRITICALITY_FILTER
}
},
'strategic-scenarios': {
From 417041f321aed4fe9274bc47ad42a5525319b593 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 21:53:47 +0100
Subject: [PATCH 09/25] feat: add operational scenario filters
---
.../ModelForm/OperationalScenarioForm.svelte | 2 +-
frontend/src/lib/utils/table.ts | 18 ++++++++++++++++--
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/frontend/src/lib/components/Forms/ModelForm/OperationalScenarioForm.svelte b/frontend/src/lib/components/Forms/ModelForm/OperationalScenarioForm.svelte
index 449a679c8..242428160 100644
--- a/frontend/src/lib/components/Forms/ModelForm/OperationalScenarioForm.svelte
+++ b/frontend/src/lib/components/Forms/ModelForm/OperationalScenarioForm.svelte
@@ -103,7 +103,6 @@
cacheLock={cacheLocks['likelihood']}
bind:cachedValue={formDataCache['likelihood']}
/>
-
+
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index 9a85f70f4..dbfa0e24a 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -175,6 +175,15 @@ const GRAVITY_FILTER: ListViewFilterConfig = {
alwaysDisplay: true
};
+const LIKELIHOOD_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.likelihood.name),
+ extraProps: {
+ defaultOptionName: 'likelihood'
+ },
+ alwaysDisplay: true
+};
+
const IS_SELECTED_FILTER: ListViewFilterConfig = {
component: SelectFilter,
getColumn: (row) => (row.is_selected ? 'true' : 'false'),
@@ -704,7 +713,12 @@ export const listViewFields: ListViewFieldsConfig = {
body: ['is_selected', 'name', 'stakeholders', 'description']
},
'operational-scenarios': {
- head: ['operatingModesDescription', 'threats', 'likelihood'],
- body: ['operating_modes_description', 'threats', 'likelihood']
+ head: ['is_selected', 'operatingModesDescription', 'threats', 'likelihood'],
+ body: ['is_selected', 'operating_modes_description', 'threats', 'likelihood'],
+ filters: {
+ threats: THREAT_FILTER,
+ likelihood: LIKELIHOOD_FILTER,
+ is_selected: IS_SELECTED_FILTER
+ }
}
};
From 22696eca39be060a25094fb48886e78faf923ce7 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 21:59:38 +0100
Subject: [PATCH 10/25] feat: add strategic scenario filters
---
backend/ebios_rm/models.py | 15 +++++++++++++++
backend/ebios_rm/serializers.py | 1 +
frontend/src/lib/utils/table.ts | 8 +++++---
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index 42dd525d1..6439ebdff 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -411,6 +411,21 @@ def get_scope(self):
def save(self, *args, **kwargs):
self.folder = self.ebios_rm_study.folder
super().save(*args, **kwargs)
+
+ def get_gravity_display(self):
+ if self.ro_to_couple.get_gravity() < 0:
+ return {
+ "abbreviation": "--",
+ "name": "--",
+ "description": "not rated",
+ "value": -1,
+ "hexcolor": "#f9fafb",
+ }
+ risk_matrix = self.parsed_matrix
+ return {
+ **risk_matrix["impact"][self.ro_to_couple.get_gravity()],
+ "value": self.ro_to_couple.get_gravity(),
+ }
class AttackPath(NameDescriptionMixin, FolderMixin):
diff --git a/backend/ebios_rm/serializers.py b/backend/ebios_rm/serializers.py
index 9a56bd5d2..e5f0b8f7d 100644
--- a/backend/ebios_rm/serializers.py
+++ b/backend/ebios_rm/serializers.py
@@ -139,6 +139,7 @@ class StrategicScenarioReadSerializer(BaseModelSerializer):
ebios_rm_study = FieldsRelatedField()
folder = FieldsRelatedField()
ro_to_couple = FieldsRelatedField()
+ gravity = serializers.JSONField(source="get_gravity_display")
class Meta:
model = StrategicScenario
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index dbfa0e24a..3a7e93bc9 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -4,7 +4,6 @@ import SelectFilter from '$lib/components/Filters/SelectFilter.svelte';
import type { ComponentType } from 'svelte';
import { LOCALE_DISPLAY_MAP } from './constants';
import type { Row } from '@vincjo/datatables';
-import { category, entity } from '$paraglide/messages';
interface ListViewFilterConfig {
component: ComponentType;
@@ -705,8 +704,11 @@ export const listViewFields: ListViewFieldsConfig = {
}
},
'strategic-scenarios': {
- head: ['ref_id', 'name', 'description', 'ro_to_couple', 'attackPaths'],
- body: ['ref_id', 'name', 'description', 'ro_to_couple', 'attack_paths']
+ head: ['ref_id', 'name', 'description', 'ro_to_couple', 'attackPaths', 'gravity'],
+ body: ['ref_id', 'name', 'description', 'ro_to_couple', 'attack_paths', 'gravity'],
+ filters: {
+ gravity: GRAVITY_FILTER
+ }
},
'attack-paths': {
head: ['is_selected', 'name', 'stakeholders', 'description'],
From 12af744d02503ece151b22215630b5b920964c8f Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 22:01:36 +0100
Subject: [PATCH 11/25] feat: add attack paths filters
---
frontend/src/lib/utils/table.ts | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index 3a7e93bc9..2d68476d3 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -246,6 +246,15 @@ const RESIDUAL_CRITICALITY_FILTER: ListViewFilterConfig = {
alwaysDisplay: true
};
+const STAKEHOLDER_FILTER: ListViewFilterConfig = {
+ component: SelectFilter,
+ getColumn: (row) => (row.stakeholders?.length ? row.stakeholders.map((t) => t.str) : null),
+ extraProps: {
+ defaultOptionName: 'stakeholder'
+ },
+ alwaysDisplay: true
+};
+
const FRAMEWORK_FILTER: ListViewFilterConfig = {
component: SelectFilter,
getColumn: (row) => row.framework.ref_id,
@@ -712,7 +721,11 @@ export const listViewFields: ListViewFieldsConfig = {
},
'attack-paths': {
head: ['is_selected', 'name', 'stakeholders', 'description'],
- body: ['is_selected', 'name', 'stakeholders', 'description']
+ body: ['is_selected', 'name', 'stakeholders', 'description'],
+ filters: {
+ is_selected: IS_SELECTED_FILTER,
+ stakeholders: STAKEHOLDER_FILTER
+ }
},
'operational-scenarios': {
head: ['is_selected', 'operatingModesDescription', 'threats', 'likelihood'],
From a0101eccda354fa92111c2fac4161ed87716aae4 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 22:11:41 +0100
Subject: [PATCH 12/25] feat: filters ro-to to create strategic scenario
---
backend/ebios_rm/views.py | 17 ++++++++++++++---
frontend/src/lib/utils/crud.ts | 2 +-
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/backend/ebios_rm/views.py b/backend/ebios_rm/views.py
index 1c04b7f39..b07780178 100644
--- a/backend/ebios_rm/views.py
+++ b/backend/ebios_rm/views.py
@@ -93,12 +93,23 @@ def gravity(self, request, pk):
return Response(choices)
+class RoToFilter(df.FilterSet):
+ used = df.BooleanFilter(method="is_used", label="Used")
+
+ def is_used(self, queryset, name, value):
+ if value:
+ return queryset.filter(strategicscenario__isnull=False)
+ return queryset.filter(strategicscenario__isnull=True)
+
+ class Meta:
+ model = RoTo
+ fields = ["ebios_rm_study", "is_selected", "used"]
+
+
class RoToViewSet(BaseModelViewSet):
model = RoTo
- filterset_fields = [
- "ebios_rm_study",
- ]
+ filterset_class = RoToFilter
@action(detail=False, name="Get risk origin choices", url_path="risk-origin")
def risk_origin(self, request):
diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts
index ca8476e8b..e00c26e80 100644
--- a/frontend/src/lib/utils/crud.ts
+++ b/frontend/src/lib/utils/crud.ts
@@ -682,7 +682,7 @@ export const URL_MODEL_MAP: ModelMap = {
field: 'ro_to_couple',
urlModel: 'ro-to',
endpointUrl: 'ebios-rm/ro-to',
- urlParams: 'ebios_rm_study=',
+ urlParams: 'is_selected=true&used=false&ebios_rm_study=',
detail: true
},
{ field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' }
From 283ac369d8f20eb0e741a48c80efe116a3324c72 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 22:12:33 +0100
Subject: [PATCH 13/25] chore: format
---
backend/ebios_rm/models.py | 2 +-
frontend/src/lib/utils/table.ts | 44 +++++++++++++++++----------------
2 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index 6439ebdff..1b4bac295 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -411,7 +411,7 @@ def get_scope(self):
def save(self, *args, **kwargs):
self.folder = self.ebios_rm_study.folder
super().save(*args, **kwargs)
-
+
def get_gravity_display(self):
if self.ro_to_couple.get_gravity() < 0:
return {
diff --git a/frontend/src/lib/utils/table.ts b/frontend/src/lib/utils/table.ts
index 2d68476d3..6bdf9529e 100644
--- a/frontend/src/lib/utils/table.ts
+++ b/frontend/src/lib/utils/table.ts
@@ -167,7 +167,7 @@ const QUALIFICATION_FILTER: ListViewFilterConfig = {
const GRAVITY_FILTER: ListViewFilterConfig = {
component: SelectFilter,
- getColumn: (row) => (row.gravity.name),
+ getColumn: (row) => row.gravity.name,
extraProps: {
defaultOptionName: 'gravity'
},
@@ -176,7 +176,7 @@ const GRAVITY_FILTER: ListViewFilterConfig = {
const LIKELIHOOD_FILTER: ListViewFilterConfig = {
component: SelectFilter,
- getColumn: (row) => (row.likelihood.name),
+ getColumn: (row) => row.likelihood.name,
extraProps: {
defaultOptionName: 'likelihood'
},
@@ -194,7 +194,7 @@ const IS_SELECTED_FILTER: ListViewFilterConfig = {
const RISK_ORIGIN_FILTER: ListViewFilterConfig = {
component: SelectFilter,
- getColumn: (row) => (row.risk_origin),
+ getColumn: (row) => row.risk_origin,
extraProps: {
defaultOptionName: 'risk_origin'
},
@@ -212,7 +212,7 @@ const FEARED_EVENT_FILTER: ListViewFilterConfig = {
const PERTINENCE_FILTER: ListViewFilterConfig = {
component: SelectFilter,
- getColumn: (row) => (row.pertinence),
+ getColumn: (row) => row.pertinence,
extraProps: {
defaultOptionName: 'pertinence'
},
@@ -221,7 +221,7 @@ const PERTINENCE_FILTER: ListViewFilterConfig = {
const ENTITY_FILTER: ListViewFilterConfig = {
component: SelectFilter,
- getColumn: (row) => (row.entity.str),
+ getColumn: (row) => row.entity.str,
extraProps: {
defaultOptionName: 'entity'
},
@@ -680,20 +680,8 @@ export const listViewFields: ListViewFieldsConfig = {
}
},
'ro-to': {
- head: [
- 'isSelected',
- 'riskOrigin',
- 'targetObjective',
- 'fearedEvents',
- 'pertinence'
- ],
- body: [
- 'is_selected',
- 'risk_origin',
- 'target_objective',
- 'feared_events',
- 'pertinence'
- ],
+ head: ['isSelected', 'riskOrigin', 'targetObjective', 'fearedEvents', 'pertinence'],
+ body: ['is_selected', 'risk_origin', 'target_objective', 'feared_events', 'pertinence'],
filters: {
is_selected: IS_SELECTED_FILTER,
risk_origin: RISK_ORIGIN_FILTER,
@@ -702,8 +690,22 @@ export const listViewFields: ListViewFieldsConfig = {
}
},
stakeholders: {
- head: ['is_selected', 'entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'],
- body: ['is_selected', 'entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'],
+ head: [
+ 'is_selected',
+ 'entity',
+ 'category',
+ 'current_criticality',
+ 'applied_controls',
+ 'residual_criticality'
+ ],
+ body: [
+ 'is_selected',
+ 'entity',
+ 'category',
+ 'current_criticality',
+ 'applied_controls',
+ 'residual_criticality'
+ ],
filters: {
is_selected: IS_SELECTED_FILTER,
entity: ENTITY_FILTER,
From f293126a2ecd39921aedc9f56b1828ccf8802095 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 22:32:07 +0100
Subject: [PATCH 14/25] fix: get matrix in strategic scenario
---
backend/ebios_rm/models.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index 1b4bac295..01fbbba94 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -421,7 +421,7 @@ def get_gravity_display(self):
"value": -1,
"hexcolor": "#f9fafb",
}
- risk_matrix = self.parsed_matrix
+ risk_matrix = self.ebios_rm_study.parsed_matrix
return {
**risk_matrix["impact"][self.ro_to_couple.get_gravity()],
"value": self.ro_to_couple.get_gravity(),
From 0af0c91f280ecfb65cc0f26921d6cd0ba796dffc Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Tue, 17 Dec 2024 23:19:03 +0100
Subject: [PATCH 15/25] style: improve ro-to layout
---
frontend/messages/en.json | 3 ++-
.../(internal)/ro-to/[id=uuid]/+page.svelte | 23 +++++++++++++------
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index 49abb549f..1ca227f2b 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -1009,5 +1009,6 @@
"operatingModesDescription": "Operating modes description",
"noStakeholders": "No stakeholders",
"strategicScenario": "Strategic scenario",
- "strategicScenarios": "Strategic scenarios"
+ "strategicScenarios": "Strategic scenarios",
+ "goBackToEbiosRmStudy": "Go back to Ebios RM study"
}
diff --git a/frontend/src/routes/(app)/(internal)/ro-to/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(internal)/ro-to/[id=uuid]/+page.svelte
index b62a50b71..5c4b2d4c2 100644
--- a/frontend/src/routes/(app)/(internal)/ro-to/[id=uuid]/+page.svelte
+++ b/frontend/src/routes/(app)/(internal)/ro-to/[id=uuid]/+page.svelte
@@ -34,6 +34,22 @@
Date: Wed, 18 Dec 2024 00:06:23 +0100
Subject: [PATCH 16/25] fix: some fixes
---
backend/ebios_rm/serializers.py | 8 ++------
backend/ebios_rm/views.py | 1 +
frontend/messages/en.json | 3 ++-
frontend/src/lib/components/DetailView/DetailView.svelte | 2 +-
frontend/src/lib/utils/crud.ts | 2 +-
frontend/src/lib/utils/load.ts | 5 ++++-
frontend/src/lib/utils/schemas.ts | 2 ++
7 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/backend/ebios_rm/serializers.py b/backend/ebios_rm/serializers.py
index e9b9efa34..9c763a87c 100644
--- a/backend/ebios_rm/serializers.py
+++ b/backend/ebios_rm/serializers.py
@@ -105,12 +105,8 @@ class Meta:
class StakeholderWriteSerializer(BaseModelSerializer):
- current_criticality = serializers.CharField(
- source="get_current_criticality_display"
- )
- residual_criticality = serializers.CharField(
- source="get_residual_criticality_display"
- )
+ current_criticality = serializers.IntegerField(read_only=True)
+ residual_criticality = serializers.IntegerField(read_only=True)
class Meta:
model = Stakeholder
diff --git a/backend/ebios_rm/views.py b/backend/ebios_rm/views.py
index b07780178..8a5dbab29 100644
--- a/backend/ebios_rm/views.py
+++ b/backend/ebios_rm/views.py
@@ -129,6 +129,7 @@ class StakeholderViewSet(BaseModelViewSet):
filterset_fields = [
"ebios_rm_study",
+ "is_selected",
]
@action(detail=False, name="Get category choices")
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index 1ca227f2b..56275e7d1 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -1010,5 +1010,6 @@
"noStakeholders": "No stakeholders",
"strategicScenario": "Strategic scenario",
"strategicScenarios": "Strategic scenarios",
- "goBackToEbiosRmStudy": "Go back to Ebios RM study"
+ "goBackToEbiosRmStudy": "Go back to Ebios RM study",
+ "addStrategicScenario": "Add strategic scenario"
}
diff --git a/frontend/src/lib/components/DetailView/DetailView.svelte b/frontend/src/lib/components/DetailView/DetailView.svelte
index acaf95bfa..71ffaaa15 100644
--- a/frontend/src/lib/components/DetailView/DetailView.svelte
+++ b/frontend/src/lib/components/DetailView/DetailView.svelte
@@ -310,7 +310,7 @@
{:else}
--
{/if}
- {:else if value.id}
+ {:else if value.id && !value.hexcolor}
{@const itemHref = `/${
URL_MODEL_MAP[data.urlModel]['foreignKeyFields']?.find(
(item) => item.field === key
diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts
index e00c26e80..de94c15ed 100644
--- a/frontend/src/lib/utils/crud.ts
+++ b/frontend/src/lib/utils/crud.ts
@@ -703,7 +703,7 @@ export const URL_MODEL_MAP: ModelMap = {
verboseName: 'Attack path',
verboseNamePlural: 'Attack paths',
foreignKeyFields: [
- { field: 'stakeholders', urlModel: 'stakeholders', endpointUrl: 'ebios-rm/stakeholders' },
+ { field: 'stakeholders', urlModel: 'stakeholders', endpointUrl: 'ebios-rm/stakeholders', urlParams: 'is_selected=true&ebios_rm_study=', detail: true },
{ field: 'ebios_rm_study', urlModel: 'ebios-rm', endpointUrl: 'ebios-rm/studies' },
{ field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' },
{
diff --git a/frontend/src/lib/utils/load.ts b/frontend/src/lib/utils/load.ts
index 893b34068..46033199a 100644
--- a/frontend/src/lib/utils/load.ts
+++ b/frontend/src/lib/utils/load.ts
@@ -87,7 +87,10 @@ export const loadDetail = async ({ event, model, id }) => {
if (info.foreignKeyFields) {
for (const keyField of info.foreignKeyFields) {
- const queryParams = keyField.urlParams ? `?${keyField.urlParams}` : '';
+ let queryParams = keyField.urlParams ? `?${keyField.urlParams}` : '';
+ if (keyField.detail===true){
+ queryParams += `${data.ebios_rm_study.id}`; // used only for ebios for now
+ }
const url = `${BASE_API_URL}/${keyField.endpointUrl || keyField.urlModel}/${queryParams}`;
const response = await event.fetch(url);
if (response.ok) {
diff --git a/frontend/src/lib/utils/schemas.ts b/frontend/src/lib/utils/schemas.ts
index ab3c76d21..68d70150a 100644
--- a/frontend/src/lib/utils/schemas.ts
+++ b/frontend/src/lib/utils/schemas.ts
@@ -437,10 +437,12 @@ export const StakeholderSchema = z.object({
current_penetration: z.number().min(0).max(4).default(0).optional(),
current_maturity: z.number().min(1).max(4).default(1).optional(),
current_trust: z.number().min(1).max(4).default(1).optional(),
+ current_criticality: z.number().min(0).max(4).default(0).optional(),
residual_dependency: z.number().min(0).max(4).default(0).optional(),
residual_penetration: z.number().min(0).max(4).default(0).optional(),
residual_maturity: z.number().min(1).max(4).default(1).optional(),
residual_trust: z.number().min(1).max(4).default(1).optional(),
+ residual_criticality: z.number().min(0).max(4).default(0).optional(),
is_selected: z.boolean().optional(),
justification: z.string().optional()
});
From 5d0491b0c93e58f84f5b0a4d904a2d89410ed35c Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Wed, 18 Dec 2024 00:07:11 +0100
Subject: [PATCH 17/25] feat: list attack paths
---
backend/ebios_rm/serializers.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/backend/ebios_rm/serializers.py b/backend/ebios_rm/serializers.py
index 9c763a87c..b23c78876 100644
--- a/backend/ebios_rm/serializers.py
+++ b/backend/ebios_rm/serializers.py
@@ -144,6 +144,7 @@ class StrategicScenarioReadSerializer(BaseModelSerializer):
folder = FieldsRelatedField()
ro_to_couple = FieldsRelatedField()
gravity = serializers.JSONField(source="get_gravity_display")
+ attack_paths = FieldsRelatedField(many=True)
class Meta:
model = StrategicScenario
From bac23fee7b4d8aae493ed33a202feb0ec44b7aee Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Wed, 18 Dec 2024 00:08:31 +0100
Subject: [PATCH 18/25] chore: format
---
frontend/src/lib/utils/crud.ts | 8 +++++++-
frontend/src/lib/utils/load.ts | 2 +-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/frontend/src/lib/utils/crud.ts b/frontend/src/lib/utils/crud.ts
index de94c15ed..fe85530bb 100644
--- a/frontend/src/lib/utils/crud.ts
+++ b/frontend/src/lib/utils/crud.ts
@@ -703,7 +703,13 @@ export const URL_MODEL_MAP: ModelMap = {
verboseName: 'Attack path',
verboseNamePlural: 'Attack paths',
foreignKeyFields: [
- { field: 'stakeholders', urlModel: 'stakeholders', endpointUrl: 'ebios-rm/stakeholders', urlParams: 'is_selected=true&ebios_rm_study=', detail: true },
+ {
+ field: 'stakeholders',
+ urlModel: 'stakeholders',
+ endpointUrl: 'ebios-rm/stakeholders',
+ urlParams: 'is_selected=true&ebios_rm_study=',
+ detail: true
+ },
{ field: 'ebios_rm_study', urlModel: 'ebios-rm', endpointUrl: 'ebios-rm/studies' },
{ field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' },
{
diff --git a/frontend/src/lib/utils/load.ts b/frontend/src/lib/utils/load.ts
index 46033199a..ad3bc6f37 100644
--- a/frontend/src/lib/utils/load.ts
+++ b/frontend/src/lib/utils/load.ts
@@ -88,7 +88,7 @@ export const loadDetail = async ({ event, model, id }) => {
if (info.foreignKeyFields) {
for (const keyField of info.foreignKeyFields) {
let queryParams = keyField.urlParams ? `?${keyField.urlParams}` : '';
- if (keyField.detail===true){
+ if (keyField.detail === true) {
queryParams += `${data.ebios_rm_study.id}`; // used only for ebios for now
}
const url = `${BASE_API_URL}/${keyField.endpointUrl || keyField.urlModel}/${queryParams}`;
From 6680fbe7390eb817e1fcf6ce91ad5f9729caf015 Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Wed, 18 Dec 2024 09:06:30 +0100
Subject: [PATCH 19/25] fix: put ebios_rm app before core in enterprise
---
enterprise/backend/enterprise_core/settings.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/enterprise/backend/enterprise_core/settings.py b/enterprise/backend/enterprise_core/settings.py
index 88d783fe1..6e6ab658d 100644
--- a/enterprise/backend/enterprise_core/settings.py
+++ b/enterprise/backend/enterprise_core/settings.py
@@ -142,8 +142,8 @@ def set_ciso_assistant_url(_, __, event_dict):
"iam",
"global_settings",
"tprm",
- "core",
"ebios_rm",
+ "core",
"cal",
"django_filters",
"library",
From 140251b501578f39e2ad4764955aa381016b6373 Mon Sep 17 00:00:00 2001
From: ab-smith
Date: Thu, 19 Dec 2024 13:33:57 +0100
Subject: [PATCH 20/25] =?UTF-8?q?chore:=20update=20translations=20with=20F?=
=?UTF-8?q?ink=20=F0=9F=90=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/messages/en.json | 2 +-
frontend/messages/fr.json | 116 ++++++++++++++++++++++++++++++++++----
2 files changed, 106 insertions(+), 12 deletions(-)
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index 56275e7d1..6d182b013 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -940,7 +940,7 @@
"existingContextHelper": "Description of the existing mitigations (this field will be deprecated soon)",
"fearedEvent": "Feared event",
"fearedEvents": "Feared events",
- "isSelected": "Is selected",
+ "isSelected": "Selected",
"ebiosRM": "Ebios RM",
"riskOrigin": "Risk origin",
"targetObjective": "Target objective",
diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json
index 6311995ff..6b65dd88a 100644
--- a/frontend/messages/fr.json
+++ b/frontend/messages/fr.json
@@ -797,6 +797,14 @@
"proof": "Preuve",
"privacy": "Vie privée",
"safety": "Sûreté",
+ "rto": "RTO",
+ "rtoHelpText": "Objectif de temps de récupération",
+ "rpo": "RPO",
+ "rpoHelpText": "Objectif du point de récupération",
+ "mtd": "MTD",
+ "mtdHelpText": "Temps d'arrêt maximal tolérable",
+ "securityObjectives": "Objectifs de sécurité",
+ "disasterRecoveryObjectives": "Objectifs de reprise après sinistre",
"noExpirationDateSet": "Aucune date d'expiration définie",
"sumpageTotal": "Total",
"sumpageActive": "Actif",
@@ -858,6 +866,11 @@
"exploitable": "Exploitable",
"mitigated": "Atténuée",
"fixed": "Fixée",
+ "general": "Général",
+ "generalSettingsDescription": "Configurez vos paramètres ici.",
+ "securityObjectiveScale": "Échelle des objectifs de sécurité",
+ "generalSettingsUpdated": "Paramètres mis à jour",
+ "securityObjectiveScaleHelpText": "Choisissez votre échelle d'objectifs de sécurité (1 à 4 par défaut)",
"labels": "Étiquettes",
"addLabel": "Ajouter une étiquette",
"labelsHelpText": "Les étiquettes sont utilisées pour catégoriser et filtrer les éléments.",
@@ -871,12 +884,23 @@
"tags": "Étiquettes",
"addTag": "Ajouter une étiquette",
"tagsHelpText": "Les étiquettes sont utilisées pour classer et filtrer les éléments. Vous pouvez ajouter des étiquettes dans la section Extra",
+ "enabled": "Activé",
+ "hours": "Heures",
+ "minutes": "Minutes",
+ "seconds": "Secondes",
+ "days": "Jours",
+ "milliseconds": "Millisecondes",
"existingMeasures": "Mesures existantes",
+ "youCanSetPasswordHere": "Vous pouvez définir votre mot de passe ici",
"forgotPassword": "Mot de passe oublié",
"ssoSettingsUpdated": "Paramètres SSO mis à jour",
"scoreSemiColon": "Score:",
"mappingInferenceHelpText": "Ces variables sont fixes et ne changeront pas en fonction de la source.",
"priority": "Priorité",
+ "p1": "P1",
+ "p2": "P2",
+ "p3": "P3",
+ "p4": "P4",
"ebiosWs1": "Atelier 1 : Cadrage et Socle de sécurité",
"ebiosWs2": "Atelier 2 : Sources de risque",
"ebiosWs3": "Atelier 3 : Scénarios stratégiques",
@@ -900,22 +924,92 @@
"ebiosWs5_4": "Évaluer et documenter les risques résiduels",
"ebiosWs5_5": "Mettre en place le cadre de suivi des risques",
"activity": "Activité",
+ "ebiosRmMatrixHelpText": "Matrice de risque utilisée pour l'étude. La valeur par défaut est `urn:intuitem:risk:library:risk-matrix-4x4-ebios-rm`",
+ "activityOne": "Activité 1",
+ "activityTwo": "Activité 2",
+ "activityThree": "Activité 3",
+ "ebiosRmStudy": "Étude Ebios RM",
+ "qualifications": "Qualifications",
+ "impacts": "Impacts",
+ "ebiosRmStudies": "Études Ebios RM",
"bringTheEvidences": "Apportez les preuves",
"bringTheEvidencesHelpText": "Si désactivé, l'objet sera dupliqué sans ses preuves",
+ "gravity": "Gravité",
"existingControlsHelper": "Que disposez-vous actuellement pour gérer ce risque",
"extraControlsHelper": "Que ferez-vous pour atténuer ce risque",
"existingContextHelper": "Description des mesures existantes (ce champ sera bientôt obsolète)",
+ "fearedEvent": "Événement redouté",
+ "fearedEvents": "Evénements redoutés",
+ "isSelected": "Retenu",
+ "ebiosRM": "Ebios RM",
+ "riskOrigin": "Source de risque",
+ "targetObjective": "Objectif visé",
+ "motivation": "Motivation",
+ "resources": "Ressources",
+ "pertinence": "Pertinence",
+ "limited": "Limité",
+ "significant": "Significatif",
+ "important": "Important",
+ "unlimited": "Illimité",
+ "strong": "Fort",
+ "irrelevant": "Non pertinent",
+ "partiallyRelevant": "Partiellement pertinent",
+ "fairlyRelevant": "Assez pertinent",
+ "highlyRelevant": "Très pertinent",
+ "roTo": "SR/OV",
+ "roToCouple": "Couple SR/OV",
+ "addRoto": "Ajouter un couple SR/OV",
+ "organizedCrime": "Crime organisé",
+ "terrorist": "Terroriste",
+ "activist": "Activiste",
+ "professional": "Concurrent",
+ "amateur": "Amateur",
+ "avenger": "Vengeur",
+ "pathological": "Pathologique",
+ "currentDependency": "Dépendance actuelle",
+ "currentPenetration": "Pénétration actuelle",
+ "currentMaturity": "Maturité actuelle",
+ "currentTrust": "Confiance actuelle",
+ "residualDependency": "Dépendance résiduelle",
+ "residualPenetration": "Pénétration résiduelle",
+ "residualMaturity": "Maturité résiduelle",
+ "residualTrust": "Confiance résiduelle",
+ "selected": "Retenu",
+ "likelihood": "Vraisemblance",
+ "stakeholders": "Parties prenantes",
+ "addAttackPath": "Ajouter un chemin d'attaque",
+ "attackPath": "Chemin d'attaque",
+ "attackPaths": "Chemins d'attaque",
+ "currentCriticality": "Criticité actuelle",
+ "residualCriticality": "Criticité résiduelle",
+ "notSelected": "Non retenu",
"resetPasswordHere": "Vous pouvez réinitialiser votre mot de passe ici.",
"resetPassword": "Réinitialiser le mot de passe",
- "securityObjectives": "Objectifs de sécurité",
- "disasterRecoveryObjectives": "Objectifs de reprise après sinistre",
- "hours": "Heures",
- "minutes": "Minutes",
- "seconds": "Secondes",
- "rto": "RTO",
- "rtoHelpText": "Objectif de temps de récupération",
- "rpo": "RPO",
- "rpoHelpText": "Objectif du point de récupération",
- "mtd": "MTD",
- "mtdHelpText": "Temps d'arrêt maximal tolérable"
+ "ebiosRm": "Ebios RM",
+ "workshopOne": "Atelier 1",
+ "refIdSemiColon": "ID de référence :",
+ "addFearedEvent": "Ajouter un événement redouté",
+ "addEbiosRMstudy": "Ajouter une étude Ebios RM",
+ "noAuthor": "Aucun auteur attribué",
+ "noReviewer": "Aucun relecteur assigné",
+ "selectAudit": "Sélectionner un audit",
+ "errorAssetGraphMustNotContainCycles": "Le graphe des actifs ne doit pas contenir de boucles.",
+ "addStakeholder": "Ajouter une partie prenante",
+ "operationalScenario": "Scénario opérationnel",
+ "operationalScenarioRefId": "Scénario opérationnel {refId}",
+ "operationalScenarios": "Scénarios opérationnels",
+ "addOperationalScenario": "Ajouter un scénario opérationnel",
+ "workshopFour": "Atelier 4",
+ "noThreat": "Aucune menace",
+ "likely": "Probable",
+ "unlikely": "Peu probable",
+ "veryLikely": "Très probable",
+ "certain": "Certain",
+ "minor": "Mineure",
+ "operatingModesDescription": "Description des modes opératoires",
+ "noStakeholders": "Aucune partie prenante",
+ "strategicScenario": "Scénario stratégique",
+ "strategicScenarios": "Scénarios stratégiques",
+ "goBackToEbiosRmStudy": "Retour à l'étude",
+ "addStrategicScenario": "Ajouter un scénario stratégique"
}
From 3a5fc41fefd3009cb24b3654b0bf869a160b88e3 Mon Sep 17 00:00:00 2001
From: Abderrahmane Smimite
Date: Thu, 19 Dec 2024 14:08:27 +0100
Subject: [PATCH 21/25] translations - extra
---
frontend/messages/en.json | 12 +-
frontend/messages/fr.json | 4 +-
.../components/CommandPalette/paletteData.ts | 120 +++++++++---------
.../workshop-one/ebios-rm-study/+page.svelte | 2 +-
4 files changed, 71 insertions(+), 67 deletions(-)
diff --git a/frontend/messages/en.json b/frontend/messages/en.json
index 6d182b013..3982c8129 100644
--- a/frontend/messages/en.json
+++ b/frontend/messages/en.json
@@ -923,18 +923,18 @@
"ebiosWs5_3": "Define security measures",
"ebiosWs5_4": "Assess and document residual risks",
"ebiosWs5_5": "Establish risk monitoring framework",
- "activity": "Activity",
+ "activity": "Step",
"ebiosRmMatrixHelpText": "Risk matrix used as a reference for the study. Defaults to `urn:intuitem:risk:library:risk-matrix-4x4-ebios-rm`",
- "activityOne": "Activity 1",
- "activityTwo": "Activity 2",
- "activityThree": "Activity 3",
+ "activityOne": "Step 1",
+ "activityTwo": "Step 2",
+ "activityThree": "Step 3",
"ebiosRmStudy": "Ebios RM study",
"qualifications": "Qualifications",
"impacts": "Impacts",
"ebiosRmStudies": "Ebios RM studies",
"bringTheEvidences": "Bring the evidences",
"bringTheEvidencesHelpText": "If disabled, the object will be duplicated without its evidences",
- "gravity": "Gravity",
+ "gravity": "Severity",
"existingControlsHelper": "What do you currently have to manage this risk",
"extraControlsHelper": "What will you do to mitigate this risk",
"existingContextHelper": "Description of the existing mitigations (this field will be deprecated soon)",
@@ -962,7 +962,7 @@
"organizedCrime": "Organized crime",
"terrorist": "Terrorist",
"activist": "Activist",
- "professional": "Professional",
+ "professional": "Competitor",
"amateur": "Amateur",
"avenger": "Avenger",
"pathological": "Pathological",
diff --git a/frontend/messages/fr.json b/frontend/messages/fr.json
index 6b65dd88a..a7e674606 100644
--- a/frontend/messages/fr.json
+++ b/frontend/messages/fr.json
@@ -804,7 +804,7 @@
"mtd": "MTD",
"mtdHelpText": "Temps d'arrêt maximal tolérable",
"securityObjectives": "Objectifs de sécurité",
- "disasterRecoveryObjectives": "Objectifs de reprise après sinistre",
+ "disasterRecoveryObjectives": "Objectifs de reprise d'activité",
"noExpirationDateSet": "Aucune date d'expiration définie",
"sumpageTotal": "Total",
"sumpageActive": "Actif",
@@ -987,7 +987,7 @@
"resetPassword": "Réinitialiser le mot de passe",
"ebiosRm": "Ebios RM",
"workshopOne": "Atelier 1",
- "refIdSemiColon": "ID de référence :",
+ "refIdSemiColon": "ID :",
"addFearedEvent": "Ajouter un événement redouté",
"addEbiosRMstudy": "Ajouter une étude Ebios RM",
"noAuthor": "Aucun auteur attribué",
diff --git a/frontend/src/lib/components/CommandPalette/paletteData.ts b/frontend/src/lib/components/CommandPalette/paletteData.ts
index 8903454cc..50ab4e47f 100644
--- a/frontend/src/lib/components/CommandPalette/paletteData.ts
+++ b/frontend/src/lib/components/CommandPalette/paletteData.ts
@@ -1,65 +1,69 @@
import * as m from '$paraglide/messages';
export interface NavigationLink {
- label: string;
- href: string;
+ label: string;
+ href: string;
}
export const navigationLinks: NavigationLink[] = [
- {
- label: 'analytics',
- href: '/'
- },
- {
- label: 'myAssignments',
- href: '/my-assignments'
- },
- {
- label: 'domains',
- href: '/folders'
- },
- {
- label: 'assets',
- href: '/assets'
- },
- {
- label: 'complianceAssessments',
- href: '/compliance-assessments'
- },
- {
- label: 'riskAssessments',
- href: '/risk-assessments'
- },
- {
- label: 'riskScenarios',
- href: '/risk-scenarios'
- },
- {
- label: 'actionPlan',
- href: '/applied-controls'
- },
- {
- label: 'evidences',
- href: '/evidences'
- },
- {
- label: 'xRays',
- href: '/x-rays'
- },
- {
- label: 'tpSolutions',
- href: '/solutions'
- },
- {
- label: 'libraries',
- href: '/libraries'
- },
- {
- label: 'myProfile',
- href: '/my-profile'
- },
- {
- label: 'settings',
- href: '/settings'
- }
+ {
+ label: 'analytics',
+ href: '/'
+ },
+ {
+ label: 'myAssignments',
+ href: '/my-assignments'
+ },
+ {
+ label: 'domains',
+ href: '/folders'
+ },
+ {
+ label: 'assets',
+ href: '/assets'
+ },
+ {
+ label: 'complianceAssessments',
+ href: '/compliance-assessments'
+ },
+ {
+ label: 'riskAssessments',
+ href: '/risk-assessments'
+ },
+ {
+ label: 'riskScenarios',
+ href: '/risk-scenarios'
+ },
+ {
+ label: 'ebiosRM',
+ href: '/ebios-rm'
+ },
+ {
+ label: 'actionPlan',
+ href: '/applied-controls'
+ },
+ {
+ label: 'evidences',
+ href: '/evidences'
+ },
+ {
+ label: 'xRays',
+ href: '/x-rays'
+ },
+ {
+ label: 'tpSolutions',
+ href: '/solutions'
+ },
+ {
+ label: 'libraries',
+ href: '/libraries'
+ },
+ {
+ label: 'myProfile',
+ href: '/my-profile'
+ },
+ {
+ label: 'settings',
+ href: '/settings'
+ }
];
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.svelte
index 55c599eed..251499d38 100644
--- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.svelte
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/workshop-one/ebios-rm-study/+page.svelte
@@ -81,7 +81,7 @@
{ebiosRmStudy.name} - v{ebiosRmStudy.version}
- {ebiosRmStudy.status}
+ {safeTranslate(ebiosRmStudy.status)}
Date: Thu, 19 Dec 2024 14:11:09 +0100
Subject: [PATCH 22/25] formatter
---
.../components/CommandPalette/paletteData.ts | 124 +++++++++---------
1 file changed, 62 insertions(+), 62 deletions(-)
diff --git a/frontend/src/lib/components/CommandPalette/paletteData.ts b/frontend/src/lib/components/CommandPalette/paletteData.ts
index 50ab4e47f..491235c04 100644
--- a/frontend/src/lib/components/CommandPalette/paletteData.ts
+++ b/frontend/src/lib/components/CommandPalette/paletteData.ts
@@ -1,69 +1,69 @@
import * as m from '$paraglide/messages';
export interface NavigationLink {
- label: string;
- href: string;
+ label: string;
+ href: string;
}
export const navigationLinks: NavigationLink[] = [
- {
- label: 'analytics',
- href: '/'
- },
- {
- label: 'myAssignments',
- href: '/my-assignments'
- },
- {
- label: 'domains',
- href: '/folders'
- },
- {
- label: 'assets',
- href: '/assets'
- },
- {
- label: 'complianceAssessments',
- href: '/compliance-assessments'
- },
- {
- label: 'riskAssessments',
- href: '/risk-assessments'
- },
- {
- label: 'riskScenarios',
- href: '/risk-scenarios'
- },
- {
- label: 'ebiosRM',
- href: '/ebios-rm'
- },
- {
- label: 'actionPlan',
- href: '/applied-controls'
- },
- {
- label: 'evidences',
- href: '/evidences'
- },
- {
- label: 'xRays',
- href: '/x-rays'
- },
- {
- label: 'tpSolutions',
- href: '/solutions'
- },
- {
- label: 'libraries',
- href: '/libraries'
- },
- {
- label: 'myProfile',
- href: '/my-profile'
- },
- {
- label: 'settings',
- href: '/settings'
- }
+ {
+ label: 'analytics',
+ href: '/'
+ },
+ {
+ label: 'myAssignments',
+ href: '/my-assignments'
+ },
+ {
+ label: 'domains',
+ href: '/folders'
+ },
+ {
+ label: 'assets',
+ href: '/assets'
+ },
+ {
+ label: 'complianceAssessments',
+ href: '/compliance-assessments'
+ },
+ {
+ label: 'riskAssessments',
+ href: '/risk-assessments'
+ },
+ {
+ label: 'riskScenarios',
+ href: '/risk-scenarios'
+ },
+ {
+ label: 'ebiosRM',
+ href: '/ebios-rm'
+ },
+ {
+ label: 'actionPlan',
+ href: '/applied-controls'
+ },
+ {
+ label: 'evidences',
+ href: '/evidences'
+ },
+ {
+ label: 'xRays',
+ href: '/x-rays'
+ },
+ {
+ label: 'tpSolutions',
+ href: '/solutions'
+ },
+ {
+ label: 'libraries',
+ href: '/libraries'
+ },
+ {
+ label: 'myProfile',
+ href: '/my-profile'
+ },
+ {
+ label: 'settings',
+ href: '/settings'
+ }
];
From 72c6d5d719ead8ae93e7441c16a0f84716c287df Mon Sep 17 00:00:00 2001
From: Mohamed-Hacene
Date: Thu, 19 Dec 2024 20:53:37 +0100
Subject: [PATCH 23/25] feat: calculate gravity for selected feared events
---
backend/ebios_rm/models.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/ebios_rm/models.py b/backend/ebios_rm/models.py
index e50285cf4..bf927bba9 100644
--- a/backend/ebios_rm/models.py
+++ b/backend/ebios_rm/models.py
@@ -257,7 +257,7 @@ def get_pertinence(self):
def get_gravity(self):
gravity = -1
for feared_event in self.feared_events.all():
- if feared_event.gravity > gravity:
+ if feared_event.gravity > gravity and feared_event.is_selected:
gravity = feared_event.gravity
return gravity
From 4b58eb28c51fa80767fd685a9a4fee50898f4b2f Mon Sep 17 00:00:00 2001
From: Nassim Tabchiche
Date: Fri, 20 Dec 2024 09:57:11 +0100
Subject: [PATCH 24/25] chore: Fix conflicting migrations
---
...ove_attackpath_ro_to_couple_strategicscenario_and_more.py} | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
rename backend/ebios_rm/migrations/{0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py => 0008_remove_attackpath_ro_to_couple_strategicscenario_and_more.py} (96%)
diff --git a/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py b/backend/ebios_rm/migrations/0008_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
similarity index 96%
rename from backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
rename to backend/ebios_rm/migrations/0008_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
index ad78b823d..3c98cffa8 100644
--- a/backend/ebios_rm/migrations/0007_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
+++ b/backend/ebios_rm/migrations/0008_remove_attackpath_ro_to_couple_strategicscenario_and_more.py
@@ -1,4 +1,4 @@
-# Generated by Django 5.1.4 on 2024-12-17 18:10
+# Generated by Django 5.1.4 on 2024-12-20 08:56
import django.db.models.deletion
import iam.models
@@ -8,7 +8,7 @@
class Migration(migrations.Migration):
dependencies = [
- ("ebios_rm", "0006_alter_attackpath_stakeholders"),
+ ("ebios_rm", "0007_ebiosrmstudy_meta"),
("iam", "0010_user_preferences"),
]
From d521e7c0e113cee33ea85f11ccbc42a9d8319972 Mon Sep 17 00:00:00 2001
From: Nassim Tabchiche
Date: Fri, 20 Dec 2024 10:37:14 +0100
Subject: [PATCH 25/25] Fix workshop 4 urls
---
.../routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte
index 87c405b67..03e6db3e1 100644
--- a/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte
+++ b/frontend/src/routes/(app)/(internal)/ebios-rm/[id=uuid]/+page.svelte
@@ -81,12 +81,12 @@
{
title: safeTranslate(m.ebiosWs4_1()),
status: 'to_do',
- href: `${$page.url.pathname}/workshop-four/operational-scenario?activity=one&next=${$page.url.pathname}`
+ href: `${$page.url.pathname}/workshop-4/operational-scenario?activity=one&next=${$page.url.pathname}`
},
{
title: safeTranslate(m.ebiosWs4_2()),
status: 'to_do',
- href: `${$page.url.pathname}/workshop-four/operational-scenario?activity=two&next=${$page.url.pathname}`
+ href: `${$page.url.pathname}/workshop-4/operational-scenario?activity=two&next=${$page.url.pathname}`
}
],
ws5: [