Skip to content

Commit 049fec2

Browse files
rushk014xingzhang-suse
authored andcommitted
feat(images): Replace mock data implementation using storage.sbombastic.rancher.io.vulnerabilityreport objects
1 parent cd48360 commit 049fec2

File tree

7 files changed

+109
-53
lines changed

7 files changed

+109
-53
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"@kubernetes/client-node": "^1.3.0",
1010
"@rancher/components": "^0.3.0-alpha.1",
1111
"@rancher/shell": "3.0.5-rc.8",
12+
"file-saver": "^2.0.5",
1213
"vue": "^3.5.17",
1314
"vue-router": "^4.5.0",
1415
"vuex": "^4.1.0"

pkg/sbombastic-image-vulnerability-scanner/components/common/AmountBarBySeverity.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<div class="badge" :class="badgeColor('high', cveAmount.high)">{{ cveAmount.high }}</div>
1313
<div class="badge" :class="badgeColor('medium', cveAmount.medium)">{{ cveAmount.medium }}</div>
1414
<div class="badge" :class="badgeColor('low', cveAmount.low)">{{ cveAmount.low }}</div>
15-
<div class="badge" :class="badgeColor('none', cveAmount.none)">{{ cveAmount.none }}</div>
15+
<div class="badge" :class="badgeColor('unknown', cveAmount.unknown)">{{ cveAmount.unknown }}</div>
1616
</div>
1717
</div>
1818
</template>
@@ -44,13 +44,13 @@
4444
},
4545
computed: {
4646
pecentages() {
47-
let total = this.cveAmount.critical + this.cveAmount.high + this.cveAmount.medium + this.cveAmount.low + this.cveAmount.none;
47+
let total = this.cveAmount.critical + this.cveAmount.high + this.cveAmount.medium + this.cveAmount.low + this.cveAmount.unknown;
4848
return [
4949
this.cveAmount.critical * 100 / total,
5050
this.cveAmount.high * 100 / total,
51-
this.cveAmount.medium * 100 / total,
51+
this.cveAmount.medium * 100 / total,
5252
this.cveAmount.low * 100 / total,
53-
this.cveAmount.none * 100 / total,
53+
this.cveAmount.unknown * 100 / total,
5454
];
5555
}
5656
}
@@ -98,7 +98,7 @@
9898
background-color: #FDD835;
9999
color: rgba(255, 255, 255, 0.90);
100100
}
101-
.badge.none {
101+
.badge.unknown {
102102
background-color: #E0E0E0;
103103
color: #717179;
104104
}

pkg/sbombastic-image-vulnerability-scanner/config/table-headers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export const IMAGE_LIST_TABLE = [
164164
"spec.scanResult.high",
165165
"spec.scanResult.medium",
166166
"spec.scanResult.low",
167-
"spec.scanResult.none",
167+
"spec.scanResult.unknown",
168168
],
169169
width: 300,
170170
},

pkg/sbombastic-image-vulnerability-scanner/l10n/en-us.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ imageScanner:
130130
registry: Registry
131131
buttons:
132132
downloadCustomReport: Download custom report
133+
downloadSbom: Download SBOM
134+
downloadCsv: Image detail report (CSV)
135+
downloadJson: Vulnerability report (JSON)
133136
listTable:
134137
checkbox:
135138
groupByRepo: Group by repository

pkg/sbombastic-image-vulnerability-scanner/pages/c/_cluster/sbombastic-image-vulnerability-scanner/ImageOverview.vue

Lines changed: 88 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div class="page">
3-
<div class="header-section">
3+
<div class="header-section mb-20">
44
<div class="title">
55
{{ t("imageScanner.images.title") }}
66
</div>
@@ -10,6 +10,7 @@
1010
:options="filterCveOptions"
1111
:close-on-select="true"
1212
:multiple="false"
13+
disabled
1314
@selecting="changeCveFilter"
1415
/>
1516
</div>
@@ -19,6 +20,7 @@
1920
:options="filterImageOptions"
2021
:close-on-select="true"
2122
:multiple="false"
23+
disabled
2224
@selecting="changeImageFilter"
2325
/>
2426
</div>
@@ -34,22 +36,19 @@
3436
</button>
3537
</div>
3638
</div>
37-
<div class="summary-section">
39+
<!-- <div class="summary-section">
3840
<TopRiskyImagesChart v-if="preprocessedDataset.topRiskyImages" :topRiskyImages="preprocessedDataset.topRiskyImages"/>
3941
<ImageRiskAssessment v-if="preprocessedDataset.chartData" :chartData="preprocessedDataset.chartData" :filterFn="filterBySeverity"/>
40-
</div>
42+
</div> -->
4143
<SortableTable
42-
:has-advanced-filtering="false"
44+
:headers="isGrouped ? REPO_BASED_TABLE : IMAGE_LIST_TABLE"
4345
:namespaced="false"
44-
:row-actions="false"
46+
:row-actions="!isGrouped"
4547
:table-actions="true"
46-
:force-update-live-and-delayed="0"
47-
:use-query-params-for-simple-filtering="true"
4848
:sub-expandable="isGrouped"
4949
:sub-rows="isGrouped"
5050
:sub-expand-column="isGrouped"
51-
:rows="isGrouped ? preprocessedDataset.rowsByRepo : preprocessedDataset.preprocessedImages"
52-
:headers="isGrouped ? REPO_BASED_TABLE : IMAGE_LIST_TABLE"
51+
:rows="isGrouped ? preprocessedDataset.rowsByRepo : rows"
5352
:key-field="'id'"
5453
@selection="onSelectionChange"
5554
>
@@ -82,12 +81,15 @@
8281
:rows="row.images"
8382
:headers="REPO_BASED_IMAGE_LIST_TABLE"
8483
:search="false"
85-
:row-actions="false"
84+
:row-actions="true"
8685
:table-actions="false"
8786
/>
8887
</td>
8988
</tr>
9089
</template>
90+
<template #row-actions="{ row }">
91+
<ActionMenu :resource="row" :custom-actions="customActions" />
92+
</template>
9193
</SortableTable>
9294
</div>
9395

