Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Workshop 3 #1139

Merged
merged 26 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8ba5ace
Add stakeholders urlmodel
nas-tabchiche Dec 5, 2024
6121a30
Write StakeholderForm
nas-tabchiche Dec 5, 2024
40c9c06
Internationalize stakeholder fields
nas-tabchiche Dec 5, 2024
1b9f758
Write workshop 3 ecosystem page
nas-tabchiche Dec 5, 2024
3f552d0
Map workshop 3.1 and 3.3 page to EBIOS RM tiles
nas-tabchiche Dec 5, 2024
6d000ac
Add string representation for Stakeholder model
nas-tabchiche Dec 5, 2024
5e52b95
Update stakeholder modeltable default fields
nas-tabchiche Dec 5, 2024
68a4efb
Add attack paths urlmodel
nas-tabchiche Dec 5, 2024
0603fd6
Write AttackPathForm component
nas-tabchiche Dec 5, 2024
13d33e0
Internationalize likelihood field
nas-tabchiche Dec 5, 2024
8b09582
Add strategic scenarios page
nas-tabchiche Dec 5, 2024
7f9d0c7
Internationalize stakeholders field
nas-tabchiche Dec 9, 2024
6de8a03
Fix AttackPathForm
nas-tabchiche Dec 9, 2024
58196b9
Improve RO/TO and AttackPath __str__ methods
nas-tabchiche Dec 9, 2024
f3a27de
Serialize attack path risk origin and target objective
nas-tabchiche Dec 9, 2024
99765de
Add ebios_rm_study filterset field to stakeholder and attack path vie…
nas-tabchiche Dec 9, 2024
d686b8d
Add translations
nas-tabchiche Dec 9, 2024
f150dc4
Properly display RO/TO choices in AttackPathForm
nas-tabchiche Dec 9, 2024
e0b6835
Update attack path schema and crud entry
nas-tabchiche Dec 9, 2024
d8468a0
Update attack path model table
nas-tabchiche Dec 9, 2024
ce6e1a2
Properly display stakeholders choices in AttackPathForm
nas-tabchiche Dec 9, 2024
5f9ddee
Internationalize criticality fields
nas-tabchiche Dec 9, 2024
4c3eb2e
Remove unused import
nas-tabchiche Dec 9, 2024
2c8128f
feat: add attack-paths and stakeholders ebios-rm foreignKey
Mohamed-Hacene Dec 9, 2024
a75fefe
feat: add attack-paths and stakeholders folder foreignKey
Mohamed-Hacene Dec 9, 2024
96ba91c
feat : add ebios foreignKeyFields endpointUrls
Mohamed-Hacene Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions backend/ebios_rm/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ class Pertinence(models.IntegerChoices):
is_selected = models.BooleanField(verbose_name=_("Is selected"), default=False)
justification = models.TextField(verbose_name=_("Justification"), blank=True)

def __str__(self) -> str:
return f"{self.get_risk_origin_display()} - {self.target_objective}"

class Meta:
verbose_name = _("RO/TO couple")
verbose_name_plural = _("RO/TO couples")
Expand Down Expand Up @@ -322,6 +325,9 @@ class Meta:
verbose_name_plural = _("Stakeholders")
ordering = ["created_at"]

def __str__(self):
return f"{self.entity.name} - {self.get_category_display()}"

def save(self, *args, **kwargs):
self.folder = self.ebios_rm_study.folder
super().save(*args, **kwargs)
Expand Down
2 changes: 2 additions & 0 deletions backend/ebios_rm/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ class AttackPathReadSerializer(BaseModelSerializer):
folder = FieldsRelatedField()
ro_to_couple = FieldsRelatedField()
stakeholders = FieldsRelatedField(many=True)
risk_origin = serializers.CharField(source="ro_to_couple.get_risk_origin_display")
target_objective = serializers.CharField(source="ro_to_couple.target_objective")

class Meta:
model = AttackPath
Expand Down
8 changes: 8 additions & 0 deletions backend/ebios_rm/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ def pertinence(self, request):
class StakeholderViewSet(BaseModelViewSet):
model = Stakeholder

filterset_fields = [
"ebios_rm_study",
]

