diff --git a/package.json b/package.json index 664c77c..f660abb 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "@kubernetes/client-node": "^1.3.0", "@rancher/components": "^0.3.0-alpha.1", "@rancher/shell": "3.0.5-rc.8", + "file-saver": "^2.0.5", "vue": "^3.5.17", "vue-router": "^4.5.0", "vuex": "^4.1.0" diff --git a/pkg/sbombastic-image-vulnerability-scanner/components/RegistryDetailScanTable.vue b/pkg/sbombastic-image-vulnerability-scanner/components/RegistryDetailScanTable.vue index 1ca1797..1a791b8 100644 --- a/pkg/sbombastic-image-vulnerability-scanner/components/RegistryDetailScanTable.vue +++ b/pkg/sbombastic-image-vulnerability-scanner/components/RegistryDetailScanTable.vue @@ -29,6 +29,7 @@ :namespaced="false" :row-actions="false" :table-actions="false" + :sub-rows-description="false" :search="false" :headers="headers" :rows="scanHistory" diff --git a/pkg/sbombastic-image-vulnerability-scanner/components/RegistryDetails.vue b/pkg/sbombastic-image-vulnerability-scanner/components/RegistryDetails.vue index 491bf10..9614f66 100644 --- a/pkg/sbombastic-image-vulnerability-scanner/components/RegistryDetails.vue +++ b/pkg/sbombastic-image-vulnerability-scanner/components/RegistryDetails.vue @@ -76,28 +76,22 @@ }, methods: { async loadData(isForceLoading = false) { - await this.$store.dispatch('cluster/find', { type: RESOURCE.REGISTRY, id: `${this.$route.params.ns}/${this.$route.params.id}`, opt: {force: isForceLoading} }); - if (this.$store.getters['cluster/canList'](RESOURCE.SCAN_JOB)) { - await this.$store.dispatch('cluster/findAll', { type: RESOURCE.SCAN_JOB, opt: {force: isForceLoading} }); - } - this.scanHistory = []; - - let registry = this.$store.getters['cluster/byId'](RESOURCE.REGISTRY, `${this.$route.params.ns}/${this.$route.params.id}`); - let scanJobs = this.$store.getters['cluster/all'](RESOURCE.SCAN_JOB).filter((rec) => { - return rec.spec.registry === registry.metadata.name; + this.registry = await this.$store.dispatch('cluster/find', { type: RESOURCE.REGISTRY, id: `${this.$route.params.ns}/${this.$route.params.id}`, opt: {force: isForceLoading} }); + this.scanHistory = (await this.$store.dispatch('cluster/findAll', { type: RESOURCE.SCAN_JOB, opt: {force: isForceLoading} })).filter((rec) => { + return rec.spec.registry === this.registry.metadata.name; }); - this.registryStatus = this.getRegistryStatus(registry); + this.registryStatus = this.scanHistory.sort((a, b) => new Date(b.status?.statusResult?.lastTransitionTime) - new Date(a.status?.statusResult?.lastTransitionTime))[0]?.status?.statusResult?.type.toLowerCase(); this.registryMetadata = [ { type: 'text', label: this.t('imageScanner.registries.configuration.meta.namespace'), - value: registry.metadata.namespace + value: this.registry.metadata.namespace }, { type: 'text', label: this.t('imageScanner.registries.configuration.meta.repositories'), - value: registry.spec.repositories?.length || 0 + value: this.registry.spec.repositories?.length || 0 }, { type: 'text', @@ -106,44 +100,18 @@ { type: 'text', label: this.t('imageScanner.registries.configuration.meta.uri'), - value: registry.spec.uri + value: this.registry.spec.uri }, { type: 'tags', - tags: registry.spec.repositories || [] + tags: this.registry.spec.repositories || [] }, { type: 'text', - value: registry.spec.scanInterval ? - this.t('imageScanner.general.schedule', { i: registry.spec.scanInterval }) : '', + value: this.registry.spec.scanInterval ? + this.t('imageScanner.general.schedule', { i: this.registry.spec.scanInterval }) : '', } ]; - - scanJobs.forEach((rec) => { - this.scanHistory.push({ - ...rec, - progress: rec.status.scannedImagesCount && rec.status.imagesCount ? Math.ceil(rec.status.scannedImagesCount / rec.status.imagesCount * 100) : 0, - status: { - ...rec.status, - statusResult: rec.status?.conditions?.filter(condition => { - return condition.status === "True"; - })[0] || { - type: "Pending", - lastTransitionTime: null, - } - } - }) - }); - this.registry = registry; - this.scanHistory = this.scanHistory.sort((a, b) => new Date(b.status?.statusResult?.lastTransitionTime) - new Date(a.status?.statusResult?.lastTransitionTime)); - this.registryStatus = this.scanHistory[0]?.status?.statusResult?.type.toLowerCase(); - }, - getRegistryStatus(registry) { - if (!registry || !registry.status || !registry.status.conditions || !registry.status.conditions.length) { - return null; - } - let status = registry.status.conditions[0].type.toLowerCase() === "discovering" ? "InProgress" : registry.status.conditions[0].type; - return status.toLowerCase(); }, }, } diff --git a/pkg/sbombastic-image-vulnerability-scanner/components/common/AmountBarBySeverity.vue b/pkg/sbombastic-image-vulnerability-scanner/components/common/AmountBarBySeverity.vue index 662ed25..501e4d7 100644 --- a/pkg/sbombastic-image-vulnerability-scanner/components/common/AmountBarBySeverity.vue +++ b/pkg/sbombastic-image-vulnerability-scanner/components/common/AmountBarBySeverity.vue @@ -12,7 +12,7 @@
{{ cveAmount.high }}
{{ cveAmount.medium }}
{{ cveAmount.low }}
-
{{ cveAmount.none }}
+
{{ cveAmount.unknown }}
@@ -44,13 +44,13 @@ }, computed: { pecentages() { - let total = this.cveAmount.critical + this.cveAmount.high + this.cveAmount.medium + this.cveAmount.low + this.cveAmount.none; + let total = this.cveAmount.critical + this.cveAmount.high + this.cveAmount.medium + this.cveAmount.low + this.cveAmount.unknown; return [ this.cveAmount.critical * 100 / total, this.cveAmount.high * 100 / total, - this.cveAmount.medium * 100 / total, + this.cveAmount.medium * 100 / total, this.cveAmount.low * 100 / total, - this.cveAmount.none * 100 / total, + this.cveAmount.unknown * 100 / total, ]; } } @@ -98,7 +98,7 @@ background-color: #FDD835; color: rgba(255, 255, 255, 0.90); } - .badge.none { + .badge.unknown { background-color: #E0E0E0; color: #717179; } diff --git a/pkg/sbombastic-image-vulnerability-scanner/config/table-headers.ts b/pkg/sbombastic-image-vulnerability-scanner/config/table-headers.ts index 0edc523..10173da 100644 --- a/pkg/sbombastic-image-vulnerability-scanner/config/table-headers.ts +++ b/pkg/sbombastic-image-vulnerability-scanner/config/table-headers.ts @@ -60,17 +60,17 @@ export const REGISTRY_SCAN_HISTORY_TABLE = [ { name: "status", labelKey: "imageScanner.registries.configuration.scanTable.header.status", - value: "status.statusResult.type", - formatter: "RegistryStatusCellBadge", - sort: "status.statusResult.type", + value: "status", + formatter: "ScanHistoryStatusCell", + sort: "status.conditions[?(@.status=='True')].type", width: 100, }, { name: "since", labelKey: "imageScanner.registries.configuration.scanTable.header.since", - value: "status.statusResult.lastTransitionTime", - formatter: "Date", - sort: "status.statusResult.lastTransitionTime:desc", + value: "status", + formatter: "ScanHistorySinceCell", + sort: "status.conditions[?(@.status=='True')].lastTransitionTime", width: 210, }, { @@ -100,9 +100,8 @@ export const REGISTRY_SCAN_HISTORY_TABLE = [ { name: "errors", labelKey: "imageScanner.registries.configuration.scanTable.header.error", - value: "status.statusResult.message", + value: "status", formatter: "ScanErrorCell", - sort: "errors", }, ]; @@ -164,7 +163,7 @@ export const IMAGE_LIST_TABLE = [ "spec.scanResult.high", "spec.scanResult.medium", "spec.scanResult.low", - "spec.scanResult.none", + "spec.scanResult.unknown", ], width: 300, }, diff --git a/pkg/sbombastic-image-vulnerability-scanner/formatters/ScanErrorCell.vue b/pkg/sbombastic-image-vulnerability-scanner/formatters/ScanErrorCell.vue index 444d1a4..6d68c79 100644 --- a/pkg/sbombastic-image-vulnerability-scanner/formatters/ScanErrorCell.vue +++ b/pkg/sbombastic-image-vulnerability-scanner/formatters/ScanErrorCell.vue @@ -12,18 +12,21 @@ export default { required: true } }, - data() { - return { - failedStatus: REGISTRY_STATUS.FAILED + computed: { + error() { + const statusResult = this.value.conditions.find(condition => { + return condition.status === "True"; + }); + return statusResult?.type.toLowerCase() === REGISTRY_STATUS.FAILED ? statusResult.message : null; } - } + }, };