diff --git a/src/lib/singleview/components/ProductVulnerabilities.svelte b/src/lib/singleview/components/ProductVulnerabilities.svelte index 014cc3a..2bacca4 100644 --- a/src/lib/singleview/components/ProductVulnerabilities.svelte +++ b/src/lib/singleview/components/ProductVulnerabilities.svelte @@ -10,17 +10,21 @@ -{#if $appStore.doc} +{#if isDocumentASecurityAdvisory}

Vulnerabilities overview

{#if productLines.length > 0} diff --git a/src/lib/singleview/docmodel/docmodel.ts b/src/lib/singleview/docmodel/docmodel.ts index a098af8..fcea503 100644 --- a/src/lib/singleview/docmodel/docmodel.ts +++ b/src/lib/singleview/docmodel/docmodel.ts @@ -139,7 +139,7 @@ const convertToDocModel = (csafDoc: any): DocModel => { trackingVersion: getTrackingVersion(csafDoc), revisionHistory: [], lastUpdate: getLastUpdate(csafDoc), - vulnerabilities: [], + productVulnerabilities: [], isDocPresent: checkDocumentPresent(csafDoc), isTrackingPresent: checkTrackingPresent(csafDoc), isDistributionPresent: checkDistributionPresent(csafDoc), diff --git a/src/lib/singleview/docmodel/docmodeltypes.ts b/src/lib/singleview/docmodel/docmodeltypes.ts index 8bafd3c..ce5cc35 100644 --- a/src/lib/singleview/docmodel/docmodeltypes.ts +++ b/src/lib/singleview/docmodel/docmodeltypes.ts @@ -48,6 +48,12 @@ export const Status = { } as const; export type StatusKeys = (typeof Status)[keyof typeof Status]; +export const DocumentCategory = { + CSAF_SECURITY_ADVISORY: "csaf_security_advisory", + CSAF_BASE: "csaf_base", + CSAF_VEX: "csaf_vex" +} as const; + export type Publisher = { category: string; name: string; @@ -73,7 +79,7 @@ export type DocModel = { publisher: Publisher; trackingVersion: string; revisionHistory: RevisionHistoryEntry[]; - vulnerabilities: Array>; + productVulnerabilities: Array>; isDocPresent: boolean; isTrackingPresent: boolean; isDistributionPresent: boolean; diff --git a/src/lib/singleview/productvulnerabilities/productvulnerabilities.test.ts b/src/lib/singleview/productvulnerabilities/productvulnerabilities.test.ts index 995d01e..2e3663f 100644 --- a/src/lib/singleview/productvulnerabilities/productvulnerabilities.test.ts +++ b/src/lib/singleview/productvulnerabilities/productvulnerabilities.test.ts @@ -12,7 +12,7 @@ import { extractVulnerabilities, generateProductVulnerabilities } from "./productvulnerabilities"; -import { ProductStatusSymbol } from "./productvulnerabilitiestypes"; +import { ProductStatusSymbol, type Vulnerability } from "./productvulnerabilitiestypes"; const emptyObject = {}; @@ -264,48 +264,48 @@ describe("Productvulnerabilities test", () => { describe("Productvulnerabilities test", () => { it("Vulnerability: parses empty object", () => { - const result = extractVulnerabilities(emptyObject); - expect(result.length).toBe(0); + const { vulnerabilities } = extractVulnerabilities(emptyObject); + expect(vulnerabilities.length).toBe(0); }); }); describe("Productvulnerabilities test", () => { it("Vulnerability: parses no vulnerabilities", () => { - const result = extractVulnerabilities(noVulnerabilities); - expect(result.length).toBe(0); + const { vulnerabilities } = extractVulnerabilities(noVulnerabilities); + expect(vulnerabilities.length).toBe(0); }); }); describe("Productvulnerabilities test", () => { it("Vulnerability: parses vulnerability without cve", () => { - const result = extractVulnerabilities(vulnerability_wo_CVE); - expect(result.length).toBe(1); + const { vulnerabilities } = extractVulnerabilities(vulnerability_wo_CVE); + expect(vulnerabilities.length).toBe(0); }); }); describe("Productvulnerabilities test", () => { it("Vulnerability: parses vulnerability with empty product_status", () => { - const result = extractVulnerabilities(vulnerability_empty_product_status); - expect(result.length).toBe(1); + const { vulnerabilities } = extractVulnerabilities(vulnerability_empty_product_status); + expect(vulnerabilities.length).toBe(1); }); }); describe("Productvulnerabilities test", () => { it("Vulnerability: parses vulnerability with empty known_affected", () => { - const result = extractVulnerabilities(vulnerability_known_affected_empty); - expect(result.length).toBe(1); - expect(Object.keys(result[0].known_affected).length).toBe(0); + const { vulnerabilities } = extractVulnerabilities(vulnerability_known_affected_empty); + expect(vulnerabilities.length).toBe(1); + expect(Object.keys(vulnerabilities[0].known_affected!).length).toBe(0); }); }); describe("Productvulnerabilities test", () => { it("Vulnerability: parses vulnerability with filled known_affected", () => { - const result = extractVulnerabilities(vulnerability_known_affected_filled); - const value = result[0]; - expect(result.length).toBe(1); - expect(Object.keys(value.known_affected).length).toBe(2); - expect(value.known_affected["123"]).toBe("123"); - expect(value.known_affected["456"]).toBe("456"); + const { vulnerabilities } = extractVulnerabilities(vulnerability_known_affected_filled); + const value = vulnerabilities[0]; + expect(vulnerabilities.length).toBe(1); + expect(Object.keys(value.known_affected!).length).toBe(2); + expect(value.known_affected!["123"]).toBe("123"); + expect(value.known_affected!["456"]).toBe("456"); }); }); diff --git a/src/lib/singleview/productvulnerabilities/productvulnerabilities.ts b/src/lib/singleview/productvulnerabilities/productvulnerabilities.ts index e8d2ad3..f41b5d1 100644 --- a/src/lib/singleview/productvulnerabilities/productvulnerabilities.ts +++ b/src/lib/singleview/productvulnerabilities/productvulnerabilities.ts @@ -12,12 +12,16 @@ import { type Product, type Relationship, type ProductStatus_t, - type ProductStatus_t_Key + type ProductStatus_t_Key, + type VulnerabilitesExtractionResult } from "./productvulnerabilitiestypes"; const generateProductVulnerabilities = (jsonDocument: any) => { - const products = extractProducts(jsonDocument); - let vulnerabilities = extractVulnerabilities(jsonDocument); + let products = extractProducts(jsonDocument); + let { vulnerabilities, relevantProducts } = extractVulnerabilities(jsonDocument); + products = products.filter((product: Product) => { + return relevantProducts[product.product_id]; + }); vulnerabilities.sort((vuln1: Vulnerability, vuln2: Vulnerability) => { if (vuln1.cve < vuln2.cve) return -1; if (vuln1.cve > vuln2.cve) return 1; @@ -119,43 +123,57 @@ const generateDictFrom = (productStatus: ProductStatus_t, section: ProductStatus }, {}); }; -const extractVulnerabilities = (jsonDocument: any): Vulnerability[] => { +const extractVulnerabilities = (jsonDocument: any): VulnerabilitesExtractionResult => { + const extractionResult: VulnerabilitesExtractionResult = { + vulnerabilities: [], + relevantProducts: {} + }; if (!jsonDocument.vulnerabilities) { - return []; + return extractionResult; } - return jsonDocument.vulnerabilities.reduce((acc: Vulnerability[], vulnerability: any) => { - if (!vulnerability.cve) { - return acc; - } - const result: Vulnerability = { - cve: vulnerability.cve - }; - if (vulnerability.product_status) { - if (vulnerability.product_status.known_affected) { - result.known_affected = generateDictFrom(vulnerability.product_status, "known_affected"); + const vulnerabilities = jsonDocument.vulnerabilities.reduce( + (acc: Vulnerability[], vulnerability: any) => { + if (!vulnerability.cve) { + return acc; } - if (vulnerability.product_status.fixed) { - result.fixed = generateDictFrom(vulnerability.product_status, "fixed"); + const result: Vulnerability = { + cve: vulnerability.cve + }; + if (vulnerability.product_status) { + if (vulnerability.product_status.known_affected) { + result.known_affected = generateDictFrom(vulnerability.product_status, "known_affected"); + Object.assign(extractionResult.relevantProducts, result.known_affected); + } + if (vulnerability.product_status.fixed) { + result.fixed = generateDictFrom(vulnerability.product_status, "fixed"); + Object.assign(extractionResult.relevantProducts, result.fixed); + } + if (vulnerability.product_status.under_investigation) { + result.under_investigation = generateDictFrom( + vulnerability.product_status, + "under_investigation" + ); + Object.assign(extractionResult.relevantProducts, result.under_investigation); + } + if (vulnerability.product_status.known_not_affected) { + result.known_not_affected = generateDictFrom( + vulnerability.product_status, + "known_not_affected" + ); + Object.assign(extractionResult.relevantProducts, result.known_not_affected); + } + if (vulnerability.product_status.recommended) { + result.recommended = generateDictFrom(vulnerability.product_status, "recommended"); + Object.assign(extractionResult.relevantProducts, result.recommended); + } } - if (vulnerability.product_status.under_investigation) { - result.under_investigation = generateDictFrom( - vulnerability.product_status, - "under_investigation" - ); - } - if (vulnerability.product_status.known_not_affected) { - result.known_not_affected = generateDictFrom( - vulnerability.product_status, - "known_not_affected" - ); - } - if (vulnerability.product_status.recommended) { - result.recommended = generateDictFrom(vulnerability.product_status, "recommended"); - } - } - acc.push(result); - return acc; - }, []); + acc.push(result); + return acc; + }, + [] + ); + extractionResult.vulnerabilities = vulnerabilities; + return extractionResult; }; export { extractProducts, extractVulnerabilities, generateProductVulnerabilities }; diff --git a/src/lib/singleview/productvulnerabilities/productvulnerabilitiestypes.ts b/src/lib/singleview/productvulnerabilities/productvulnerabilitiestypes.ts index e542af4..3f0072a 100644 --- a/src/lib/singleview/productvulnerabilities/productvulnerabilitiestypes.ts +++ b/src/lib/singleview/productvulnerabilities/productvulnerabilitiestypes.ts @@ -59,3 +59,8 @@ export type Vulnerability = { known_not_affected?: StringObject; recommended?: StringObject; }; + +export type VulnerabilitesExtractionResult = { + vulnerabilities: Vulnerability[]; + relevantProducts: StringObject; +};