@@ -99,11 +101,14 @@
99101
import LabeledSelect from "@shell/components/form/LabeledSelect";
100102
import DownloadCustomReport from "@pkg/components/common/DownloadCustomReport";
101103
import TopRiskyImagesChart from "@pkg/components/TopRiskyImagesChart";
102-
import ImageRiskAssessment from "@pkg/components/ImageRiskAssessment"
103-
import { images } from "@pkg/data/sbombastic.rancher.io.image";
104+
import ImageRiskAssessment from "@pkg/components/ImageRiskAssessment";
105+
import ActionMenu from '@shell/components/ActionMenuShell.vue';
104106
import { IMAGE_LIST_TABLE, REPO_BASED_TABLE, REPO_BASED_IMAGE_LIST_TABLE } from "@pkg/config/table-headers";
105107
import { Checkbox } from '@components/Form/Checkbox';
106-
import { filter } from "lodash";
108+
import { RESOURCE } from "@pkg/types";
109+
import { saveAs } from 'file-saver';
110+
111+
107112
export default {
108113
name: 'imageOverview',
109114
components: {
@@ -113,6 +118,7 @@ import { filter } from "lodash";
113118
SortableTable,
114119
DownloadCustomReport,
115120
Checkbox,
121+
ActionMenu
116122
},
117123
data() {
118124
const filterCveOptions = [
@@ -140,7 +146,7 @@ import { filter } from "lodash";
140146
}
141147
];
142148
return {
143-
rows: images,
149+
rows: [],
144150
REPO_BASED_TABLE: REPO_BASED_TABLE,
145151
IMAGE_LIST_TABLE: IMAGE_LIST_TABLE,
146152
REPO_BASED_IMAGE_LIST_TABLE: REPO_BASED_IMAGE_LIST_TABLE,
@@ -158,14 +164,59 @@ import { filter } from "lodash";
158164
selectedRegistry: "Any",
159165
}
160166
},
161-
167+
computed: {
168+
customActions() {
169+
const downloadSbom = {
170+
action: 'downloadSbom',
171+
label: this.t('imageScanner.images.buttons.downloadSbom'),
172+
icon: 'icon-download',
173+
enabled: true,
174+
bulkable: false,
175+
invoke: (_, res) => {
176+
this.downloadSbom(res);
177+
}
178+
};
179+
const downloadCsv = {
180+
action: 'downloadCsv',
181+
label: this.t('imageScanner.images.buttons.downloadCsv'),
182+
icon: 'icon-download',
183+
enabled: true,
184+
bulkable: false,
185+
invoke: async ({}, res = []) => {}
186+
};
187+
const downloadJson = {
188+
action: 'downloadJson',
189+
label: this.t('imageScanner.images.buttons.downloadJson'),
190+
icon: 'icon-download',
191+
enabled: true,
192+
bulkable: false,
193+
invoke: async ({}, res = []) => {}
194+
};
195+
return [
196+
downloadSbom,
197+
{divider: true},
198+
downloadCsv,
199+
downloadJson
200+
];
201+
}
202+
},
162203
async fetch() {
163-
this.preprocessedDataset = this.preprocessData(this.rows);
204+
await this.$store.dispatch('cluster/findAll', { type: RESOURCE.VULNERABILITY_REPORT });
205+
const vulReportCRD = this.$store.getters['cluster/all']?.(RESOURCE.VULNERABILITY_REPORT);
206+
this.preprocessData(vulReportCRD);
207+
this.preprocessedDataset = this.preprocessData(vulReportCRD);
164208
this.preprocessedImagesBak = _.cloneDeep(this.preprocessedDataset.preprocessedImages);
165209
console.log("this.preprocessedDataset", this.preprocessedDataset)
166210
},
167-
168211
methods: {
212+
async downloadSbom(res) {
213+
const target = (res && res.length ? res[0] : null);
214+
console.log("target", target);
215+
const sbom = await this.$store.dispatch('cluster/find', { type: RESOURCE.SBOM, id: target.id });
216+
const spdxString = JSON.stringify(sbom.spdx, null, 2);
217+
const sbomBlob = new Blob([spdxString], { type: 'application/json;charset=utf-8' });
218+
saveAs(sbomBlob, `${sbom.metadata.name}-sbom.spdx.json`);
219+
},
169220
applyFilters() {
170221
let filtered = _.cloneDeep(this.preprocessedImagesBak);
171222
if (this.selectedImageFilter.value === "excludeBaseImages" || this.selectedImageFilter === "excludeBaseImages") {
@@ -197,18 +248,28 @@ import { filter } from "lodash";
197248
onSelectionChange(selected) {
198249
this.selectedRows = selected || [];
199250
},
200-
preprocessData(images) {
201-
console.log("images", images);
202-
const severityKeys = ['critical', 'high', 'medium', 'low', 'none'];
203-
const chartData = {};
251+
preprocessData(vulReportCRD) {
252+
this.rows = [];
253+
vulReportCRD.forEach(report => {
254+
this.rows.push({
255+
id: report.id,
256+
metadata: {
257+
name: `${report.imageMetadata.registry}:${report.imageMetadata.tag}`
258+
},
259+
spec: {
260+
isBaseImage: true,
261+
hasAffectedPackages: false,
262+
repository: report.imageMetadata.repository,
263+
registry: report.imageMetadata.registryURI,
264+
scanResult: report.report.summary,
265+
}
266+
});
267+
});
268+
const severityKeys = ['critical', 'high', 'medium', 'low', 'unknown'];
204269
const repoMap = new Map();
205270
const preprocessedImages = [];
206271
207-
for (const key of severityKeys) {
208-
chartData[key] = 0;
209-
}
210-
211-
const topRiskyImages = images.map(image => {
272+
this.rows.forEach(image => {
212273
let repoRec = {};
213274
let imageSeverity = "";
214275
const mapKey = `${image.spec.repository},${image.spec.registry}`;
@@ -246,9 +307,6 @@ import { filter } from "lodash";
246307
}
247308
repoMap.set(mapKey, repoRec);
248309
}
249-
for (const key of severityKeys) {
250-
chartData[key] += imageSeverity === key ? 1 : 0;
251-
}
252310
preprocessedImages.push({
253311
...image,
254312
severity: imageSeverity || "none",
@@ -257,27 +315,16 @@ import { filter } from "lodash";
257315
imageName: image.metadata.name,
258316
cveCnt: image.spec.scanResult,
259317
}
260-
}).sort((a, b) => {
261-
for (const key of severityKeys) {
262-
const diff = (b.cveCnt[key] || 0) - (a.cveCnt[key] || 0);
263-
if (diff !== 0) return diff;
264-
}
265-
return 0;
266-
}).slice(0, 5);
318+
});
267319
return {
268320
preprocessedImages,
269-
topRiskyImages,
270-
chartData,
271321
rowsByRepo: Array.from(repoMap.values())
272322
};
273323
},
274324
updateData(event) {
275325
console.log("isGrouped", this.isGrouped);
276326
},
277327
},
278-
279-
computed: {
280-
},
281328
}
282329
283330
</script>

pkg/sbombastic-image-vulnerability-scanner/types/sbombastic-image-vulnerability-scanner.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ export const SBOMBASTIC = {
33
CONTROLLER: "sbombastic",
44
SERVICE: "sbombastic-service",
55
SCHEMA: "sbombastic.rancher.io.registry",
6-
}
6+
};
77
export const SBOMBASTIC_REPOS = {
8-
CHARTS: 'https://charts.sbombastic.io',
9-
CHARTS_REPO: 'https://github.com/sbombastic/helm-charts',
10-
CHARTS_REPO_GIT: 'https://github.com/sbombastic/helm-charts.git',
11-
CHARTS_REPO_NAME: 'sbombastic-charts',
8+
CHARTS: "https://charts.sbombastic.io",
9+
CHARTS_REPO: "https://github.com/sbombastic/helm-charts",
10+
CHARTS_REPO_GIT: "https://github.com/sbombastic/helm-charts.git",
11+
CHARTS_REPO_NAME: "sbombastic-charts",
1212
};
1313
export const RESOURCE = {
1414
REGISTRY: "sbombastic.rancher.io.registry",
@@ -31,4 +31,4 @@ export interface MetadataProperty {
3131
label?: string;
3232
value?: string;
3333
tags?: string[];
34-
}
34+
}

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8319,6 +8319,11 @@ [email protected]:
83198319
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.2.tgz#06d6e728a9ea2df2cce2f8d9e84dfcdc338ec17a"
83208320
integrity sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw==
83218321

8322+
file-saver@^2.0.5:
8323+
version "2.0.5"
8324+
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
8325+
integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
8326+
83228327
filelist@^1.0.4:
83238328
version "1.0.4"
83248329
resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"

0 commit comments

Comments
 (0)