Skip to content
Open
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
@@ -1,5 +1,6 @@
import { addDays, format } from 'date-fns';
import { getDescriptionListGroup } from '../../../helpers/formHelpers';
import { hasFeatureFlag } from '../../../helpers/features';
import {
getRouteMatcherMapForGraphQL,
interactAndWaitForResponses,
Expand Down Expand Up @@ -242,6 +243,25 @@ export function verifySelectedCvesInModal(cveNames) {
});
}

/**
* Transform a v1 image CVE response to a v2 response format.
* The v2 response uses `imageV2` as the root key, `ImageV2` as the typename,
* a UUID-style `id`, and an additional `digest` field.
*/
function toImageV2Response(v1Response) {
const { image } = v1Response.data;
return {
data: {
imageV2: {
...image,
id: '4c657931-d333-5cb8-8f0d-7e3836525ec7',
digest: image.id,
__typename: 'ImageV2',
},
},
};
}

/**
* Visits an image single page via the workload CVE overview page and mocks the responses for the image
* details and CVE list. We need to mock the CVE list to ensure that multiple CVEs are present for the image. We
Expand All @@ -257,13 +277,25 @@ export function visitImageSinglePageWithMockedResponses() {
imageDetailsOpname,
cveListOpname,
]);

const staticResponseMapForImageCves = {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we remove that new .json file and use a helper function to transform the v1 data, this is how I'd imagine it:

  1. Add the helper function at the top
function toImageV2Response(v1Response) {
      const { image } = v1Response.data;
      return {
          data: {
              imageV2: {
                  ...image,
                  id: '4c657931-d333-5cb8-8f0d-7e3836525ec7',
                  digest: image.id,
                  __typename: 'ImageV2',
              },
          },
      };
  }
  1. Update the conditional
if (hasFeatureFlag('ROX_FLATTEN_IMAGE_DATA')) {
      cy.fixture('vulnerabilities/workloadCves/multipleCvesForImage.json').then((v1Response) => {
          staticResponseMapForImageCves[cveListOpname] = { body: toImageV2Response(v1Response) };
      });
  } else {
      staticResponseMapForImageCves[cveListOpname] = {
          fixture: 'vulnerabilities/workloadCves/multipleCvesForImage.json',
      };
  }

[imageDetailsOpname]: {
fixture: 'vulnerabilities/workloadCves/imageWithMultipleCves.json',
},
[cveListOpname]: { fixture: 'vulnerabilities/workloadCves/multipleCvesForImage.json' },
};

// When FlattenImageData is enabled, the getCVEsForImage query uses imageV2(...)
// which returns data under the `imageV2` key instead of `image`.
if (hasFeatureFlag('ROX_FLATTEN_IMAGE_DATA')) {
cy.fixture('vulnerabilities/workloadCves/multipleCvesForImage.json').then((v1Response) => {
staticResponseMapForImageCves[cveListOpname] = { body: toImageV2Response(v1Response) };
});
} else {
staticResponseMapForImageCves[cveListOpname] = {
fixture: 'vulnerabilities/workloadCves/multipleCvesForImage.json',
};
}

visitWorkloadCveOverview();

interactAndWaitForResponses(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,128 +157,139 @@ describe('Workload CVE Image Single page', () => {
// see: https://issues.redhat.com/browse/ROX-24254
// https://github.com/stackrox/stackrox/pull/6156
it('should display nested component data correctly when processed via apollo client', () => {
const isFlattenImageData = hasFeatureFlag('ROX_FLATTEN_IMAGE_DATA');
const imageRootKey = isFlattenImageData ? 'imageV2' : 'image';

const opname = 'getCVEsForImage';
const routeMatcherMap = getRouteMatcherMapForGraphQL([opname]);
const body = {
data: {
image: {
id: 'sha256:010fec71f42f4b5e65f3f56f10af94a7c05c9c271a9bbc3026684ba170698cb5',
name: {
registry: 'quay.io',
remote: 'openshift-release-dev/ocp-v4.0-art-dev',
tag: '',
__typename: 'ImageName',
},
metadata: {
v1: {
layers: [

const imageData = {
id: 'sha256:010fec71f42f4b5e65f3f56f10af94a7c05c9c271a9bbc3026684ba170698cb5',
...(isFlattenImageData
? {
digest: 'sha256:010fec71f42f4b5e65f3f56f10af94a7c05c9c271a9bbc3026684ba170698cb5',
}
: {}),
name: {
registry: 'quay.io',
remote: 'openshift-release-dev/ocp-v4.0-art-dev',
tag: '',
__typename: 'ImageName',
},
metadata: {
v1: {
layers: [
{
instruction: 'ADD',
value: 'file:091e888311e2628528312ffc60e27702fe04b23f8e4c95b456c16a967cdd89e0 in /',
__typename: 'ImageLayer',
},
],
__typename: 'V1Metadata',
},
__typename: 'ImageMetadata',
},
__typename: isFlattenImageData ? 'ImageV2' : 'Image',
imageCVECountBySeverity: {
unknown: {
total: 0,
fixable: 0,
__typename: 'ResourceCountByFixability',
},
low: {
total: 0,
fixable: 0,
__typename: 'ResourceCountByFixability',
},
moderate: {
total: 1,
fixable: 1,
__typename: 'ResourceCountByFixability',
},
important: {
total: 0,
fixable: 0,
__typename: 'ResourceCountByFixability',
},
critical: {
total: 0,
fixable: 0,
__typename: 'ResourceCountByFixability',
},
__typename: 'ResourceCountByCVESeverity',
},
imageVulnerabilities: [
{
severity: 'MODERATE_VULNERABILITY_SEVERITY',
cve: '[CYPRESS-MOCKED] CVE-2023-44487',
summary: 'HTTP/2 Stream Cancellation Attack',
cvss: 5.300000190734863,
scoreVersion: 'V3',
discoveredAtImage: '2024-04-03T19:44:55.837891332Z',
pendingExceptionCount: 0,
imageComponents: [
{
name: 'golang.org/x/net',
version: 'v0.13.0',
location: 'usr/bin/cluster-samples-operator-watch',
source: 'GO',
layerIndex: 0,
imageVulnerabilities: [
{
instruction: 'ADD',
value: 'file:091e888311e2628528312ffc60e27702fe04b23f8e4c95b456c16a967cdd89e0 in /',
__typename: 'ImageLayer',
vulnerabilityId: 'CVE-2023-44487#rhel:9',
severity: 'MODERATE_VULNERABILITY_SEVERITY',
fixedByVersion: '0.17.0',
pendingExceptionCount: 0,
__typename: 'ImageVulnerability',
},
],
__typename: 'V1Metadata',
},
__typename: 'ImageMetadata',
},
__typename: 'Image',
imageCVECountBySeverity: {
unknown: {
total: 0,
fixable: 0,
__typename: 'ResourceCountByFixability',
},
low: {
total: 0,
fixable: 0,
__typename: 'ResourceCountByFixability',
},
moderate: {
total: 1,
fixable: 1,
__typename: 'ResourceCountByFixability',
__typename: 'ImageComponent',
},
important: {
total: 0,
fixable: 0,
__typename: 'ResourceCountByFixability',
},
critical: {
total: 0,
fixable: 0,
__typename: 'ResourceCountByFixability',
},
__typename: 'ResourceCountByCVESeverity',
},
imageVulnerabilities: [
{
severity: 'MODERATE_VULNERABILITY_SEVERITY',
cve: '[CYPRESS-MOCKED] CVE-2023-44487',
summary: 'HTTP/2 Stream Cancellation Attack',
cvss: 5.300000190734863,
scoreVersion: 'V3',
discoveredAtImage: '2024-04-03T19:44:55.837891332Z',
pendingExceptionCount: 0,
imageComponents: [
{
name: 'golang.org/x/net',
version: 'v0.13.0',
location: 'usr/bin/cluster-samples-operator-watch',
source: 'GO',
layerIndex: 0,
imageVulnerabilities: [
{
vulnerabilityId: 'CVE-2023-44487#rhel:9',
severity: 'MODERATE_VULNERABILITY_SEVERITY',
fixedByVersion: '0.17.0',
pendingExceptionCount: 0,
__typename: 'ImageVulnerability',
},
],
__typename: 'ImageComponent',
},
name: 'google.golang.org/grpc',
version: 'v1.54.0',
location: 'usr/bin/cluster-samples-operator-watch',
source: 'GO',
layerIndex: 0,
imageVulnerabilities: [
{
name: 'google.golang.org/grpc',
version: 'v1.54.0',
location: 'usr/bin/cluster-samples-operator-watch',
source: 'GO',
layerIndex: 0,
imageVulnerabilities: [
{
vulnerabilityId: 'CVE-2023-44487#rhel:9',
severity: 'MODERATE_VULNERABILITY_SEVERITY',
fixedByVersion: '1.56.3',
pendingExceptionCount: 0,
__typename: 'ImageVulnerability',
},
],
__typename: 'ImageComponent',
vulnerabilityId: 'CVE-2023-44487#rhel:9',
severity: 'MODERATE_VULNERABILITY_SEVERITY',
fixedByVersion: '1.56.3',
pendingExceptionCount: 0,
__typename: 'ImageVulnerability',
},
],
__typename: 'ImageComponent',
},
{
name: 'openshift4/ose-cluster-samples-rhel9-operator',
version: 'v4.15.0-202401261531.p0.gd546ec2.assembly.stream',
location:
'root/buildinfo/Dockerfile-openshift-ose-cluster-samples-rhel9-operator-v4.15.0-202401261531.p0.gd546ec2.assembly.stream',
source: 'OS',
layerIndex: 0,
imageVulnerabilities: [
{
name: 'openshift4/ose-cluster-samples-rhel9-operator',
version: 'v4.15.0-202401261531.p0.gd546ec2.assembly.stream',
location:
'root/buildinfo/Dockerfile-openshift-ose-cluster-samples-rhel9-operator-v4.15.0-202401261531.p0.gd546ec2.assembly.stream',
source: 'OS',
layerIndex: 0,
imageVulnerabilities: [
{
vulnerabilityId: 'CVE-2023-44487#rhel:9',
severity: 'MODERATE_VULNERABILITY_SEVERITY',
fixedByVersion:
'v4.15.0-202404031310.p0.gbf845b5.assembly.stream.el9',
pendingExceptionCount: 0,
__typename: 'ImageVulnerability',
},
],
__typename: 'ImageComponent',
vulnerabilityId: 'CVE-2023-44487#rhel:9',
severity: 'MODERATE_VULNERABILITY_SEVERITY',
fixedByVersion:
'v4.15.0-202404031310.p0.gbf845b5.assembly.stream.el9',
pendingExceptionCount: 0,
__typename: 'ImageVulnerability',
},
],
__typename: 'ImageVulnerability',
__typename: 'ImageComponent',
},
],
__typename: 'ImageVulnerability',
},
],
};

const body = {
data: {
[imageRootKey]: imageData,
},
};

Expand All @@ -295,7 +306,7 @@ describe('Workload CVE Image Single page', () => {
cy.get(vulnSelectors.expandRowButton).click();

const fixedInCellSelector = `table td[data-label="CVE fixed in"]`;
const components = body.data.image.imageVulnerabilities[0].imageComponents;
const components = imageData.imageVulnerabilities[0].imageComponents;

components.forEach((component, index) => {
cy.get(fixedInCellSelector)
Expand All @@ -306,6 +317,9 @@ describe('Workload CVE Image Single page', () => {

// See case 03985920 and ROX-27344 for more details
it('should receive consistent CVE counts when sorting and paginating the table', () => {
const isFlattenImageData = hasFeatureFlag('ROX_FLATTEN_IMAGE_DATA');
const imageRootKey = isFlattenImageData ? 'imageV2' : 'image';

const opname = 'getCVEsForImage';
const routeMatcherMap = getRouteMatcherMapForGraphQL([opname]);

Expand All @@ -314,9 +328,9 @@ describe('Workload CVE Image Single page', () => {
function createAssertion(initialCount: number, initialQuery: string) {
return function (interception) {
expect(interception.request.body.variables.query).to.equal(initialQuery);
expect(interception.response.body.data.image.imageVulnerabilityCount).to.equal(
initialCount
);
expect(
interception.response.body.data[imageRootKey].imageVulnerabilityCount
).to.equal(initialCount);
};
}

Expand All @@ -326,7 +340,7 @@ describe('Workload CVE Image Single page', () => {
waitForRequests()
.then(({ request, response }) => ({
assertCveCountsUnchanged: createAssertion(
response.body.data.image.imageVulnerabilityCount,
response.body.data[imageRootKey].imageVulnerabilityCount,
request.body.variables.query
),
}))
Expand Down
Loading