Skip to content

Commit

Permalink
Merge branch 'main' into CA-141-prevent-deleting-a-library-that-is-in…
Browse files Browse the repository at this point in the history
…-use-in-an-assessment
  • Loading branch information
nas-tabchiche committed Feb 12, 2024
2 parents a70bba8 + 67d24f4 commit 16ad95e
Show file tree
Hide file tree
Showing 21 changed files with 105 additions and 40 deletions.
7 changes: 5 additions & 2 deletions backend/app_tests/api/test_api_requirement_assessments.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def test_get_requirement_assessments(self, authenticated_client):
},
{
"folder": str(folder.id),
"compliance_assessment": str(compliance_assessment.id),
"compliance_assessment": {"id": str(compliance_assessment.id), "str": compliance_assessment.name},
"requirement": str(RequirementNode.objects.all()[0].id),
},
-1,
Expand Down Expand Up @@ -143,6 +143,9 @@ def test_create_requirement_assessments(self, authenticated_client):
"requirement": str(RequirementNode.objects.all()[0].id),
"security_measures": [str(security_measure.id)],
},
{
"compliance_assessment": {"id": str(compliance_assessment.id), "str": compliance_assessment.name}
},
base_count=-1,
)

Expand Down Expand Up @@ -186,7 +189,7 @@ def test_update_requirement_assessments(self, authenticated_client):
},
{
"folder": str(Folder.get_root_folder().id),
"compliance_assessment": str(compliance_assessment.id),
"compliance_assessment": {"id": str(compliance_assessment.id), "str": compliance_assessment.name},
"requirement": str(RequirementNode.objects.all()[0].id),
},
)
Expand Down
2 changes: 2 additions & 0 deletions backend/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ class Meta:

class RequirementAssessmentReadSerializer(BaseModelSerializer):
name = serializers.CharField(source="__str__")
compliance_assessment = FieldsRelatedField()


class Meta:
model = RequirementAssessment
Expand Down
3 changes: 2 additions & 1 deletion backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ class SecurityMeasureViewSet(BaseModelViewSet):
"effort",
"risk_scenarios",
"requirement_assessments",
"evidences"
]
search_fields = ["name", "description", "risk_scenarios", "requirement_assessments"]