@action(detail=False, name="Get category choices")
def category(self, request):
return Response(dict(Stakeholder.Category.choices))
Expand All @@ -109,6 +113,10 @@ def category(self, request):
class AttackPathViewSet(BaseModelViewSet):
model = AttackPath

filterset_fields = [
"ebios_rm_study",
]


class OperationalScenarioViewSet(BaseModelViewSet):
model = OperationalScenario
17 changes: 16 additions & 1 deletion frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -955,12 +955,27 @@
"fairlyRelevant": "Fairly relevant",
"highlyRelevant": "Highly relevant",
"roTo": "RO/TO",
"roToCouple": "RO/TO couple",
"addRoto": "Add RO/TO couple",
"organizedCrime": "Organized crime",
"terrorist": "Terrorist",
"activist": "Activist",
"professional": "Professional",
"amateur": "Amateur",
"avenger": "Avenger",
"pathological": "Pathological"
"pathological": "Pathological",
"currentDependency": "Current dependency",
"currentPenetration": "Current penetration",
"currentMaturity": "Current maturity",
"currentTrust": "Current trust",
"residualDependency": "Residual dependency",
"residualPenetration": "Residual penetration",
"residualMaturity": "Residual maturity",
"residualTrust": "Residual trust",
"selected": "Selected",
"likelihood": "Likelihood",
"stakeholders": "Stakeholders",
"addAttackPath": "Add attack path",
"currentCriticality": "Current criticality",
"residualCriticality": "Residual criticality"
}
6 changes: 6 additions & 0 deletions frontend/src/lib/components/Forms/ModelForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import EbiosRmForm from './ModelForm/EbiosRmForm.svelte';
import FearedEventForm from './ModelForm/FearedEventForm.svelte';
import RoToForm from './ModelForm/RoToForm.svelte';
import StakeholderForm from './ModelForm/StakeholderForm.svelte';
import AttackPathForm from './ModelForm/AttackPathForm.svelte';

import AutocompleteSelect from './AutocompleteSelect.svelte';

