diff --git a/monkey/common/data/zero_trust_consts.py b/monkey/common/data/zero_trust_consts.py index b6a8c8c33..c55ee160d 100644 --- a/monkey/common/data/zero_trust_consts.py +++ b/monkey/common/data/zero_trust_consts.py @@ -12,7 +12,7 @@ STATUS_POSITIVE = u"Positive" STATUS_INCONCLUSIVE = u"Inconclusive" STATUS_CONCLUSIVE = u"Conclusive" # Don't change order! -TEST_STATUSES = [STATUS_CONCLUSIVE, STATUS_INCONCLUSIVE, STATUS_POSITIVE, STATUS_UNEXECUTED] +ORDERED_TEST_STATUSES = [STATUS_CONCLUSIVE, STATUS_INCONCLUSIVE, STATUS_POSITIVE, STATUS_UNEXECUTED] TEST_DATA_ENDPOINT_ELASTIC = u"unencrypted_data_endpoint_elastic" TEST_DATA_ENDPOINT_HTTP = u"unencrypted_data_endpoint_http" diff --git a/monkey/monkey_island/cc/models/finding.py b/monkey/monkey_island/cc/models/finding.py index d67b10247..5ee014cfb 100644 --- a/monkey/monkey_island/cc/models/finding.py +++ b/monkey/monkey_island/cc/models/finding.py @@ -4,7 +4,7 @@ Define a Document Schema for Zero Trust findings. from mongoengine import Document, StringField, EmbeddedDocumentListField -from common.data.zero_trust_consts import TEST_STATUSES, TESTS, TESTS_MAP, EXPLANATION_KEY, PILLARS_KEY +from common.data.zero_trust_consts import ORDERED_TEST_STATUSES, TESTS, TESTS_MAP, EXPLANATION_KEY, PILLARS_KEY # Dummy import for mongoengine. # noinspection PyUnresolvedReferences from event import Event @@ -19,7 +19,7 @@ class Finding(Document): """ # SCHEMA test = StringField(required=True, choices=TESTS) - status = StringField(required=True, choices=TEST_STATUSES) + status = StringField(required=True, choices=ORDERED_TEST_STATUSES) events = EmbeddedDocumentListField(document_type=Event) # LOGIC diff --git a/monkey/monkey_island/cc/resources/reporting/report.py b/monkey/monkey_island/cc/resources/reporting/report.py index 84e458398..fba129e65 100644 --- a/monkey/monkey_island/cc/resources/reporting/report.py +++ b/monkey/monkey_island/cc/resources/reporting/report.py @@ -27,7 +27,11 @@ class Report(flask_restful.Resource): return ReportService.get_report() elif report_type == ZERO_TRUST_REPORT_TYPE: if report_data == REPORT_DATA_PILLARS: - return jsonify(ZeroTrustService.get_pillars_grades()) + return jsonify({ + "summary": ZeroTrustService.get_pillars_summary(), + "grades": ZeroTrustService.get_pillars_grades() + } + ) elif report_data == REPORT_DATA_DIRECTIVES_STATUS: return jsonify(ZeroTrustService.get_directives_status()) elif report_data == REPORT_DATA_FINDINGS: diff --git a/monkey/monkey_island/cc/services/reporting/zero_trust_service.py b/monkey/monkey_island/cc/services/reporting/zero_trust_service.py index 7a4a5ce43..835f869ea 100644 --- a/monkey/monkey_island/cc/services/reporting/zero_trust_service.py +++ b/monkey/monkey_island/cc/services/reporting/zero_trust_service.py @@ -7,13 +7,13 @@ class ZeroTrustService(object): @staticmethod def get_pillars_grades(): pillars_grades = [] - all_findings = Finding.objects() for pillar in PILLARS: - pillars_grades.append(ZeroTrustService.__get_pillar_grade(pillar, all_findings)) + pillars_grades.append(ZeroTrustService.__get_pillar_grade(pillar)) return pillars_grades @staticmethod - def __get_pillar_grade(pillar, all_findings): + def __get_pillar_grade(pillar): + all_findings = Finding.objects() pillar_grade = { "pillar": pillar, STATUS_CONCLUSIVE: 0, @@ -66,7 +66,7 @@ class ZeroTrustService(object): all_statuses |= set(Finding.objects(test=test).distinct("status")) for status in all_statuses: - if TEST_STATUSES.index(status) < TEST_STATUSES.index(worst_status): + if ORDERED_TEST_STATUSES.index(status) < ORDERED_TEST_STATUSES.index(worst_status): worst_status = status return worst_status @@ -88,7 +88,7 @@ class ZeroTrustService(object): def __get_lcd_worst_status_for_test(all_findings_for_test): current_status = STATUS_UNEXECUTED for finding in all_findings_for_test: - if TEST_STATUSES.index(finding.status) < TEST_STATUSES.index(current_status): + if ORDERED_TEST_STATUSES.index(finding.status) < ORDERED_TEST_STATUSES.index(current_status): current_status = finding.status return current_status @@ -115,3 +115,23 @@ class ZeroTrustService(object): def __get_events_as_dict(events): return [json.loads(event.to_json()) for event in events] + @staticmethod + def get_pillars_summary(): + results = { + STATUS_CONCLUSIVE: [], + STATUS_INCONCLUSIVE: [], + STATUS_POSITIVE: [], + STATUS_UNEXECUTED: [] + } + for pillar in PILLARS: + results[ZeroTrustService.__get_status_for_pillar(pillar)].append(pillar) + + return results + + @staticmethod + def __get_status_for_pillar(pillar): + grade = ZeroTrustService.__get_pillar_grade(pillar) + for status in ORDERED_TEST_STATUSES: + if grade[status] > 0: + return status + return STATUS_UNEXECUTED diff --git a/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js b/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js index 737e524fe..3bc0e38e1 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/ZeroTrustReportPage.js @@ -2,7 +2,7 @@ import React from 'react'; import {Button, Col} from 'react-bootstrap'; import AuthComponent from '../AuthComponent'; import ReportHeader, {ReportTypes} from "../report-components/common/ReportHeader"; -import PillarGrades from "../report-components/zerotrust/PillarGrades"; +import PillarsOverview from "../report-components/zerotrust/PillarOverview"; import FindingsTable from "../report-components/zerotrust/FindingsTable"; import {SinglePillarDirectivesStatus} from "../report-components/zerotrust/SinglePillarDirectivesStatus"; import {MonkeysStillAliveWarning} from "../report-components/common/MonkeysStillAliveWarning"; @@ -60,9 +60,10 @@ class ZeroTrustReportPageComponent extends AuthComponent { if (this.stillLoadingDataFromServer()) { content = ; } else { + console.log(this.state.pillars); const pillarsSection =

