mirror of https://github.com/rancher/ui.git
190 lines
5.2 KiB
JavaScript
190 lines
5.2 KiB
JavaScript
import Controller from '@ember/controller';
|
|
import { computed, get } from '@ember/object';
|
|
import { inject as service } from '@ember/service';
|
|
|
|
export default Controller.extend({
|
|
modalService: service('modal'),
|
|
router: service(),
|
|
scope: service(),
|
|
growl: service(),
|
|
intl: service(),
|
|
securityScanConfig: service(),
|
|
|
|
tableHeaders: [
|
|
{
|
|
name: 'collapse',
|
|
width: 40,
|
|
},
|
|
{
|
|
name: 'state',
|
|
sort: ['state', 'sortableId'],
|
|
translationKey: 'cis.scan.detail.table.state',
|
|
width: 100,
|
|
},
|
|
{
|
|
name: 'id',
|
|
sort: ['sortableId'],
|
|
translationKey: 'cis.scan.detail.table.number',
|
|
width: 100,
|
|
},
|
|
{
|
|
name: 'description',
|
|
sort: ['description', 'sortableId'],
|
|
translationKey: 'cis.scan.detail.table.description',
|
|
},
|
|
{
|
|
name: 'buttons',
|
|
width: 120,
|
|
}
|
|
],
|
|
sortBy: 'id',
|
|
|
|
runningClusterScans: computed.filterBy('clusterScans', 'isRunning', true),
|
|
|
|
actions: {
|
|
async runScan() {
|
|
await get(this, 'scope.currentCluster').doAction('runSecurityScan', {
|
|
failuresOnly: false,
|
|
skip: null
|
|
});
|
|
get(this, 'router').replaceWith('authenticated.cluster.cis/scan');
|
|
},
|
|
download() {
|
|
get(this, 'model.scan').send('download');
|
|
},
|
|
async delete() {
|
|
await get(this, 'modalService').toggleModal('confirm-delete', {
|
|
escToClose: true,
|
|
resources: [get(this, 'model.scan')],
|
|
onDeleteFinished: () => get(this, 'router').replaceWith('authenticated.cluster.cis/scan')
|
|
});
|
|
}
|
|
},
|
|
|
|
disableRunScanButton: computed('runningClusterScans', 'scope.currentCluster.systemProject', function() {
|
|
return get(this, 'runningClusterScans.length') > 0 || !get(this, 'scope.currentCluster.systemProject');
|
|
}),
|
|
|
|
tests: computed('model.scan.report', 'securityScanConfig.skipList', function() {
|
|
const results = get(this, 'model.scan.report.results');
|
|
|
|
if (!results) {
|
|
return [];
|
|
}
|
|
|
|
const tests = results.reduce((agg, result) => [...agg, ...result.checks], []);
|
|
|
|
return tests.map((test) => {
|
|
const state = this.getCheckState(test);
|
|
const nodeNames = get(this, 'model.scan').getNodeNamesFromNodeType(test.node_type);
|
|
const checkNodes = test.nodes || [];
|
|
const nodes = nodeNames.map((nodeName) => {
|
|
const node = get(this, 'model.nodes').findBy('nodeName', nodeName);
|
|
const nodeId = node ? node.id : null;
|
|
|
|
return {
|
|
state: this.getNodeState(test, nodeName, checkNodes),
|
|
nodeId,
|
|
name: nodeName
|
|
};
|
|
});
|
|
|
|
return {
|
|
state,
|
|
id: test.id,
|
|
sortableId: this.createSortableId(test.id),
|
|
description: test.description,
|
|
remediation: state === 'Fail' ? test.remediation : null,
|
|
nodes,
|
|
toggleSkip: () => {
|
|
this.toggleSkip(test.id)
|
|
},
|
|
skipList: get(this, 'securityScanConfig.skipList'),
|
|
_availableActions: []
|
|
};
|
|
});
|
|
}),
|
|
|
|
|
|
|
|
clusterScans: computed('model.clusterScans.@each', function() {
|
|
return get(this, 'model.clusterScans').filterBy('clusterId', get(this, 'scope.currentCluster.id'));
|
|
}),
|
|
|
|
/**
|
|
* Converts an id that looks like 1.1.9 into 000010000100009. This
|
|
* allows us to appropriately compare the ids as if they are versions
|
|
* instead of just doing a naive string comparison.
|
|
* @param {*} id
|
|
*/
|
|
createSortableId(id) {
|
|
const columnWidth = 5;
|
|
const splitId = id.split('.');
|
|
|
|
return splitId
|
|
.map((column) => {
|
|
const columnPaddingWidth = Math.max(columnWidth - column.length, 0)
|
|
|
|
return '0'.repeat(columnPaddingWidth) + column;
|
|
})
|
|
.join('');
|
|
},
|
|
|
|
toggleSkip(testId) {
|
|
this.securityScanConfig.validateSecurityScanConfig();
|
|
const isSkipped = get(this, 'securityScanConfig.skipList').indexOf(testId) !== -1;
|
|
const fn = isSkipped ? this.unskip : this.skip;
|
|
|
|
fn.call(this, testId);
|
|
},
|
|
|
|
skip(testId) {
|
|
const newSkipList = [...get(this, 'securityScanConfig.skipList'), testId];
|
|
|
|
this.securityScanConfig.editSkipList(newSkipList);
|
|
},
|
|
|
|
unskip(testId) {
|
|
const newSkipList = get(this, 'securityScanConfig.skipList').filter((skippedTestId) => skippedTestId !== testId);
|
|
|
|
this.securityScanConfig.editSkipList(newSkipList);
|
|
},
|
|
|
|
getCheckState(check) {
|
|
switch (check.state) {
|
|
case 'pass':
|
|
return 'Pass';
|
|
case 'skip':
|
|
return 'Skipped';
|
|
default:
|
|
return 'Fail';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Per the API.
|
|
* When check state is pass Pass.
|
|
* When check state is fail Fail.
|
|
* When check state is skip Skip.
|
|
* When check state is mixed fail if nodeName is in checkNodes otherwise pass
|
|
*/
|
|
getNodeState(check, nodeName, checkNodes) {
|
|
if (check.state === 'pass') {
|
|
return 'Pass';
|
|
}
|
|
|
|
if (check.state === 'fail') {
|
|
return 'Fail';
|
|
}
|
|
|
|
if (check.state === 'skip') {
|
|
return 'Skipped';
|
|
}
|
|
|
|
return checkNodes.includes(nodeName)
|
|
? 'Fail'
|
|
: 'Pass';
|
|
}
|
|
|
|
});
|