diff --git a/shared/spdx/convertSpdxToXlsx.ts b/shared/spdx/convertSpdxToXlsx.ts index 491c7a5..a82cfe7 100644 --- a/shared/spdx/convertSpdxToXlsx.ts +++ b/shared/spdx/convertSpdxToXlsx.ts @@ -210,6 +210,9 @@ export async function convertSpdxToXlsxAsync(spdx: IDocument): Promise { content: securityAdvisories .orderBy((vuln: ISecurityVulnerability) => getSeverityByName(vuln.advisory.severity).weight, false) .map((vuln: ISecurityVulnerability) => { + const packageSpdxId = packages?.find( + (p) => p.name == vuln.package.name && p.versionInfo == vuln.package.version, + )?.SPDXID; return { ghsaId: vuln.advisory.identifiers.find((i) => i.type == SecurityAdvisoryIdentifierType.Ghsa)?.value || '', cveId: vuln.advisory.identifiers.find((i) => i.type == SecurityAdvisoryIdentifierType.Cve)?.value || '', @@ -219,9 +222,11 @@ export async function convertSpdxToXlsxAsync(spdx: IDocument): Promise { fixAvailable: vuln.firstPatchedVersion ? 'Yes' : 'No', firstPatchedVersion: vuln.firstPatchedVersion, introducedThrough: - getPackageDependsOnChain(spdx, vuln.package.id) - .map((p) => p.name) - .join(' > ') || '', + (packageSpdxId && + getPackageDependsOnChain(spdx, packageSpdxId) + .map((p) => p.name) + .join(' > ')) || + '', severity: vuln.advisory.severity?.toPascalCase(), cvssScore: vuln.advisory.cvss?.score || '', cvssVector: vuln.advisory.cvss?.vectorString || '', diff --git a/ui/components/sbom/SpdxSecurityTableCard.tsx b/ui/components/sbom/SpdxSecurityTableCard.tsx index baa47e1..19b0142 100644 --- a/ui/components/sbom/SpdxSecurityTableCard.tsx +++ b/ui/components/sbom/SpdxSecurityTableCard.tsx @@ -15,6 +15,7 @@ import { TableCell, TwoLineTableCell, } from 'azure-devops-ui/Table'; +import { Tooltip } from 'azure-devops-ui/TooltipEx'; import { FILTER_CHANGE_EVENT, IFilter } from 'azure-devops-ui/Utilities/Filter'; import { ZeroData } from 'azure-devops-ui/ZeroData'; @@ -32,6 +33,7 @@ interface ISecurityAdvisoryTableItem { package: IPackage; vulnerableVersionRange: string; firstPatchedVersion: string; + introducedThrough: string[]; severity: ISeverity; cvssScore: number; cvssVector: string; @@ -84,6 +86,9 @@ export class SpdxSecurityTableCard extends React.Component { props.securityAdvisories ?.orderBy((vuln: ISecurityVulnerability) => getSeverityByName(vuln.advisory.severity).weight, false) ?.map((vuln: ISecurityVulnerability) => { + const packageSpdxId = props.document.packages?.find( + (p) => p.name == vuln.package.name && p.versionInfo == vuln.package.version, + )?.SPDXID; const cvssParts = vuln.advisory.cvss?.vectorString?.match(/^CVSS\:([\d]+\.[\d]+)\/(.*)$/i); return { ghsaId: vuln.advisory.identifiers.find((i) => i.type == SecurityAdvisoryIdentifierType.Ghsa)?.value || '', @@ -93,7 +98,8 @@ export class SpdxSecurityTableCard extends React.Component { vulnerableVersionRange: vuln.vulnerableVersionRange, fixAvailable: vuln.firstPatchedVersion ? 'Yes' : 'No', firstPatchedVersion: vuln.firstPatchedVersion, - introducedThrough: getPackageDependsOnChain(props.document, vuln.package.id).map((p) => p.name), + introducedThrough: + (packageSpdxId && getPackageDependsOnChain(props.document, packageSpdxId).map((p) => p.name)) || [], severity: getSeverityByName(vuln.advisory.severity), cvssScore: vuln.advisory.cvss?.score, cvssVector: cvssParts?.[2]?.trim() || '', @@ -410,7 +416,17 @@ function renderAdvisoryPackageCell( ariaRowIndex: rowIndex, columnIndex: columnIndex, tableColumn: tableColumn, - line1:
{tableItem.package?.name}
, + line1: ( + ')}\n > ${tableItem.package?.name}` + : 'Direct dependency' + } + > +
{tableItem.package?.name}
+
+ ), line2:
{tableItem.package?.version}
, }); }