Expand Down Expand Up @@ -1161,7 +1162,7 @@ class RequirementAssessmentViewSet(BaseModelViewSet):
"""

model = RequirementAssessment
filterset_fields = ["folder"]
filterset_fields = ["folder", "evidences"]
search_fields = ["name", "description"]

@action(detail=False, name="Get updatable measures")
Expand Down
2 changes: 2 additions & 0 deletions frontend/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ node_modules
.env
.env.*
!.env.example
/tests/reports/*
/tests/results/*

# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
Expand Down
2 changes: 2 additions & 0 deletions frontend/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ node_modules
.env
.env.*
!.env.example
/tests/reports/*
/tests/results/*

# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
Expand Down
14 changes: 0 additions & 14 deletions frontend/src/lib/components/Forms/ModelForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -248,20 +248,6 @@
label="Domain"
hide={initialData.security_measures || initialData.requirement_assessments}
/>
<AutocompleteSelect
{form}
multiple
options={getOptions({ objects: model.foreignKeys['security_measures'] })}
field="security_measures"
label="Security measures"
/>
<AutocompleteSelect
{form}
multiple
options={getOptions({ objects: model.foreignKeys['requirement_assessments'] })}
field="requirement_assessments"
label="Requirement assessments"
/>
<TextField
{form}
field="link"
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/lib/components/Modals/CreateModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
{$modalStore[0].title ?? '(title missing)'}
</header>
<div
role="button"
tabindex="0"
class="flex items-center hover:text-primary-500 cursor-pointer"
on:click={parent.onClose}
on:keydown={parent.onClose}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
$: display = LOCALE_DISPLAY_MAP[cell];
</script>

<span {...$$restProps}>{@html display}</span>
<span {...$$restProps}>{display}</span>
2 changes: 1 addition & 1 deletion frontend/src/lib/components/ModelTable/ModelTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
if (['Enter', 'Space'].includes(event.code)) onRowClick(event, rowIndex);
}
export let identifierField: string = 'id';
export let identifierField = 'id';
export let deleteForm: SuperValidated<AnyZodObject> | undefined = undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,13 @@
}}
>
{#if typeof node.content === 'string'}
{@html node.content}
{node.content}
{:else}
<svelte:component this={node.content} {...node.contentProps} />
{/if}
<svelte:fragment slot="lead">
{#if typeof node.lead === 'string'}
{@html node.lead}
{node.lead}
{:else}
<svelte:component this={node.lead} {...node.leadProps} />
{/if}
Expand Down
16 changes: 8 additions & 8 deletions frontend/src/lib/components/fragments/WatchlistExceptions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,21 @@
request_path
)}'"
>
<td scope="row" class="px-3 py-4 font-medium">
<th scope="row" class="px-3 py-4 font-medium">
{#if acceptance.approver == user.id && acceptance.state == 'submitted'}
<span class="mr-1 p-1 rounded-md text-xs bg-indigo-500 text-white">
action requested
</span>
{/if}
{acceptance.name}
</td>
<td class="px-3 py-4">
</th>
<th class="px-3 py-4">
{acceptance.folder.str}
</td>
<td class="px-3 py-4">
</th>
<th class="px-3 py-4">
{acceptance.approver.str}
</td>
<td class="px-3 py-4">
</th>
<th class="px-3 py-4">
{#if acceptanceState(acceptance.expiry_date) === 'expired'}
<span class="rounded bg-red-500 text-white p-1 text-xs mr-1">expired</span>
{:else if acceptanceState(acceptance.expiry_date) === 'upcoming'}
Expand All @@ -66,7 +66,7 @@
<span class="rounded bg-yellow-500 text-white p-1 text-xs mr-1">today</span>
{/if}
{formatStringToDate(acceptance.expiry_date)}
</td>
</th>
</tr>
{/each}
{:else}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib/utils/crud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ export const URL_MODEL_MAP: ModelMap = {
selectFields: [{ field: 'status' }],
foreignKeyFields: [
{ field: 'security_measures', urlModel: 'security-measures' },
{ field: 'evidences', urlModel: 'evidences' }
{ field: 'evidences', urlModel: 'evidences' },
{ field: 'compliance_assessment', urlModel: 'compliance-assessments' }
]
},
libraries: {
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/lib/utils/csrf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ async function getCsrfToken() {
credentials: 'include'
}).then((res) => res.json());
return response.csrfToken;
} catch (error) {}
} catch (error) {
console.error(error);
}
}

export const csrfToken = await getCsrfToken();
4 changes: 4 additions & 0 deletions frontend/src/lib/utils/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export const listViewFields = {
head: ['Name', 'Framework', 'Description', 'Project'],
body: ['name', 'framework', 'description', 'project']
},
'requirement-assessments': {
head: ['Name', 'Description', 'Compliance Assessment'],
body: ['name', 'description', 'compliance_assessment']
},
evidences: {
head: ['Name', 'File', 'Description'],
body: ['name', 'attachment', 'description']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
if (node.children && Object.keys(node.children).length > 0) {
for (const childId in node.children) {
if (node.children.hasOwnProperty(childId)) {
if (Object.prototype.hasOwnProperty.call(node.children, childId)) {
const childNode = node.children[childId];
countStatus(childNode, statusCounts);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
export let security_functions: Record<string, any>[] | undefined = undefined;
export let children: Record<string, Record<string, unknown>> | undefined = undefined;
export let canEditRequirementAssessment: boolean;
export let status: string | undefined = undefined;
// export let status: string | undefined = undefined;
export let statusCounts: Record<string, number> | undefined;
$: hasChildren = children && Object.keys(children).length > 0;
Expand Down Expand Up @@ -87,7 +87,7 @@
{#if threats || security_functions}
<div
role="button"
tabindex="-1"
tabindex="0"
class="underline text-sm hover:text-primary-400 {classesShowInfoText(showInfo)}"
on:click={(_) => (showInfo = !showInfo)}
on:keydown={(_) => (showInfo = !showInfo)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
export let status: string;
// export let status: string;
export let statusDisplay: string;
export let statusColor: string;
export let assessable: boolean;
Expand Down
25 changes: 24 additions & 1 deletion frontend/src/routes/(app)/evidences/[id=uuid]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { z } from 'zod';
import { setError, superValidate } from 'sveltekit-superforms/server';
import { setFlash } from 'sveltekit-flash-message/server';
import type { PageServerLoad } from './$types';
import type { urlModel } from '$lib/utils/types';
import { listViewFields } from '$lib/utils/table';
import { tableSourceMapper, type TableSource } from '@skeletonlabs/skeleton';

export const load: PageServerLoad = async ({ fetch, params }) => {
const URLModel = 'evidences';
Expand All @@ -14,7 +17,27 @@ export const load: PageServerLoad = async ({ fetch, params }) => {

const object = await fetch(`${endpoint}object/`).then((res) => res.json());

return { URLModel, evidence, object };
const tables: Record<string, any> = {};

for (const key of ['security-measures', 'requirement-assessments'] as urlModel[]) {
const keyEndpoint = `${BASE_API_URL}/${key}/?evidences=${params.id}`;
const response = await fetch(keyEndpoint);
if (response.ok) {
const data = await response.json().then((data) => data.results);
const bodyData = tableSourceMapper(data, listViewFields[key].body);

const table: TableSource = {
head: listViewFields[key].head,
body: bodyData,
meta: data
};
tables[key] = table;
} else {
console.error(`Failed to fetch data for ${key}: ${response.statusText}`);
}
}

return { URLModel, evidence, object, tables };
};

export const actions: Actions = {
Expand Down
40 changes: 37 additions & 3 deletions frontend/src/routes/(app)/evidences/[id=uuid]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@
import { breadcrumbObject } from '$lib/utils/stores';
import { URL_MODEL_MAP } from '$lib/utils/crud';
import ConfirmModal from '$lib/components/Modals/ConfirmModal.svelte';
import type { ModalSettings, ModalComponent, ModalStore } from '@skeletonlabs/skeleton';
import { getModalStore } from '@skeletonlabs/skeleton';
import type {
ModalSettings,
ModalComponent,
ModalStore,
ToastStore
} from '@skeletonlabs/skeleton';
import { getModalStore, TabGroup, Tab, getToastStore } from '@skeletonlabs/skeleton';
import { isURL } from '$lib/utils/helpers';
import { getModelInfo } from '$lib/utils/crud.js';
import ModelTable from '$lib/components/ModelTable/ModelTable.svelte';
export let data: PageData;
breadcrumbObject.set(data.evidence);
Expand All @@ -21,6 +27,7 @@
let attachment: Attachment | undefined = undefined;
const modalStore: ModalStore = getModalStore();
const toastStore: ToastStore = getToastStore();
function modalConfirm(id: string, name: string, action: string): void {
const modalComponent: ModalComponent = {
Expand Down Expand Up @@ -55,12 +62,14 @@
const user = $page.data.user;
const model = URL_MODEL_MAP['evidences'];
const canEditObject: boolean = Object.hasOwn(user.permissions, `change_${model.name}`);
let tabSet = 0;
</script>

<div class="flex flex-col space-y-4">
<div class="card px-6 py-4 bg-white flex flex-row justify-between shadow-lg">
<div class="flex flex-col space-y-2">
{#each Object.entries(data.evidence).filter( ([key, _]) => ['name', 'description', 'folder', 'security_measures', 'requirement_assessments', 'attachment', 'link', 'comment'].includes(key) ) as [key, value]}
{#each Object.entries(data.evidence).filter( ([key, _]) => ['name', 'description', 'folder', 'attachment', 'link', 'comment'].includes(key) ) as [key, value]}
<div class="flex flex-col">
<div class="text-sm font-medium text-gray-800 capitalize-first">
{#if key === 'urn'}
Expand Down Expand Up @@ -123,6 +132,31 @@
{/if}
</span>
</div>
<div class="card px-6 py-4 bg-white flex flex-col shadow-lg space-y-4">
<TabGroup>
<Tab bind:group={tabSet} name="compliance_assessments_tab" value={0}>Security measures</Tab>
<Tab bind:group={tabSet} name="risk_assessments_tab" value={1}>Requirement assessments</Tab>
<svelte:fragment slot="panel">
{#if tabSet === 0}
<div
class="h-full flex flex-col space-y-2 variant-outline-surface rounded-container-token p-4"
>
<ModelTable source={data.tables['security-measures']} URLModel="security-measures" />
</div>
{/if}
{#if tabSet === 1}
<div
class="h-full flex flex-col space-y-2 variant-outline-surface rounded-container-token p-4"
>
<ModelTable
source={data.tables['requirement-assessments']}
URLModel="requirement-assessments"
/>
</div>
{/if}
</svelte:fragment>
</TabGroup>
</div>
{#if data.evidence.attachment}
<div class="card px-6 py-4 bg-white flex flex-col shadow-lg space-y-4">
<div class="flex flex-row justify-between">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@
</span>
{#if (threats && threats.length > 0) || (security_functions && security_functions.length > 0)}
<div
role="button"
tabindex="0"
class="underline text-sm hover:text-primary-400 {classesShowInfoText(showInfo)}"
on:click={(_) => (showInfo = !showInfo)}
on:keydown={(_) => (showInfo = !showInfo)}
>
<i class="text-xs fa-solid fa-info-circle" /> Learn more
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/routes/(app)/libraries/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const load = (async ({ fetch }) => {
const libraries: Library[] = await res.json().then((res) => res.results);

function countObjects(library: Library) {
let result: { [key: string]: any } = new Object();
const result: { [key: string]: any } = new Object();
for (const [key, value] of Object.entries(library.objects)) {
if (Array.isArray(value)) {
const str = key.charAt(0).toUpperCase() + key.slice(1).replace('_', ' ');
Expand Down

0 comments on commit 16ad95e

Please sign in to comment.