From 18f8fa45bb59af1351fff703ad2b8a5e5c80e80b Mon Sep 17 00:00:00 2001 From: Charmik Sheth Date: Mon, 6 Apr 2026 11:26:35 -0700 Subject: [PATCH 1/2] Update UI tests to work with FlattenImageData enabled --- .../workloadCves/multipleCvesForImageV2.json | 127 ++++++++++ .../workloadCves/WorkloadCves.helpers.js | 10 +- .../workloadCves/imageSingle.test.ts | 238 +++++++++--------- 3 files changed, 262 insertions(+), 113 deletions(-) create mode 100644 ui/apps/platform/cypress/fixtures/vulnerabilities/workloadCves/multipleCvesForImageV2.json diff --git a/ui/apps/platform/cypress/fixtures/vulnerabilities/workloadCves/multipleCvesForImageV2.json b/ui/apps/platform/cypress/fixtures/vulnerabilities/workloadCves/multipleCvesForImageV2.json new file mode 100644 index 0000000000000..5759793bd1ebd --- /dev/null +++ b/ui/apps/platform/cypress/fixtures/vulnerabilities/workloadCves/multipleCvesForImageV2.json @@ -0,0 +1,127 @@ +{ + "data": { + "imageV2": { + "id": "4c657931-d333-5cb8-8f0d-7e3836525ec7", + "digest": "sha256:abcxyz", + "name": { + "registry": "docker.io", + "remote": "cypress-test/image", + "tag": "v0.0.1", + "__typename": "ImageName" + }, + "metadata": { + "v1": { + "layers": [ + { + "instruction": "ADD", + "value": "file:abc123 in /", + "__typename": "ImageLayer" + } + ], + "__typename": "V1Metadata" + }, + "__typename": "ImageMetadata" + }, + "__typename": "ImageV2", + "imageVulnerabilityCount": 2, + "imageCVECountBySeverity": { + "unknown": { + "total": 0, + "fixable": 0, + "__typename": "ResourceCountByFixability" + }, + "low": { + "total": 0, + "fixable": 0, + "__typename": "ResourceCountByFixability" + }, + "moderate": { + "total": 0, + "fixable": 0, + "__typename": "ResourceCountByFixability" + }, + "important": { + "total": 2, + "fixable": 2, + "__typename": "ResourceCountByFixability" + }, + "critical": { + "total": 0, + "fixable": 0, + "__typename": "ResourceCountByFixability" + }, + "__typename": "ResourceCountByCVESeverity" + }, + "imageVulnerabilities": [ + { + "severity": "IMPORTANT_VULNERABILITY_SEVERITY", + "cve": "MOCK-2023-0464", + "summary": "This is a mocked CVE in a Cypress test", + "cvss": 7.5, + "scoreVersion": "V3", + "nvdCvss": 0, + "nvdScoreVersion": "UNKNOWN_VERSION", + "cveBaseInfo": { + "epss": null + }, + "discoveredAtImage": "2024-03-01T17:45:32.757812569Z", + "publishedOn": "2023-03-22T17:15:00Z", + "pendingExceptionCount": 0, + "imageComponents": [ + { + "name": "openssl", + "version": "3.0.8-r0", + "location": "", + "source": "OS", + "layerIndex": 0, + "imageVulnerabilities": [ + { + "severity": "IMPORTANT_VULNERABILITY_SEVERITY", + "fixedByVersion": "3.0.8-r1", + "pendingExceptionCount": 0, + "__typename": "ImageVulnerability" + } + ], + "__typename": "ImageComponent" + } + ], + "__typename": "ImageVulnerability" + }, + { + "severity": "IMPORTANT_VULNERABILITY_SEVERITY", + "cve": "MOCK-2023-5363", + "summary": "This is a mocked CVE in a Cypress test", + "cvss": 7.5, + "scoreVersion": "V3", + "nvdCvss": 0, + "nvdScoreVersion": "UNKNOWN_VERSION", + "cveBaseInfo": { + "epss": null + }, + "discoveredAtImage": "2024-03-01T17:45:32.757812569Z", + "publishedOn": "2023-10-25T18:17:00Z", + "pendingExceptionCount": 0, + "imageComponents": [ + { + "name": "openssl", + "version": "3.0.8-r0", + "location": "", + "source": "OS", + "layerIndex": 0, + "imageVulnerabilities": [ + { + "severity": "IMPORTANT_VULNERABILITY_SEVERITY", + "fixedByVersion": "3.0.12-r0", + "pendingExceptionCount": 0, + "__typename": "ImageVulnerability" + } + ], + "__typename": "ImageComponent" + } + ], + "__typename": "ImageVulnerability" + } + ] + } + } +} diff --git a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/WorkloadCves.helpers.js b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/WorkloadCves.helpers.js index d34c7be0a120b..7e7ce7aafa6ec 100644 --- a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/WorkloadCves.helpers.js +++ b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/WorkloadCves.helpers.js @@ -1,5 +1,6 @@ import { addDays, format } from 'date-fns'; import { getDescriptionListGroup } from '../../../helpers/formHelpers'; +import { hasFeatureFlag } from '../../../helpers/features'; import { getRouteMatcherMapForGraphQL, interactAndWaitForResponses, @@ -257,11 +258,18 @@ export function visitImageSinglePageWithMockedResponses() { imageDetailsOpname, cveListOpname, ]); + + // When FlattenImageData is enabled, the getCVEsForImage query uses imageV2(...) + // which returns data under the `imageV2` key instead of `image`. + const cveListFixture = hasFeatureFlag('ROX_FLATTEN_IMAGE_DATA') + ? 'vulnerabilities/workloadCves/multipleCvesForImageV2.json' + : 'vulnerabilities/workloadCves/multipleCvesForImage.json'; + const staticResponseMapForImageCves = { [imageDetailsOpname]: { fixture: 'vulnerabilities/workloadCves/imageWithMultipleCves.json', }, - [cveListOpname]: { fixture: 'vulnerabilities/workloadCves/multipleCvesForImage.json' }, + [cveListOpname]: { fixture: cveListFixture }, }; visitWorkloadCveOverview(); diff --git a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/imageSingle.test.ts b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/imageSingle.test.ts index f2c474d9bdfdf..ea7bcd01f7797 100644 --- a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/imageSingle.test.ts +++ b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/imageSingle.test.ts @@ -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, }, }; @@ -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) @@ -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]); @@ -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); }; } @@ -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 ), })) From bace8fd506f9695aa0a8dfb57e842425806782ff Mon Sep 17 00:00:00 2001 From: Charmik Sheth Date: Mon, 13 Apr 2026 15:24:38 -0700 Subject: [PATCH 2/2] Address comments Co-Authored-By: Claude Opus 4.6 --- .../workloadCves/multipleCvesForImageV2.json | 127 ------------------ .../workloadCves/WorkloadCves.helpers.js | 38 +++++- 2 files changed, 31 insertions(+), 134 deletions(-) delete mode 100644 ui/apps/platform/cypress/fixtures/vulnerabilities/workloadCves/multipleCvesForImageV2.json diff --git a/ui/apps/platform/cypress/fixtures/vulnerabilities/workloadCves/multipleCvesForImageV2.json b/ui/apps/platform/cypress/fixtures/vulnerabilities/workloadCves/multipleCvesForImageV2.json deleted file mode 100644 index 5759793bd1ebd..0000000000000 --- a/ui/apps/platform/cypress/fixtures/vulnerabilities/workloadCves/multipleCvesForImageV2.json +++ /dev/null @@ -1,127 +0,0 @@ -{ - "data": { - "imageV2": { - "id": "4c657931-d333-5cb8-8f0d-7e3836525ec7", - "digest": "sha256:abcxyz", - "name": { - "registry": "docker.io", - "remote": "cypress-test/image", - "tag": "v0.0.1", - "__typename": "ImageName" - }, - "metadata": { - "v1": { - "layers": [ - { - "instruction": "ADD", - "value": "file:abc123 in /", - "__typename": "ImageLayer" - } - ], - "__typename": "V1Metadata" - }, - "__typename": "ImageMetadata" - }, - "__typename": "ImageV2", - "imageVulnerabilityCount": 2, - "imageCVECountBySeverity": { - "unknown": { - "total": 0, - "fixable": 0, - "__typename": "ResourceCountByFixability" - }, - "low": { - "total": 0, - "fixable": 0, - "__typename": "ResourceCountByFixability" - }, - "moderate": { - "total": 0, - "fixable": 0, - "__typename": "ResourceCountByFixability" - }, - "important": { - "total": 2, - "fixable": 2, - "__typename": "ResourceCountByFixability" - }, - "critical": { - "total": 0, - "fixable": 0, - "__typename": "ResourceCountByFixability" - }, - "__typename": "ResourceCountByCVESeverity" - }, - "imageVulnerabilities": [ - { - "severity": "IMPORTANT_VULNERABILITY_SEVERITY", - "cve": "MOCK-2023-0464", - "summary": "This is a mocked CVE in a Cypress test", - "cvss": 7.5, - "scoreVersion": "V3", - "nvdCvss": 0, - "nvdScoreVersion": "UNKNOWN_VERSION", - "cveBaseInfo": { - "epss": null - }, - "discoveredAtImage": "2024-03-01T17:45:32.757812569Z", - "publishedOn": "2023-03-22T17:15:00Z", - "pendingExceptionCount": 0, - "imageComponents": [ - { - "name": "openssl", - "version": "3.0.8-r0", - "location": "", - "source": "OS", - "layerIndex": 0, - "imageVulnerabilities": [ - { - "severity": "IMPORTANT_VULNERABILITY_SEVERITY", - "fixedByVersion": "3.0.8-r1", - "pendingExceptionCount": 0, - "__typename": "ImageVulnerability" - } - ], - "__typename": "ImageComponent" - } - ], - "__typename": "ImageVulnerability" - }, - { - "severity": "IMPORTANT_VULNERABILITY_SEVERITY", - "cve": "MOCK-2023-5363", - "summary": "This is a mocked CVE in a Cypress test", - "cvss": 7.5, - "scoreVersion": "V3", - "nvdCvss": 0, - "nvdScoreVersion": "UNKNOWN_VERSION", - "cveBaseInfo": { - "epss": null - }, - "discoveredAtImage": "2024-03-01T17:45:32.757812569Z", - "publishedOn": "2023-10-25T18:17:00Z", - "pendingExceptionCount": 0, - "imageComponents": [ - { - "name": "openssl", - "version": "3.0.8-r0", - "location": "", - "source": "OS", - "layerIndex": 0, - "imageVulnerabilities": [ - { - "severity": "IMPORTANT_VULNERABILITY_SEVERITY", - "fixedByVersion": "3.0.12-r0", - "pendingExceptionCount": 0, - "__typename": "ImageVulnerability" - } - ], - "__typename": "ImageComponent" - } - ], - "__typename": "ImageVulnerability" - } - ] - } - } -} diff --git a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/WorkloadCves.helpers.js b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/WorkloadCves.helpers.js index 7e7ce7aafa6ec..d1ba62451daa1 100644 --- a/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/WorkloadCves.helpers.js +++ b/ui/apps/platform/cypress/integration/vulnerabilities/workloadCves/WorkloadCves.helpers.js @@ -243,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 @@ -259,19 +278,24 @@ export function visitImageSinglePageWithMockedResponses() { cveListOpname, ]); - // When FlattenImageData is enabled, the getCVEsForImage query uses imageV2(...) - // which returns data under the `imageV2` key instead of `image`. - const cveListFixture = hasFeatureFlag('ROX_FLATTEN_IMAGE_DATA') - ? 'vulnerabilities/workloadCves/multipleCvesForImageV2.json' - : 'vulnerabilities/workloadCves/multipleCvesForImage.json'; - const staticResponseMapForImageCves = { [imageDetailsOpname]: { fixture: 'vulnerabilities/workloadCves/imageWithMultipleCves.json', }, - [cveListOpname]: { fixture: cveListFixture }, }; + // 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(