Expand Down Expand Up @@ -264,6 +266,10 @@
<FearedEventForm {form} {model} {cacheLocks} {formDataCache} {initialData} />
{:else if URLModel === 'ro-to'}
<RoToForm {form} {model} {cacheLocks} {formDataCache} {initialData} />
{:else if URLModel === 'stakeholders'}
<StakeholderForm {form} {model} {cacheLocks} {formDataCache} {context} />
{:else if URLModel === 'attack-paths'}
<AttackPathForm {form} {model} {cacheLocks} {formDataCache} {initialData} />
{/if}
<div class="flex flex-row justify-between space-x-4">
{#if closeModal}
Expand Down
50 changes: 50 additions & 0 deletions frontend/src/lib/components/Forms/ModelForm/AttackPathForm.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script lang="ts">
import type { SuperValidated } from 'sveltekit-superforms';
import type { ModelInfo, CacheLock } from '$lib/utils/types';
import TextField from '$lib/components/Forms/TextField.svelte';
import AutocompleteSelect from '$lib/components/Forms/AutocompleteSelect.svelte';
import Select from '$lib/components/Forms/Select.svelte';
import * as m from '$paraglide/messages.js';
import { getOptions } from '$lib/utils/crud';
import TextArea from '../TextArea.svelte';
import NumberField from '../NumberField.svelte';
import Checkbox from '../Checkbox.svelte';

export let form: SuperValidated<any>;
export let model: ModelInfo;
export let cacheLocks: Record<string, CacheLock> = {};
export let formDataCache: Record<string, any> = {};
export let initialData: Record<string, any> = {};
export let context: 'create' | 'edit' = 'create';
</script>

<AutocompleteSelect
{form}
options={getOptions({ objects: model.foreignKeys['ro_to_couple'], label: 'str' })}
field="ro_to_couple"
cacheLock={cacheLocks['ro_to_couple']}
bind:cachedValue={formDataCache['ro_to_couple']}
label={m.roToCouple()}
hidden={initialData.ro_to_couple}
/>
<AutocompleteSelect
{form}
multiple
options={getOptions({
objects: model.foreignKeys['stakeholders'],
label: 'str'
})}
field="stakeholders"
cacheLock={cacheLocks['stakeholders']}
bind:cachedValue={formDataCache['stakeholders']}
label={m.stakeholders()}
/>

<Checkbox {form} field="is_selected" label={m.selected()} />
<TextArea
{form}
field="justification"
label={m.justification()}
cacheLock={cacheLocks['justification']}
bind:cachedValue={formDataCache['justification']}
/>
116 changes: 116 additions & 0 deletions frontend/src/lib/components/Forms/ModelForm/StakeholderForm.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<script lang="ts">
import type { SuperValidated } from 'sveltekit-superforms';
import type { ModelInfo, CacheLock } from '$lib/utils/types';
import AutocompleteSelect from '$lib/components/Forms/AutocompleteSelect.svelte';
import Select from '$lib/components/Forms/Select.svelte';
import * as m from '$paraglide/messages.js';
import { getOptions } from '$lib/utils/crud';
import TextArea from '../TextArea.svelte';
import NumberField from '../NumberField.svelte';
import Checkbox from '../Checkbox.svelte';

export let form: SuperValidated<any>;
export let model: ModelInfo;
export let cacheLocks: Record<string, CacheLock> = {};
export let formDataCache: Record<string, any> = {};
export let initialData: Record<string, any> = {};
export let context: 'create' | 'edit' = 'create';
</script>

<AutocompleteSelect
{form}
options={getOptions({ objects: model.foreignKeys['entity'] })}
field="entity"
cacheLock={cacheLocks['entity']}
bind:cachedValue={formDataCache['entity']}
label={m.entity()}
hidden={initialData.entity}
/>
<Select
{form}
options={model.selectOptions['category']}
field="category"
label={m.category()}
cacheLock={cacheLocks['category']}
bind:cachedValue={formDataCache['category']}
/>

{#if context === 'edit'}
<NumberField
{form}
field="current_dependency"
label={m.currentDependency()}
cacheLock={cacheLocks['current_dependency']}
bind:cachedValue={formDataCache['current_dependency']}
/>
<NumberField
{form}
field="current_penetration"
label={m.currentPenetration()}
cacheLock={cacheLocks['current_penetration']}
bind:cachedValue={formDataCache['current_penetration']}
/>
<NumberField
{form}
field="current_maturity"
label={m.currentMaturity()}
cacheLock={cacheLocks['current_maturity']}
bind:cachedValue={formDataCache['current_maturity']}
/>
<NumberField
{form}
field="current_trust"
label={m.currentTrust()}
cacheLock={cacheLocks['current_trust']}
bind:cachedValue={formDataCache['current_trust']}
/>

<AutocompleteSelect
multiple
{form}
options={getOptions({
objects: model.foreignKeys['applied_controls'],
extra_fields: [['folder', 'str']]
})}
field="applied_controls"
label={m.appliedControls()}
/>

<NumberField
{form}
field="residual_dependency"
label={m.residualDependency()}
cacheLock={cacheLocks['residual_dependency']}
bind:cachedValue={formDataCache['residual_dependency']}
/>
<NumberField
{form}
field="residual_penetration"
label={m.residualPenetration()}
cacheLock={cacheLocks['residual_penetration']}
bind:cachedValue={formDataCache['residual_penetration']}
/>
<NumberField
{form}
field="residual_maturity"
label={m.residualMaturity()}
cacheLock={cacheLocks['residual_maturity']}
bind:cachedValue={formDataCache['residual_maturity']}
/>
<NumberField
{form}
field="residual_trust"
label={m.residualTrust()}
cacheLock={cacheLocks['residual_trust']}
bind:cachedValue={formDataCache['residual_trust']}
/>

<Checkbox {form} field="is_selected" label={m.selected()} />
<TextArea
{form}
field="justification"
label={m.justification()}
cacheLock={cacheLocks['justification']}
bind:cachedValue={formDataCache['justification']}
/>
{/if}
30 changes: 30 additions & 0 deletions frontend/src/lib/utils/crud.ts
Copy link
Collaborator

@Mohamed-Hacene Mohamed-Hacene Dec 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add in attack-paths and stakeholdes ebios_rm_study, folder foreignKeyFields for link in DetailedView.

Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export const getOptions = ({
interface ForeignKeyField {
field: string;
urlModel: urlModel;
endpointUrl?: string;
urlParams?: string;
}

Expand Down Expand Up @@ -641,6 +642,35 @@ export const URL_MODEL_MAP: ModelMap = {
{ field: 'resources', valueType: 'number' },
{ field: 'pertinence', valueType: 'number' }
]
},
stakeholders: {
endpointUrl: 'ebios-rm/stakeholders',
name: 'stakeholder',
localName: 'stakeholder',
localNamePlural: 'stakeholders',
verboseName: 'Stakeholder',
verboseNamePlural: 'Stakeholders',
foreignKeyFields: [
{ field: 'entity', urlModel: 'entities' },
{ field: 'applied_controls', urlModel: 'applied-controls' },
{ field: 'ebios_rm_study', urlModel: 'ebios-rm' },
{ field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' }
],
selectFields: [{ field: 'category' }]
},
'attack-paths': {
endpointUrl: 'ebios-rm/attack-paths',
name: 'attackpath',
localName: 'attackPath',
localNamePlural: 'attackPaths',
verboseName: 'Attack path',
verboseNamePlural: 'Attack paths',
foreignKeyFields: [
{ field: 'stakeholders', urlModel: 'stakeholders', endpointUrl: 'ebios-rm/stakeholders' },
{ field: 'ro_to_couple', urlModel: 'ro-to', endpointUrl: 'ebios-rm/ro-to' },
{ field: 'ebios_rm_study', urlModel: 'ebios-rm' },
{ field: 'folder', urlModel: 'folders', urlParams: 'content_type=DO' }
]
}
};

Expand Down
30 changes: 29 additions & 1 deletion frontend/src/lib/utils/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,32 @@ export const roToSchema = z.object({
justification: z.string().optional()
});

export const StakeholderSchema = z.object({
ebios_rm_study: z.string(),
applied_controls: z.string().uuid().optional().array().optional(),
category: z.string().optional(),
entity: z.string().optional(),
current_dependency: z.number().min(0).max(4).optional(),
current_penetration: z.number().min(0).max(4).optional(),
current_maturity: z.number().min(1).max(4).optional(),
current_trust: z.number().min(1).max(4).optional(),
residual_dependency: z.number().min(0).max(4).optional(),
residual_penetration: z.number().min(0).max(4).optional(),
residual_maturity: z.number().min(1).max(4).optional(),
residual_trust: z.number().min(1).max(4).optional(),
is_selected: z.boolean().optional(),
justification: z.string().optional()
});

export const AttackPathSchema = z.object({
ebios_rm_study: z.string(),
ro_to_couple: z.string().uuid(),
stakeholders: z.string().uuid().array(),
description: z.string(),
is_selected: z.boolean().optional(),
justification: z.string().optional()
});

const SCHEMA_MAP: Record<string, AnyZodObject> = {
folders: FolderSchema,
projects: ProjectSchema,
Expand Down Expand Up @@ -453,7 +479,9 @@ const SCHEMA_MAP: Record<string, AnyZodObject> = {
'filtering-labels': FilteringLabelSchema,
'ebios-rm': ebiosRMSchema,
'feared-events': fearedEventsSchema,
'ro-to': roToSchema
'ro-to': roToSchema,
stakeholders: StakeholderSchema,
'attack-paths': AttackPathSchema
};

export const modelSchema = (model: string) => {
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/lib/utils/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,5 +573,13 @@ export const listViewFields: ListViewFieldsConfig = {
'feared_events',
'pertinence'
]
},
stakeholders: {
head: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality'],
body: ['entity', 'category', 'current_criticality', 'applied_controls', 'residual_criticality']
},
'attack-paths': {
head: ['risk_origin', 'target_objective', 'stakeholders', 'attackPath'],
body: ['risk_origin', 'target_objective', 'stakeholders', 'description']
}
};
4 changes: 3 additions & 1 deletion frontend/src/lib/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export const URL_MODEL = [
'vulnerabilities',
'filtering-labels',
'feared-events',
'ro-to'
'ro-to',
'stakeholders',
'attack-paths'
// 'ebios-rm',
] as const;

Expand Down
Loading
Loading