Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,11 @@ function DeploymentPageVulnerabilities({
const managedColumnState = useManagedColumns(tableId, defaultColumns);

const isEpssProbabilityColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');
const isOriginColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');

const columnConfig = overrideManagedColumns(managedColumnState.columns, {
epssProbability: hideColumnIf(!isEpssProbabilityColumnEnabled),
origin: hideColumnIf(!isOriginColumnEnabled),
});

// Keep searchFilterConfigWithFeatureFlagDependency for ROX_SCANNER_V4 also Advisory.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,15 @@ function ImagePageVulnerabilities({

const isNvdCvssColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');
const isEpssProbabilityColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');
const isOriginColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');

const managedColumnState = useManagedColumns(tableId, defaultColumns);

const columnConfig = overrideManagedColumns(managedColumnState.columns, {
cveSelection: hideColumnIf(!canSelectRows),
nvdCvss: hideColumnIf(!isNvdCvssColumnEnabled),
epssProbability: hideColumnIf(!isEpssProbabilityColumnEnabled),
origin: hideColumnIf(!isOriginColumnEnabled),
requestDetails: hideColumnIf(vulnerabilityState === 'OBSERVED'),
rowActions: hideColumnIf(createTableActions === undefined),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { VulnerabilityState } from 'types/cve.proto';
import CvssFormatted from 'Components/CvssFormatted';

import AdvisoryLinkOrText from '../../components/AdvisoryLinkOrText';
import { getOriginDisplayName } from '../../utils/vulnerabilityUtils';
import PendingExceptionLabel from '../../components/PendingExceptionLabel';
import ImageNameLink from '../components/ImageNameLink';
import {
Expand Down Expand Up @@ -37,6 +38,7 @@ export const deploymentComponentVulnerabilitiesFragment = gql`
cvss
scoreVersion
fixedByVersion
origin
advisory {
name
link
Expand Down Expand Up @@ -68,8 +70,10 @@ function DeploymentComponentVulnerabilitiesTable({
}: DeploymentComponentVulnerabilitiesTableProps) {
const { isFeatureFlagEnabled } = useFeatureFlags();
const isAdvisoryColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');
const isOriginColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');

const colSpanForDockerfileLayer = 8 + (isAdvisoryColumnEnabled ? 1 : 0);
const colSpanForDockerfileLayer =
8 + (isAdvisoryColumnEnabled ? 1 : 0) + (isOriginColumnEnabled ? 1 : 0);

const { sortOption, getSortParams } = useTableSort({ sortFields, defaultSortOption });
const componentVulns = images.flatMap(({ imageMetadataContext, componentVulnerabilities }) =>
Expand All @@ -89,6 +93,7 @@ function DeploymentComponentVulnerabilitiesTable({
<Th>CVE fixed in</Th>
{isAdvisoryColumnEnabled && <Th>Advisory</Th>}
<Th>Source</Th>
{isOriginColumnEnabled && <Th>CVE origin</Th>}
<Th>Location</Th>
</Tr>
</Thead>
Expand All @@ -101,6 +106,7 @@ function DeploymentComponentVulnerabilitiesTable({
cvss,
scoreVersion,
fixedByVersion,
origin,
advisory,
location,
source,
Expand Down Expand Up @@ -161,6 +167,9 @@ function DeploymentComponentVulnerabilitiesTable({
</Td>
)}
<Td dataLabel="Source">{source}</Td>
{isOriginColumnEnabled && (
<Td dataLabel="CVE origin">{getOriginDisplayName(origin)}</Td>
)}
<Td dataLabel="Location">
<ComponentLocation location={location} source={source} />
</Td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ExpandableRowContent, Table, Tbody, Td, Th, Thead, Tr } from '@patternf
import { gql } from '@apollo/client';

import useFeatureFlags from 'hooks/useFeatureFlags';
import useMetadata from 'hooks/useMetadata';
import useSet from 'hooks/useSet';
import type { UseURLSortResult } from 'hooks/useURLSort';
import VulnerabilitySeverityIconText from 'Components/PatternFly/IconText/VulnerabilitySeverityIconText';
Expand All @@ -27,7 +28,7 @@ import DeploymentComponentVulnerabilitiesTable, {
} from './DeploymentComponentVulnerabilitiesTable';
import PartialCVEDataAlert from '../../components/PartialCVEDataAlert';
import useWorkloadCveViewContext from '../hooks/useWorkloadCveViewContext';
import { infoForEpssProbability } from './infoForTh';
import { getInfoForCveOrigin, infoForEpssProbability } from './infoForTh';
import { formatEpssProbabilityAsPercent } from './table.utils';
import type { FormattedDeploymentVulnerability } from './table.utils';

Expand Down Expand Up @@ -63,6 +64,10 @@ export const defaultColumns = {
title: 'Affected components',
isShownByDefault: true,
},
origin: {
title: 'CVE origin',
isShownByDefault: true,
},
firstDiscovered: {
title: 'First discovered',
isShownByDefault: true,
Expand Down Expand Up @@ -120,6 +125,7 @@ function DeploymentVulnerabilitiesTable({
tableConfig,
}: DeploymentVulnerabilitiesTableProps) {
const { isFeatureFlagEnabled } = useFeatureFlags();
const { version } = useMetadata();
const { urlBuilder } = useWorkloadCveViewContext();
const getVisibilityClass = generateVisibilityForColumns(tableConfig);
const hiddenColumnCount = getHiddenColumnCount(tableConfig);
Expand Down Expand Up @@ -156,6 +162,12 @@ function DeploymentVulnerabilitiesTable({
Affected components
{isFiltered && <DynamicColumnIcon />}
</Th>
<Th
className={getVisibilityClass('origin')}
info={getInfoForCveOrigin(version, 'deployment')}
>
CVE origin
</Th>
<Th className={getVisibilityClass('firstDiscovered')}>First discovered</Th>
<Th className={getVisibilityClass('publishedOn')}>Published</Th>
</Tr>
Expand All @@ -175,6 +187,7 @@ function DeploymentVulnerabilitiesTable({
severity,
summary,
isFixable,
origin,
images,
affectedComponentsText,
discoveredAtImage,
Expand Down Expand Up @@ -274,6 +287,12 @@ function DeploymentVulnerabilitiesTable({
>
{affectedComponentsText}
</Td>
<Td
className={getVisibilityClass('origin')}
dataLabel="CVE origin"
>
{origin}
</Td>
<Td
className={getVisibilityClass('firstDiscovered')}
modifier="nowrap"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import { gql } from '@apollo/client';

import useFeatureFlags from 'hooks/useFeatureFlags';
import useTableSort from 'hooks/useTableSort';
import VulnerabilitySeverityIconText from 'Components/PatternFly/IconText/VulnerabilitySeverityIconText';
import CvssFormatted from 'Components/CvssFormatted';

import AdvisoryLinkOrText from '../../components/AdvisoryLinkOrText';
import { getOriginDisplayName } from '../../utils/vulnerabilityUtils';
import {
flattenImageComponentVulns,
imageMetadataContextFragment,
Expand All @@ -29,7 +32,10 @@ export const imageComponentVulnerabilitiesFragment = gql`
inBaseImageLayer
imageVulnerabilities(query: $query) {
severity
cvss
scoreVersion
fixedByVersion
origin
advisory {
name
link
Expand All @@ -54,10 +60,14 @@ function ImageComponentVulnerabilitiesTable({
}: ImageComponentVulnerabilitiesTableProps) {
const { isFeatureFlagEnabled } = useFeatureFlags();
const isAdvisoryColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');
const isOriginColumnEnabled = isFeatureFlagEnabled('ROX_SCANNER_V4');
const isLayerTypeColumnEnabled = isFeatureFlagEnabled('ROX_BASE_IMAGE_DETECTION');

const colSpanForDockerfileLayer =
5 + (isAdvisoryColumnEnabled ? 1 : 0) + (isLayerTypeColumnEnabled ? 1 : 0);
7 +
(isAdvisoryColumnEnabled ? 1 : 0) +
(isOriginColumnEnabled ? 1 : 0) +
(isLayerTypeColumnEnabled ? 1 : 0);

const { sortOption, getSortParams } = useTableSort({ sortFields, defaultSortOption });
const componentVulns = flattenImageComponentVulns(
Expand All @@ -72,9 +82,12 @@ function ImageComponentVulnerabilitiesTable({
<Tr>
<Th sort={getSortParams('Component')}>Component</Th>
<Th>Version</Th>
<Th>CVE severity</Th>
<Th>CVSS</Th>
<Th>CVE fixed in</Th>
{isAdvisoryColumnEnabled && <Th>Advisory</Th>}
<Th>Source</Th>
{isOriginColumnEnabled && <Th>CVE origin</Th>}
{isLayerTypeColumnEnabled && <Th>Layer type</Th>}
<Th>Location</Th>
</Tr>
Expand All @@ -84,7 +97,11 @@ function ImageComponentVulnerabilitiesTable({
image,
name,
version,
severity,
cvss,
scoreVersion,
fixedByVersion,
origin,
advisory,
location,
source,
Expand All @@ -105,6 +122,12 @@ function ImageComponentVulnerabilitiesTable({
<Tr>
<Td dataLabel="Component">{name}</Td>
<Td dataLabel="Version">{version}</Td>
<Td dataLabel="CVE severity" modifier="nowrap">
<VulnerabilitySeverityIconText severity={severity} />
</Td>
<Td dataLabel="CVSS" modifier="nowrap">
<CvssFormatted cvss={cvss} scoreVersion={scoreVersion} />
</Td>
<Td dataLabel="CVE fixed in" modifier="nowrap">
<FixedByVersion fixedByVersion={fixedByVersion} />
</Td>
Expand All @@ -114,6 +137,9 @@ function ImageComponentVulnerabilitiesTable({
</Td>
)}
<Td dataLabel="Source">{source}</Td>
{isOriginColumnEnabled && (
<Td dataLabel="CVE origin">{getOriginDisplayName(origin)}</Td>
)}
{isLayerTypeColumnEnabled && (
<Td dataLabel="Layer type">
<Label color={inBaseImageLayer ? 'blue' : 'grey'} isCompact>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type { IAction } from '@patternfly/react-table';
import { gql } from '@apollo/client';

import useFeatureFlags from 'hooks/useFeatureFlags';
import useMetadata from 'hooks/useMetadata';
import useSet from 'hooks/useSet';
import type { UseURLSortResult } from 'hooks/useURLSort';
import VulnerabilityFixableIconText from 'Components/PatternFly/IconText/VulnerabilityFixableIconText';
Expand All @@ -32,6 +33,7 @@ import type { TableUIState } from 'utils/getTableUIState';
import { generateVisibilityForColumns, getHiddenColumnCount } from 'hooks/useManagedColumns';
import type { ManagedColumns } from 'hooks/useManagedColumns';
import {
getAggregateOrigin,
getIsSomeVulnerabilityFixable,
hasKnownExploit,
hasKnownRansomwareCampaignUse,
Expand All @@ -53,7 +55,7 @@ import PendingExceptionLabel from '../../components/PendingExceptionLabel';
import ExceptionDetailsCell from '../components/ExceptionDetailsCell';
import PartialCVEDataAlert from '../../components/PartialCVEDataAlert';
import useWorkloadCveViewContext from '../hooks/useWorkloadCveViewContext';
import { infoForEpssProbability } from './infoForTh';
import { getInfoForCveOrigin, infoForEpssProbability } from './infoForTh';
import { formatEpssProbabilityAsPercent } from './table.utils';

export const tableId = 'WorkloadCvesImageVulnerabilitiesTable';
Expand Down Expand Up @@ -97,6 +99,10 @@ export const defaultColumns = {
title: 'Affected components',
isShownByDefault: true,
},
origin: {
title: 'CVE origin',
isShownByDefault: true,
},
firstDiscovered: {
title: 'First discovered',
isShownByDefault: true,
Expand Down Expand Up @@ -184,6 +190,7 @@ function ImageVulnerabilitiesTable({
tableConfig,
}: ImageVulnerabilitiesTableProps) {
const { isFeatureFlagEnabled } = useFeatureFlags();
const { version } = useMetadata();
const { urlBuilder } = useWorkloadCveViewContext();
const getVisibilityClass = generateVisibilityForColumns(tableConfig);
const hiddenColumnCount = getHiddenColumnCount(tableConfig);
Expand Down Expand Up @@ -228,6 +235,12 @@ function ImageVulnerabilitiesTable({
Affected components
{isFiltered && <DynamicColumnIcon />}
</Th>
<Th
className={getVisibilityClass('origin')}
info={getInfoForCveOrigin(version, 'image')}
>
CVE origin
</Th>
<Th className={getVisibilityClass('firstDiscovered')} modifier="nowrap">
First discovered
</Th>
Expand Down Expand Up @@ -271,6 +284,7 @@ function ImageVulnerabilitiesTable({
(imageComponent) => imageComponent.imageVulnerabilities
);
const isFixableInImage = getIsSomeVulnerabilityFixable(vulnerabilities);
const aggregateOrigin = getAggregateOrigin(vulnerabilities);
const epssProbability = cveBaseInfo?.epss?.epssProbability;

const labels: ReactNode[] = [];
Expand Down Expand Up @@ -391,6 +405,12 @@ function ImageVulnerabilitiesTable({
? imageComponents[0].name
: `${imageComponents.length} components`}
</Td>
<Td
className={getVisibilityClass('origin')}
dataLabel="CVE origin"
>
{aggregateOrigin}
</Td>
<Td
className={getVisibilityClass('firstDiscovered')}
dataLabel="First discovered"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ThProps } from '@patternfly/react-table';

import ExternalLink from 'Components/PatternFly/IconText/ExternalLink';
import PopoverBodyContent from 'Components/PopoverBodyContent';
import { getVersionedDocs } from 'utils/versioning';

export const infoForEpssProbability: ThProps['info'] = {
// ariaLabel for OutlinedQuestionCircleIcon
Expand Down Expand Up @@ -34,3 +35,43 @@ export const infoForEpssProbability: ThProps['info'] = {
/>
),
};

// The CVE origin popover links to versioned RHACS documentation, so it must be
// built with the current version rather than defined as a static object.
export function getInfoForCveOrigin(
version: string,
resourceType: 'image' | 'deployment'
): ThProps['info'] {
return {
ariaLabel: 'Information about CVE origin',
popover: (
<PopoverBodyContent
headerContent="CVE origin"
bodyContent={
<Flex direction={{ default: 'column' }}>
<FlexItem>
Where the CVE assessment comes from for components in this{' '}
{resourceType}. Values are supported OS vendors, OSV.dev, Other, or
Multiple when components differ.
</FlexItem>
<FlexItem>
For more information, see{' '}
<ExternalLink>
<a
href={getVersionedDocs(
version,
'operating/examine-images-for-vulnerabilities#supported-operating-systems_examine-images-for-vulnerabilities'
)}
>
rel="noopener noreferrer"
>
Supported operating systems (RHACS)
</a>
</ExternalLink>
</FlexItem>
</Flex>
}
/>
),
};
}
Loading
Loading