Skip to content

Commit 9d7eabf

Browse files
rushk014xingzhang-suse
authored andcommitted
feat(images): Parse Registry CRD into Column filter options; Add CSV/JSON download methods
1 parent f1ba34a commit 9d7eabf

File tree

4 files changed

+84
-8
lines changed

4 files changed

+84
-8
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
"@rancher/components": "^0.3.0-alpha.1",
1111
"@rancher/shell": "3.0.5-rc.8",
1212
"file-saver": "^2.0.5",
13+
"flat": "^6.0.1",
14+
"papaparse": "^5.5.3",
1315
"vue": "^3.5.17",
1416
"vue-router": "^4.5.0",
1517
"vuex": "^4.1.0"

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ imageScanner:
275275
medium: Medium
276276
low: Low
277277
none: None
278+
unknown: Unknown
279+
suppressed: Suppressed
278280
status:
279281
pending: Pending
280282
scheduled: Scheduled

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

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@
152152
import { Checkbox } from '@components/Form/Checkbox';
153153
import { RESOURCE } from "@pkg/types";
154154
import { saveAs } from 'file-saver';
155+
import Papa from 'papaparse';
156+
import { flatten } from 'flat';
155157
156158
export default {
157159
name: 'imageOverview',
@@ -189,6 +191,36 @@
189191
label: this.t('imageScanner.images.filters.image.includeBaseImages')
190192
}
191193
];
194+
const severityOptions = [
195+
{
196+
value: "any",
197+
label: this.t('imageScanner.imageDetails.any')
198+
},
199+
{
200+
value: "critical",
201+
label: this.t('imageScanner.enum.cve.critical')
202+
},
203+
{
204+
value: "high",
205+
label: this.t('imageScanner.enum.cve.high')
206+
},
207+
{
208+
value: "medium",
209+
label: this.t('imageScanner.enum.cve.medium')
210+
},
211+
{
212+
value: "low",
213+
label: this.t('imageScanner.enum.cve.low')
214+
},
215+
{
216+
value: "unknown",
217+
label: this.t('imageScanner.enum.cve.unknown')
218+
},
219+
{
220+
value: "suppressed",
221+
label: this.t('imageScanner.enum.cve.suppressed')
222+
}
223+
]
192224
return {
193225
rows: [],
194226
REPO_BASED_TABLE: REPO_BASED_TABLE,
@@ -200,14 +232,16 @@
200232
preprocessedImagesBak: [],
201233
filterCveOptions,
202234
filterImageOptions,
235+
severityOptions,
203236
selectedCveFilter: filterCveOptions[0],
204237
selectedImageFilter: filterImageOptions[0],
205238
filters: {
206239
imageSearch: '',
207-
severitySearch: 'any',
208-
repositorySearch: 'any',
209-
registrySearch: 'any',
240+
severitySearch: severityOptions[0],
241+
repositorySearch: 'Any',
242+
registrySearch: 'Any',
210243
},
244+
registryCrds: [],
211245
}
212246
},
213247
computed: {
@@ -228,41 +262,69 @@
228262
icon: 'icon-download',
229263
enabled: true,
230264
bulkable: false,
231-
invoke: async ({}, res = []) => {}
265+
invoke: (_, res) => {
266+
this.downloadCsv(res);
267+
}
232268
};
233269
const downloadJson = {
234270
action: 'downloadJson',
235271
label: this.t('imageScanner.images.buttons.downloadJson'),
236272
icon: 'icon-download',
237273
enabled: true,
238274
bulkable: false,
239-
invoke: async ({}, res = []) => {}
275+
invoke: (_, res) => {
276+
this.downloadJson(res);
277+
}
240278
};
241279
return [
242280
downloadSbom,
243281
{divider: true},
244282
downloadCsv,
245283
downloadJson
246284
];
285+
},
286+
repositoryOptions() {
287+
const repoSet = new Set();
288+
this.registryCrds.forEach(reg => {
289+
if (reg.spec.repositories && reg.spec.repositories.length) {
290+
reg.spec.repositories.forEach(repo => repoSet.add(repo));
291+
}
292+
});
293+
return ["Any", ...repoSet];
294+
},
295+
registryOptions() {
296+
return ["Any", ...this.registryCrds.map(reg => `${reg.metadata.namespace}/${reg.metadata.name}`)];
247297
}
248298
},
249299
async fetch() {
250-
await this.$store.dispatch('cluster/findAll', { type: RESOURCE.VULNERABILITY_REPORT });
251-
const vulReportCRD = this.$store.getters['cluster/all']?.(RESOURCE.VULNERABILITY_REPORT);
300+
const vulReportCRD = await this.$store.dispatch('cluster/findAll', { type: RESOURCE.VULNERABILITY_REPORT });
252301
this.preprocessData(vulReportCRD);
253302
this.preprocessedDataset = this.preprocessData(vulReportCRD);
254303
this.preprocessedImagesBak = _.cloneDeep(this.preprocessedDataset.preprocessedImages);
255304
console.log("this.preprocessedDataset", this.preprocessedDataset)
305+
this.registryCrds = await this.$store.dispatch('cluster/findAll', { type: RESOURCE.REGISTRY });
256306
},
257307
methods: {
258308
async downloadSbom(res) {
259309
const target = (res && res.length ? res[0] : null);
260-
console.log("target", target);
261310
const sbom = await this.$store.dispatch('cluster/find', { type: RESOURCE.SBOM, id: target.id });
262311
const spdxString = JSON.stringify(sbom.spdx, null, 2);
263312
const sbomBlob = new Blob([spdxString], { type: 'application/json;charset=utf-8' });
264313
saveAs(sbomBlob, `${sbom.metadata.name}-sbom.spdx.json`);
265314
},
315+
async downloadJson(res) {
316+
const target = (res && res.length ? res[0] : null);
317+
const vulReport = await this.$store.dispatch('cluster/find', { type: RESOURCE.VULNERABILITY_REPORT, id: target.id });
318+
const jsonBlob = new Blob([JSON.stringify(vulReport, null, 2)], { type: 'application/json;charset=utf-8' });
319+
saveAs(jsonBlob, `${target.id}-vul-report.json`);
320+
},
321+
async downloadCsv(res) {
322+
const target = (res && res.length ? res[0] : null);
323+
const vulReport = await this.$store.dispatch('cluster/find', { type: RESOURCE.VULNERABILITY_REPORT, id: target.id });
324+
const csvString = JSON.stringify(vulReport.report.results[0].vulnerabilities.map(vul => flatten(vul)));
325+
const csvBlob = new Blob([Papa.unparse(csvString)], { type: 'text/csv;charset=utf-8' });
326+
saveAs(csvBlob, `${target.id}-image-detail-report.csv`);
327+
},
266328
applyFilters() {
267329
let filtered = _.cloneDeep(this.preprocessedImagesBak);
268330
if (this.selectedImageFilter.value === "excludeBaseImages" || this.selectedImageFilter === "excludeBaseImages") {

yarn.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8433,6 +8433,11 @@ flat@^5.0.2:
84338433
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
84348434
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
84358435

8436+
flat@^6.0.1:
8437+
version "6.0.1"
8438+
resolved "https://registry.yarnpkg.com/flat/-/flat-6.0.1.tgz#09070cf918293b401577f20843edeadf4d3e8755"
8439+
integrity sha512-/3FfIa8mbrg3xE7+wAhWeV+bd7L2Mof+xtZb5dRDKZ+wDvYJK4WDYeIOuOhre5Yv5aQObZrlbRmk3RTSiuQBtw==
8440+
84368441
flatted@^3.2.9:
84378442
version "3.3.3"
84388443
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358"
@@ -12089,6 +12094,11 @@ papaparse@^5.2.0:
1208912094
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.5.2.tgz#fb67cc5a03ba8930cb435dc4641a25d6804bd4d7"
1209012095
integrity sha512-PZXg8UuAc4PcVwLosEEDYjPyfWnTEhOrUfdv+3Bx+NuAb+5NhDmXzg5fHWmdCh1mP5p7JAZfFr3IMQfcntNAdA==
1209112096

12097+
papaparse@^5.5.3:
12098+
version "5.5.3"
12099+
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.5.3.tgz#07f8994dec516c6dab266e952bed68e1de59fa9a"
12100+
integrity sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==
12101+
1209212102
param-case@^3.0.4:
1209312103
version "3.0.4"
1209412104
resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"

0 commit comments

Comments
 (0)