diff --git a/src/components/SysdigVMPipelineFetchComponent/SysdigVMPipelineFetchComponent.test.tsx b/src/components/SysdigVMPipelineFetchComponent/SysdigVMPipelineFetchComponent.test.tsx
index dde4119..eff5547 100644
--- a/src/components/SysdigVMPipelineFetchComponent/SysdigVMPipelineFetchComponent.test.tsx
+++ b/src/components/SysdigVMPipelineFetchComponent/SysdigVMPipelineFetchComponent.test.tsx
@@ -41,6 +41,15 @@ const mockEntityWithoutAnnotations = {
},
};
+const mockPipelineScanV1 = {
+ resultId: 'result-pipeline-123',
+ imageId: 'sha256:deadbeef1234',
+ pullString: 'ghcr.io/sysdiglabs/sample-app:latest',
+ policyEvaluationResult: 'failed',
+ createdAt: new Date('2024-01-22T08:51:46Z'),
+ vulnTotalBySeverity: { critical: 1, high: 3, medium: 7, low: 2, negligible: 0 },
+};
+
const mockSysdigApi = {
fetchVulnRuntime: jest.fn().mockResolvedValue({ data: [] }),
fetchVulnRegistry: jest.fn().mockResolvedValue({ data: [] }),
@@ -92,4 +101,48 @@ describe('SysdigVMPipelineFetchComponent', () => {
const message = await screen.findByText(/missing annotation/i);
expect(message).toBeInTheDocument();
});
+
+ it('renders rows using v1 policyEvaluationResult field (without s)', async () => {
+ const apiWithData = {
+ ...mockSysdigApi,
+ fetchVulnPipeline: jest.fn().mockResolvedValue({ data: [mockPipelineScanV1] }),
+ };
+
+ await renderInTestApp(
+
+
+
+
+
+ );
+
+ expect(await screen.findByText('ghcr.io/sysdiglabs/sample-app:latest')).toBeInTheDocument();
+ expect(screen.getByText('failed')).toBeInTheDocument();
+ });
+
+ it('filters out rows with null policyEvaluationResult', async () => {
+ const scanWithNullPolicy = { ...mockPipelineScanV1, policyEvaluationResult: null as any };
+ const apiWithData = {
+ ...mockSysdigApi,
+ fetchVulnPipeline: jest.fn().mockResolvedValue({ data: [scanWithNullPolicy, mockPipelineScanV1] }),
+ };
+
+ await renderInTestApp(
+
+
+
+
+
+ );
+
+ // Only the scan with a non-null policyEvaluationResult should appear
+ const rows = await screen.findAllByText('ghcr.io/sysdiglabs/sample-app:latest');
+ expect(rows).toHaveLength(1);
+ });
});
diff --git a/src/components/SysdigVMPipelineFetchComponent/SysdigVMPipelineFetchComponent.tsx b/src/components/SysdigVMPipelineFetchComponent/SysdigVMPipelineFetchComponent.tsx
index 966e7b4..d2e0b2e 100644
--- a/src/components/SysdigVMPipelineFetchComponent/SysdigVMPipelineFetchComponent.tsx
+++ b/src/components/SysdigVMPipelineFetchComponent/SysdigVMPipelineFetchComponent.tsx
@@ -35,8 +35,8 @@ import { sysdigApiRef } from '../../api';
type PipelineScan = {
createdAt: Date,
imageId: string,
- mainAssetName: string,
- policyEvaluationsResult: string,
+ pullString: string,
+ policyEvaluationResult: string,
resultId: string,
vulnTotalBySeverity: {
critical: number,
@@ -58,8 +58,8 @@ type DenseTableProps = {
{
"createdAt": "2019-08-24T14:15:22Z",
"imageId": "string",
- "mainAssetName": "string",
- "policyEvaluationsResult": "passed",
+ "pullString": "string",
+ "policyEvaluationResult": "passed",
"resultId": "string",
"vulnTotalBySeverity": {
"critical": 0,
@@ -82,12 +82,12 @@ export const DenseTable = ({ pipelineScans, title }: DenseTableProps) => {
// { title: 'URL', field: "url", width: "10%" },
];
- const data = pipelineScans.filter(scan => { return scan.policyEvaluationsResult !== null && scan.policyEvaluationsResult !== '' })
+ const data = pipelineScans.filter(scan => { return scan.policyEvaluationResult !== null && scan.policyEvaluationResult !== '' })
.flatMap(scan => {
return {
- policyEvalStatus: getStatusColorSpan(scan.policyEvaluationsResult),
+ policyEvalStatus: getStatusColorSpan(scan.policyEvaluationResult),
imageId: {scan.imageId},
- asset: scan.mainAssetName,
+ asset: scan.pullString,
vulns: getChips(scan.vulnTotalBySeverity),
// convert image.lastEvaluatedAt to a date string
// lastEvaluatedAt: getDate(image.lastEvaluatedAt * 1000),
diff --git a/src/components/SysdigVMRegistryFetchComponent/SysdigVMRegistryFetchComponent.test.tsx b/src/components/SysdigVMRegistryFetchComponent/SysdigVMRegistryFetchComponent.test.tsx
index 52dbf08..11b0d3f 100644
--- a/src/components/SysdigVMRegistryFetchComponent/SysdigVMRegistryFetchComponent.test.tsx
+++ b/src/components/SysdigVMRegistryFetchComponent/SysdigVMRegistryFetchComponent.test.tsx
@@ -42,6 +42,13 @@ const mockEntityWithoutAnnotations = {
},
};
+const mockRegistryScanV1 = {
+ resultId: 'result-registry-456',
+ imageId: 'sha256:abc123def456',
+ pullString: 'harbor.example.com/library/nginx:1.25',
+ vulnTotalBySeverity: { critical: 0, high: 2, medium: 5, low: 1, negligible: 3 },
+};
+
const mockSysdigApi = {
fetchVulnRuntime: jest.fn().mockResolvedValue({ data: [] }),
fetchVulnRegistry: jest.fn().mockResolvedValue({ data: [] }),
@@ -93,4 +100,24 @@ describe('SysdigVMRegistryFetchComponent', () => {
const message = await screen.findByText(/missing annotation/i);
expect(message).toBeInTheDocument();
});
+
+ it('renders rows using v1 pullString field (not mainAssetName)', async () => {
+ const apiWithData = {
+ ...mockSysdigApi,
+ fetchVulnRegistry: jest.fn().mockResolvedValue({ data: [mockRegistryScanV1] }),
+ };
+
+ await renderInTestApp(
+
+
+
+
+
+ );
+
+ expect(await screen.findByText('harbor.example.com/library/nginx:1.25')).toBeInTheDocument();
+ });
});
diff --git a/src/components/SysdigVMRegistryFetchComponent/SysdigVMRegistryFetchComponent.tsx b/src/components/SysdigVMRegistryFetchComponent/SysdigVMRegistryFetchComponent.tsx
index ce0fbb6..d975b8c 100644
--- a/src/components/SysdigVMRegistryFetchComponent/SysdigVMRegistryFetchComponent.tsx
+++ b/src/components/SysdigVMRegistryFetchComponent/SysdigVMRegistryFetchComponent.tsx
@@ -34,7 +34,7 @@ import {
import { sysdigApiRef } from '../../api';
type RegistryScan = {
- mainAssetName: string,
+ pullString: string,
imageId: string,
resultId: string,
vulnTotalBySeverity: {
@@ -57,7 +57,7 @@ type DenseTableProps = {
{
"createdAt": "2019-08-24T14:15:22Z",
"imageId": "string",
- "mainAssetName": "string",
+ "pullString": "string",
"resultId": "string",
"vulnTotalBySeverity": {
"critical": 0,
@@ -81,7 +81,7 @@ export const DenseTable = ({ registryScans, title }: DenseTableProps) => {
.flatMap(scan => {
return {
imageId: {scan.imageId},
- asset: scan.mainAssetName,
+ asset: scan.pullString,
severity: getChips(scan.vulnTotalBySeverity)
};
});
diff --git a/src/components/SysdigVMRuntimeFetchComponent/SysdigVMRuntimeFetchComponent.test.tsx b/src/components/SysdigVMRuntimeFetchComponent/SysdigVMRuntimeFetchComponent.test.tsx
index d91e0c1..03d9e51 100644
--- a/src/components/SysdigVMRuntimeFetchComponent/SysdigVMRuntimeFetchComponent.test.tsx
+++ b/src/components/SysdigVMRuntimeFetchComponent/SysdigVMRuntimeFetchComponent.test.tsx
@@ -42,6 +42,25 @@ const mockEntityWithoutAnnotations = {
},
};
+const mockRuntimeScanV1 = {
+ resultId: 'result-abc123',
+ resourceId: 'sha256:a1b2c3d4e5f6',
+ mainAssetName: 'nginx:latest',
+ policyEvaluationResult: 'failed',
+ isRiskSpotlightEnabled: true,
+ sbomId: 'sbom-xyz',
+ scope: {
+ 'asset.type': 'workload',
+ 'kubernetes.cluster.name': 'test-cluster',
+ 'kubernetes.namespace.name': 'test-namespace',
+ 'kubernetes.workload.name': 'nginx',
+ 'kubernetes.workload.type': 'deployment',
+ 'kubernetes.pod.container.name': 'nginx',
+ },
+ vulnTotalBySeverity: { critical: 2, high: 5, medium: 10, low: 3, negligible: 1 },
+ runningVulnTotalBySeverity: { critical: 1, high: 2, medium: 4, low: 1, negligible: 0 },
+};
+
const mockSysdigApi = {
fetchVulnRuntime: jest.fn().mockResolvedValue({ data: [] }),
fetchVulnRegistry: jest.fn().mockResolvedValue({ data: [] }),
@@ -93,4 +112,48 @@ describe('SysdigVMRuntimeFetchComponent', () => {
const message = await screen.findByText(/missing annotation/i);
expect(message).toBeInTheDocument();
});
+
+ it('renders rows using v1 policyEvaluationResult field (without s)', async () => {
+ const apiWithData = {
+ ...mockSysdigApi,
+ fetchVulnRuntime: jest.fn().mockResolvedValue({ data: [mockRuntimeScanV1] }),
+ };
+
+ await renderInTestApp(
+
+
+
+
+
+ );
+
+ expect(await screen.findByText('nginx:latest')).toBeInTheDocument();
+ expect(screen.getByText('failed')).toBeInTheDocument();
+ });
+
+ it('filters out rows with null policyEvaluationResult', async () => {
+ const scanWithNullPolicy = { ...mockRuntimeScanV1, policyEvaluationResult: null as any };
+ const apiWithData = {
+ ...mockSysdigApi,
+ fetchVulnRuntime: jest.fn().mockResolvedValue({ data: [scanWithNullPolicy, mockRuntimeScanV1] }),
+ };
+
+ await renderInTestApp(
+
+
+
+
+
+ );
+
+ // Only the scan with a non-null policyEvaluationResult should appear (1 row = 1 asset name)
+ const rows = await screen.findAllByText('nginx:latest');
+ expect(rows).toHaveLength(1);
+ });
});
diff --git a/src/components/SysdigVMRuntimeFetchComponent/SysdigVMRuntimeFetchComponent.tsx b/src/components/SysdigVMRuntimeFetchComponent/SysdigVMRuntimeFetchComponent.tsx
index 686b45f..6eafd69 100644
--- a/src/components/SysdigVMRuntimeFetchComponent/SysdigVMRuntimeFetchComponent.tsx
+++ b/src/components/SysdigVMRuntimeFetchComponent/SysdigVMRuntimeFetchComponent.tsx
@@ -42,7 +42,8 @@ import { sysdigApiRef } from '../../api';
type RuntimeScan = {
isRiskSpotlightEnabled: boolean,
mainAssetName: string,
- policyEvaluationsResult: string,
+ policyEvaluationResult: string,
+ resourceId: string,
resultId: string,
runningVulnTotalBySeverity: {
critical: number,
@@ -120,10 +121,10 @@ export const DenseTable = ({ runtimeScans, title }: DenseTableProps) => {
// { title: 'URL', field: "url", width: "10%" },
];
- const data = runtimeScans.filter(scan => { return scan.policyEvaluationsResult !== null && scan.policyEvaluationsResult !== '' })
+ const data = runtimeScans.filter(scan => { return scan.policyEvaluationResult !== null && scan.policyEvaluationResult !== '' })
.flatMap(scan => {
return {
- policyEvalStatus: getStatusColorSpan(scan.policyEvaluationsResult),
+ policyEvalStatus: getStatusColorSpan(scan.policyEvaluationResult),
asset: scan.mainAssetName,
// scope: JSON.stringify(scan.scope),
severity: getChips(scan.vulnTotalBySeverity),
diff --git a/src/infra/api/SysdigApiClient.test.ts b/src/infra/api/SysdigApiClient.test.ts
index bef53d9..a1c1243 100644
--- a/src/infra/api/SysdigApiClient.test.ts
+++ b/src/infra/api/SysdigApiClient.test.ts
@@ -4,7 +4,7 @@ import { ConfigApi, FetchApi } from "@backstage/core-plugin-api";
import { rest } from "msw";
import { setupServer } from "msw/node";
import { SysdigApiClient } from "./SysdigApiClient";
-import { API_PROXY_BASE_PATH, API_VULN_RUNTIME } from "../../lib";
+import { API_PROXY_BASE_PATH, API_VULN_RUNTIME, API_VULN_REGISTRY, API_VULN_PIPELINE } from "../../lib";
describe("SysdigApiClient", () => {
const configApi: ConfigApi = new ConfigReader({
@@ -46,4 +46,13 @@ describe("SysdigApiClient", () => {
undefined,
);
});
+
+ it("should use v1 endpoint paths (not v1beta1)", () => {
+ expect(API_VULN_RUNTIME).toMatch(/\/v1\//);
+ expect(API_VULN_REGISTRY).toMatch(/\/v1\//);
+ expect(API_VULN_PIPELINE).toMatch(/\/v1\//);
+ expect(API_VULN_RUNTIME).not.toMatch(/v1beta1/);
+ expect(API_VULN_REGISTRY).not.toMatch(/v1beta1/);
+ expect(API_VULN_PIPELINE).not.toMatch(/v1beta1/);
+ });
});
diff --git a/src/lib/endpoints.ts b/src/lib/endpoints.ts
index b9308dc..08f0107 100644
--- a/src/lib/endpoints.ts
+++ b/src/lib/endpoints.ts
@@ -8,13 +8,13 @@ export const API_PROXY_BASE_PATH = "/api/proxy/sysdig";
*/
// API Endpoint for Vulnerability Management at Runtime
-export const API_VULN_RUNTIME = "/secure/vulnerability/v1beta1/runtime-results";
+export const API_VULN_RUNTIME = "/secure/vulnerability/v1/runtime-results";
// API Endpoint for Vulnerability Management at Registry
-export const API_VULN_REGISTRY = "/secure/vulnerability/v1beta1/registry-results";
+export const API_VULN_REGISTRY = "/secure/vulnerability/v1/registry-results";
// API Endpoint for Vulnerability Management at Pipeline
-export const API_VULN_PIPELINE = "/secure/vulnerability/v1beta1/pipeline-results";
+export const API_VULN_PIPELINE = "/secure/vulnerability/v1/pipeline-results";
// API Endpoint for Inventory (Posture)
export const API_INVENTORY = "/api/cspm/v1/inventory/resources";
@@ -54,4 +54,4 @@ export function getBacklink(endpoint: string | undefined, backlink: string | und
}
return backlink_base + backlink_section;
-}
\ No newline at end of file
+}