Moved rule parsing methods into a separate component, added more details about rules in rule overview: added how many failed/passed/uncheck rules there are for a finding.

This commit is contained in:
VakarisZ 2021-01-12 12:40:45 +02:00
parent 5027dd4d2c
commit 7e07489807
3 changed files with 90 additions and 45 deletions

View File

@ -2,9 +2,10 @@ import React, {useState} from 'react';
import {Modal} from 'react-bootstrap'; import {Modal} from 'react-bootstrap';
import * as PropTypes from 'prop-types'; import * as PropTypes from 'prop-types';
import Pluralize from 'pluralize'; import Pluralize from 'pluralize';
import ScoutSuiteSingleRuleDropdown, {getRuleStatus} from './ScoutSuiteSingleRuleDropdown'; import ScoutSuiteSingleRuleDropdown from './ScoutSuiteSingleRuleDropdown';
import '../../../../styles/components/scoutsuite/RuleModal.scss'; import '../../../../styles/components/scoutsuite/RuleModal.scss';
import STATUSES from '../../common/consts/StatusConsts'; import STATUSES from '../../common/consts/StatusConsts';
import {getRuleCountByStatus, sortRules} from './rule-parsing/ParsingUtils';
export default function ScoutSuiteRuleModal(props) { export default function ScoutSuiteRuleModal(props) {
@ -18,46 +19,54 @@ export default function ScoutSuiteRuleModal(props) {
} }
} }
function compareRules(firstRule, secondRule) {
let firstStatus = getRuleStatus(firstRule);
let secondStatus = getRuleStatus(secondRule);
return compareRuleStatuses(firstStatus, secondStatus);
}
function compareRuleStatuses(ruleStatusOne, ruleStatusTwo) {
if (ruleStatusOne === ruleStatusTwo) {
return 0;
} else if (ruleStatusOne === STATUSES.STATUS_FAILED) {
return -1;
} else if (ruleStatusTwo === STATUSES.STATUS_FAILED) {
return 1;
} else if (ruleStatusOne === STATUSES.STATUS_VERIFY) {
return -1;
} else if (ruleStatusTwo === STATUSES.STATUS_VERIFY) {
return 1;
} else if (ruleStatusOne === STATUSES.STATUS_PASSED) {
return -1;
} else if (ruleStatusTwo === STATUSES.STATUS_PASSED) {
return 1;
}
}
function renderRuleDropdowns() { function renderRuleDropdowns() {
let dropdowns = []; let dropdowns = [];
let rules = props.scoutsuite_rules; let rules = sortRules(props.scoutsuite_rules);
rules.sort(compareRules);
rules.forEach(rule => { rules.forEach(rule => {
let dropdown = (<ScoutSuiteSingleRuleDropdown isCollapseOpen={openRuleId === rule.description} let dropdown = (<ScoutSuiteSingleRuleDropdown isCollapseOpen={openRuleId === rule.description}
toggleCallback={() => toggleRuleDropdown(rule.description)} toggleCallback={() => toggleRuleDropdown(rule.description)}
rule={rule} rule={rule}
scoutsuite_data={props.scoutsuite_data} scoutsuite_data={props.scoutsuite_data}
key={rule.description+rule.path}/>) key={rule.description + rule.path}/>)
dropdowns.push(dropdown) dropdowns.push(dropdown)
}); });
return dropdowns; return dropdowns;
} }
function getGeneralRuleOverview() {
return <>
There {Pluralize('is', props.scoutsuite_rules.length)}
&nbsp;<span className={'badge badge-primary'}>{props.scoutsuite_rules.length}</span>
&nbsp;ScoutSuite {Pluralize('rule', props.scoutsuite_rules.length)} associated with this finding.
</>
}
function getFailedRuleOverview() {
let failedRuleCnt = getRuleCountByStatus(props.scoutsuite_rules, STATUSES.STATUS_FAILED) +
+ getRuleCountByStatus(props.scoutsuite_rules, STATUSES.STATUS_VERIFY);
return <>
&nbsp;<span className={'badge badge-danger'}>{failedRuleCnt}</span>
&nbsp;failed security {Pluralize('rule', failedRuleCnt)}.
</>
}
function getPassedRuleOverview() {
let passedRuleCnt = getRuleCountByStatus(props.scoutsuite_rules, STATUSES.STATUS_PASSED);
return <>
&nbsp;<span className={'badge badge-success'}>{passedRuleCnt}</span>
&nbsp;passed security {Pluralize('rule', passedRuleCnt)}.
</>
}
function getUnexecutedRuleOverview() {
let unexecutedRuleCnt = getRuleCountByStatus(props.scoutsuite_rules, STATUSES.STATUS_UNEXECUTED);
return <>
&nbsp;<span className={'badge badge-default'}>{unexecutedRuleCnt}</span>
&nbsp;{Pluralize('rule', unexecutedRuleCnt)} {Pluralize('was', unexecutedRuleCnt)} not
checked (no relevant resources for the rule).
</>
}
return ( return (
<div> <div>
<Modal show={props.isModalOpen} onHide={() => props.hideCallback()} className={'scoutsuite-rule-modal'}> <Modal show={props.isModalOpen} onHide={() => props.hideCallback()} className={'scoutsuite-rule-modal'}>
@ -67,9 +76,10 @@ export default function ScoutSuiteRuleModal(props) {
</h3> </h3>
<hr/> <hr/>
<p> <p>
There {Pluralize('is', props.scoutsuite_rules.length)} { {getGeneralRuleOverview()}
<span className={'badge badge-primary'}>{props.scoutsuite_rules.length}</span> {getFailedRuleOverview()}
} ScoutSuite {Pluralize('rule', props.scoutsuite_rules.length)} associated with this finding. {getPassedRuleOverview()}
{getUnexecutedRuleOverview()}
</p> </p>
{renderRuleDropdowns()} {renderRuleDropdowns()}
</Modal.Body> </Modal.Body>

View File

@ -6,10 +6,10 @@ import {faChevronDown} from '@fortawesome/free-solid-svg-icons/faChevronDown'
import classNames from 'classnames'; import classNames from 'classnames';
import * as PropTypes from 'prop-types'; import * as PropTypes from 'prop-types';
import RULE_LEVELS from '../../common/consts/ScoutSuiteConsts/RuleLevels';
import STATUSES from '../../common/consts/StatusConsts'; import STATUSES from '../../common/consts/StatusConsts';
import {faCheckCircle, faCircle, faExclamationCircle} from '@fortawesome/free-solid-svg-icons'; import {faCheckCircle, faCircle, faExclamationCircle} from '@fortawesome/free-solid-svg-icons';
import RuleDisplay from './RuleDisplay'; import RuleDisplay from './RuleDisplay';
import {getRuleStatus} from './rule-parsing/ParsingUtils';
export default function ScoutSuiteSingleRuleDropdown(props) { export default function ScoutSuiteSingleRuleDropdown(props) {
@ -70,18 +70,6 @@ export default function ScoutSuiteSingleRuleDropdown(props) {
return getRuleCollapse(); return getRuleCollapse();
} }
export function getRuleStatus(rule) {
if (rule.checked_items === 0) {
return STATUSES.STATUS_UNEXECUTED
} else if (rule.items.length === 0) {
return STATUSES.STATUS_PASSED
} else if (rule.level === RULE_LEVELS.LEVEL_WARNING) {
return STATUSES.STATUS_VERIFY
} else {
return STATUSES.STATUS_FAILED
}
}
ScoutSuiteSingleRuleDropdown.propTypes = { ScoutSuiteSingleRuleDropdown.propTypes = {
isCollapseOpen: PropTypes.bool, isCollapseOpen: PropTypes.bool,

View File

@ -0,0 +1,47 @@
import STATUSES from '../../../common/consts/StatusConsts';
import RULE_LEVELS from '../../../common/consts/ScoutSuiteConsts/RuleLevels';
export function getRuleStatus(rule) {
if (rule.checked_items === 0) {
return STATUSES.STATUS_UNEXECUTED
} else if (rule.items.length === 0) {
return STATUSES.STATUS_PASSED
} else if (rule.level === RULE_LEVELS.LEVEL_WARNING) {
return STATUSES.STATUS_VERIFY
} else {
return STATUSES.STATUS_FAILED
}
}
export function getRuleCountByStatus(rules, status) {
return rules.filter(rule => getRuleStatus(rule) === status).length;
}
export function sortRules(rules) {
rules.sort(compareRules);
return rules;
}
function compareRules(firstRule, secondRule) {
let firstStatus = getRuleStatus(firstRule);
let secondStatus = getRuleStatus(secondRule);
return compareRuleStatuses(firstStatus, secondStatus);
}
function compareRuleStatuses(ruleStatusOne, ruleStatusTwo) {
if (ruleStatusOne === ruleStatusTwo) {
return 0;
} else if (ruleStatusOne === STATUSES.STATUS_FAILED) {
return -1;
} else if (ruleStatusTwo === STATUSES.STATUS_FAILED) {
return 1;
} else if (ruleStatusOne === STATUSES.STATUS_VERIFY) {
return -1;
} else if (ruleStatusTwo === STATUSES.STATUS_VERIFY) {
return 1;
} else if (ruleStatusOne === STATUSES.STATUS_PASSED) {
return -1;
} else if (ruleStatusTwo === STATUSES.STATUS_PASSED) {
return 1;
}
}