Pillars Overview

- +
; const directivesSection =
diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarGrades.js b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarOverview.js similarity index 63% rename from monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarGrades.js rename to monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarOverview.js index 15e38607c..0636ab679 100644 --- a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarGrades.js +++ b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarOverview.js @@ -1,6 +1,7 @@ import React, {Component} from "react"; import {PillarLabel} from "./PillarLabel"; import PaginatedTable from "../common/PaginatedTable"; +import {PillarsSummary} from "./PillarsSummary"; const columns = [ { @@ -17,10 +18,14 @@ const columns = [ } ]; -class PillarGrades extends Component { +class PillarOverview extends Component { render() { - return ; + return (
+ +
+ +
); } } -export default PillarGrades; +export default PillarOverview; diff --git a/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarsSummary.js b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarsSummary.js new file mode 100644 index 000000000..e029b50e6 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/report-components/zerotrust/PillarsSummary.js @@ -0,0 +1,29 @@ +import React, {Component, Fragment} from "react"; +import {PillarLabel} from "./PillarLabel"; + +export class PillarsSummary extends Component { + render() { + return (
+ {this.getStatusSummary("Conclusive")} + {this.getStatusSummary("Inconclusive")} + {this.getStatusSummary("Positive")} + {this.getStatusSummary("Unexecuted")} +
); + } + + getStatusSummary(status) { + console.log(this.props.pillars); + if (this.props.pillars[status].length > 0) { + return +

{status}

+

+ { + this.props.pillars[status].map((pillar) => { + return + }) + } +

+
+ } + } +}