From 5d7ecaf8c0b872af51212c5bacab71c1c35ded5d Mon Sep 17 00:00:00 2001
From: Dor Tambour <57690513+dortam888@users.noreply.github.com>
Date: Wed, 20 Nov 2024 13:19:13 +0200
Subject: [PATCH] Adding webview logic for non applicable vulnerabilities.
(#63)
---
.../ApplicabilityEvidence.module.css | 17 ----
.../Page/Dependency/Dependency.test.tsx | 1 +
src/components/Page/Dependency/Dependency.tsx | 13 ++-
.../ApplicabilityEvidence.module.css | 41 ++++++++++
.../ApplicabilityEvidence.test.tsx | 80 +++++++++++++++++++
.../ApplicabilityEvidence.tsx | 20 ++++-
.../InformationTabs.module.css | 7 +-
.../UI/InformationTabs/InformationTabs.tsx | 31 ++++++-
8 files changed, 180 insertions(+), 30 deletions(-)
delete mode 100644 src/components/Page/Dependency/ApplicabilityEvidence.module.css
create mode 100644 src/components/UI/InformationTabs/ApplicabilityEvidence.module.css
create mode 100644 src/components/UI/InformationTabs/ApplicabilityEvidence.test.tsx
rename src/components/{Page/Dependency => UI/InformationTabs}/ApplicabilityEvidence.tsx (72%)
diff --git a/src/components/Page/Dependency/ApplicabilityEvidence.module.css b/src/components/Page/Dependency/ApplicabilityEvidence.module.css
deleted file mode 100644
index 3ce43d5a..00000000
--- a/src/components/Page/Dependency/ApplicabilityEvidence.module.css
+++ /dev/null
@@ -1,17 +0,0 @@
-.rowList {
- display: flex;
- flex-direction: column;
- gap: 16px;
-}
-.defaultContainer {
- display: flex;
- flex-direction: column;
- gap: 16px;
-}
-.subtitle {
- color: #f0f0f0;
- font-size: 12px;
- font-style: normal;
- font-weight: 600;
- line-height: normal;
-}
diff --git a/src/components/Page/Dependency/Dependency.test.tsx b/src/components/Page/Dependency/Dependency.test.tsx
index 0154059c..a8f41c21 100644
--- a/src/components/Page/Dependency/Dependency.test.tsx
+++ b/src/components/Page/Dependency/Dependency.test.tsx
@@ -116,6 +116,7 @@ describe('Dependency page component', () => {
const expectedTexts = [
TABS.WHAT_CAN_I_DO.label,
+ TABS.CONTEXTUAL_ANALYSIS.label,
TABS.CVE_INFORMATION.label,
TABS.IMPACT_GRAPH.label
]
diff --git a/src/components/Page/Dependency/Dependency.tsx b/src/components/Page/Dependency/Dependency.tsx
index f065bd9e..9f141cbb 100644
--- a/src/components/Page/Dependency/Dependency.tsx
+++ b/src/components/Page/Dependency/Dependency.tsx
@@ -2,23 +2,22 @@ import css from './Dependency.module.css'
import Header from '../../UI/Header/Header'
import { IDependencyPage } from '../../../model'
import InformationTabs, { TABS } from '../../UI/InformationTabs/InformationTabs'
-import ApplicabilityEvidence from './ApplicabilityEvidence'
export interface Props {
data: IDependencyPage
}
export default function Dependency(props: Props): JSX.Element {
- const showApplicabilityEvidence =
- props.data.cve?.applicableData?.evidence ?? props.data.cve?.applicableData?.searchTarget
return (
- {props.data.cve?.applicableData && showApplicabilityEvidence && (
-
- )}
)
diff --git a/src/components/UI/InformationTabs/ApplicabilityEvidence.module.css b/src/components/UI/InformationTabs/ApplicabilityEvidence.module.css
new file mode 100644
index 00000000..503e2d75
--- /dev/null
+++ b/src/components/UI/InformationTabs/ApplicabilityEvidence.module.css
@@ -0,0 +1,41 @@
+.rowList {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+.defaultContainer {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+.subtitle {
+ color: #f0f0f0;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: 600;
+ line-height: normal;
+}
+
+ul.bulletList {
+ list-style-type: disc;
+ padding-left: 20px;
+}
+ul.bulletList li {
+ color: white;
+ font-family: 'Arial', sans-serif;
+ margin-bottom: 10px;
+ display: flex;
+ align-items: center;
+}
+ul {
+ list-style-type: disc;
+ margin-left: 20px;
+}
+
+ol {
+ list-style-type: decimal;
+ margin-left: 20px;
+}
+li {
+ margin-bottom: 20px;
+}
diff --git a/src/components/UI/InformationTabs/ApplicabilityEvidence.test.tsx b/src/components/UI/InformationTabs/ApplicabilityEvidence.test.tsx
new file mode 100644
index 00000000..19b8c348
--- /dev/null
+++ b/src/components/UI/InformationTabs/ApplicabilityEvidence.test.tsx
@@ -0,0 +1,80 @@
+import { render, screen } from '@testing-library/react'
+import ApplicabilityEvidence from './ApplicabilityEvidence'
+import { IApplicableDetails, IEvidence } from '../../../model'
+
+// Sample data for testing
+const applicableData: IApplicableDetails = {
+ isApplicable: true,
+ searchTarget: 'Example search target',
+ evidence: [
+ {
+ filePathEvidence: 'file/path/evidence',
+ codeEvidence: 'const example = "example";',
+ reason: 'Reason for applicability'
+ } as IEvidence
+ ]
+}
+
+const notApplicableData: IApplicableDetails = {
+ isApplicable: false,
+ searchTarget: 'Example search target',
+ evidence: [
+ {
+ reason: 'Reason for non-applicability'
+ } as IEvidence
+ ]
+}
+
+describe('ApplicabilityEvidence component', () => {
+ test('renders applicable CVE information correctly', () => {
+ render()
+ expect(screen.getByText('Contextual Analysis')).toBeInTheDocument()
+ expect(screen.getByText('Why is this CVE applicable?')).toBeInTheDocument()
+ expect(screen.getByText('Reason for applicability')).toBeInTheDocument()
+ expect(screen.getByText('file/path/evidence')).toBeInTheDocument()
+ expect(screen.getByText('const example = "example";')).toBeInTheDocument()
+ expect(screen.getByText('What does the scanner check/look for?')).toBeInTheDocument()
+ expect(screen.getByText('Example search target')).toBeInTheDocument()
+ })
+
+ test('renders non-applicable CVE information correctly', () => {
+ render()
+ expect(screen.getByText('Contextual Analysis')).toBeInTheDocument()
+ expect(screen.getByText('Why is this CVE not applicable?')).toBeInTheDocument()
+ expect(screen.getByText('Reason for non-applicability')).toBeInTheDocument()
+ expect(screen.getByText('What does the scanner check/look for?')).toBeInTheDocument()
+ expect(screen.getByText('Example search target')).toBeInTheDocument()
+ })
+
+ test('renders evidence section correctly when no evidence provided', () => {
+ const noEvidenceData: IApplicableDetails = {
+ isApplicable: true,
+ searchTarget: 'Example search target',
+ evidence: []
+ }
+ render()
+ expect(screen.getByText('Contextual Analysis')).toBeInTheDocument()
+ expect(screen.getByText('Why is this CVE applicable?')).toBeInTheDocument()
+ expect(screen.getByText('What does the scanner check/look for?')).toBeInTheDocument()
+ expect(screen.getByText('Example search target')).toBeInTheDocument()
+ })
+
+ test('renders correctly without searchTarget', () => {
+ const noSearchTargetData: IApplicableDetails = {
+ isApplicable: true,
+ evidence: [
+ {
+ filePathEvidence: 'file/path/evidence',
+ codeEvidence: 'const example = "example";',
+ reason: 'Reason for applicability'
+ } as IEvidence
+ ]
+ }
+ render()
+ expect(screen.getByText('Contextual Analysis')).toBeInTheDocument()
+ expect(screen.getByText('Why is this CVE applicable?')).toBeInTheDocument()
+ expect(screen.getByText('file/path/evidence')).toBeInTheDocument()
+ expect(screen.getByText('const example = "example";')).toBeInTheDocument()
+ expect(screen.queryByText('What does the scanner check/look for?')).not.toBeInTheDocument()
+ })
+})
diff --git a/src/components/Page/Dependency/ApplicabilityEvidence.tsx b/src/components/UI/InformationTabs/ApplicabilityEvidence.tsx
similarity index 72%
rename from src/components/Page/Dependency/ApplicabilityEvidence.tsx
rename to src/components/UI/InformationTabs/ApplicabilityEvidence.tsx
index 51b82b5a..7c4e16d5 100644
--- a/src/components/Page/Dependency/ApplicabilityEvidence.tsx
+++ b/src/components/UI/InformationTabs/ApplicabilityEvidence.tsx
@@ -16,12 +16,13 @@ export default function ApplicabilityEvidence(props: Props): JSX.Element {
expanded
header={
- Applicability Evidence
+ Contextual Analysis
}
>
- {props.data.isApplicable && (
+ {/* If CVE is applicable */}
+ {props.data.isApplicable ? (
<>
Why is this CVE applicable?
@@ -37,6 +38,21 @@ export default function ApplicabilityEvidence(props: Props): JSX.Element {
>
+ ) : (
+ // If CVE is not applicable
+ <>
+
Why is this CVE not applicable?
+
+
+ {props.data.evidence?.map((evidence, i) => (
+
+
+
+ ))}
+
+
+
+ >
)}
{props.data.searchTarget && (
<>
diff --git a/src/components/UI/InformationTabs/InformationTabs.module.css b/src/components/UI/InformationTabs/InformationTabs.module.css
index a474f1a9..8a4d896c 100644
--- a/src/components/UI/InformationTabs/InformationTabs.module.css
+++ b/src/components/UI/InformationTabs/InformationTabs.module.css
@@ -1,7 +1,9 @@
.tabsContainer {
display: flex;
flex-direction: column;
- gap: 16px;
+ justify-content: space-between;
+ gap: 8px;
+ flex-wrap: wrap;
overflow: hidden;
}
@@ -9,8 +11,11 @@
display: flex;
flex-direction: column;
align-items: flex-start;
+ flex: 1;
+ text-align: center;
gap: 16px;
width: 100%;
+ cursor: pointer;
}
.alignCenterFlex {
diff --git a/src/components/UI/InformationTabs/InformationTabs.tsx b/src/components/UI/InformationTabs/InformationTabs.tsx
index 4ba171ac..bd6bb786 100644
--- a/src/components/UI/InformationTabs/InformationTabs.tsx
+++ b/src/components/UI/InformationTabs/InformationTabs.tsx
@@ -23,6 +23,7 @@ import { TreeNode } from '../../../model/treeNode'
import { toTreeNode } from '../../../utils/utils'
import WhatCanIDoTab from './WhatCanIDoTab'
import Markdown from '../Markdown/Markdown'
+import ApplicabilityEvidence from './ApplicabilityEvidence'
export const TABS = {
WHAT_CAN_I_DO: {
@@ -40,6 +41,10 @@ export const TABS = {
IMPACT_GRAPH: {
label: 'Impact Graph',
key: 'impact_graph'
+ },
+ CONTEXTUAL_ANALYSIS: {
+ label: 'Contextual Analysis',
+ key: 'contextual_analysis'
}
}
export const LABELS = {
@@ -138,6 +143,12 @@ function InformationTabs(props: Props): JSX.Element {
const showMoreInformationTab =
props.tabs.includes(TABS.MORE_INFORMATION.key) && (props.data as ISastPage).description
+ const pageTypeDependency = props.data as IDependencyPage
+ const showApplicabilityEvidence =
+ pageTypeDependency.cve?.applicableData?.evidence ??
+ pageTypeDependency.cve?.applicableData?.searchTarget
+ const showContextualAnalysisTab =
+ showApplicabilityEvidence && props.tabs.includes(TABS.CONTEXTUAL_ANALYSIS.key)
return (
@@ -154,6 +165,13 @@ function InformationTabs(props: Props): JSX.Element {
label={TABS.WHAT_CAN_I_DO.label}
/>
)}
+ {showContextualAnalysisTab && (
+
+ )}
{showCveInformationTab && (
)}
+ {showContextualAnalysisTab && (
+
+ {pageTypeDependency.cve?.applicableData && showApplicabilityEvidence && (
+
+ )}
+
+ )}
{showMoreInformationTab && (