def dismiss(ipaddress, rule, autoremediate="0", profilename="DemonstrationProfile", hopperip=None): global consoleLog try: keyValueStore = redis.Redis("localhost") codeversion = keyValueStore.get("codeversion") prevConsoleLog = "" dump = keyValueStore.lrange(ipaddress, 0, -1) for item in dump: if rule in item: selected_rule_dict = json.loads(item) if selected_rule_dict.has_key('console'): prevConsoleLog = selected_rule_dict['console'] keyValueStore.lrem(ipaddress, item) break prevConsoleLog = prevConsoleLog.replace( "=================================================", "\n------ Marking rule as successful ------\n") addConsole("\nRule : " + rule + " manually marked as sucessful\n") addConsole("=================================================\n") rulestatus = {} rulestatus['rule'] = rule rulestatus['status'] = "COMPLETE" rulestatus['outcome'] = "manually marked as successful" rulestatus['console'] = prevConsoleLog + consoleLog rulestatus['profile'] = profilename rulestatus['exemode'] = autoremediate rulestatus['severity'] = loadrules.getSeverity(rule[2:]) rulestatus['codeversion'] = codeversion keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) return 1 except Exception as e: print("runrules: Dismiss: Exception " + str(e.args)) return 99
def runRules(username, ipaddress="192.168.122.17", rules=['V-38443', 'V-38488', 'V-38477', 'V-38455'], autoremediate="0", profilename="DemonstrationProfile", hopperip=None): print("runrules: runRules: starting run" + rules) global consoleLog, gw machine_reachable = True # for this version, we are assuming hopperip = None and not doing any hopping # Open an execnet link to the target ip # ipaddress = "130.211.112.245" # cloud raxak GCE ubuntu # ipaddress = "130.211.122.121" # cloud raxak GCE centOS # ipaddress = "192.168.122.17" # Local centos # ipaddress = "146.148.89.19" # cloud raxak GCE rhel-6 # Connect to the redis database keyValueStore = redis.Redis("localhost") # Archive the logs details of associated IP address archieveLogs(username, ipaddress) status = "Rules execution is in progress (" + str(os.getpid()) + ")..." keyValueStore.set(ipaddress + "status", status) codeversion = keyValueStore.get("codeversion") channel = None #Default channel value is None only gets initialized when VM access status is ALL OK. status_list = checkAccess(username, [ipaddress]) if status_list[0].has_key('access'): access_value = status_list[0]['access'] if access_value > 0: channel = connectGateway(username, ipaddress) # Added check to fix the issue git #80. if channel == None: keyValueStore.set(ipaddress + "status", "Rules execution is in progress...") # Adding the inaccessible message to console. if status_list[0].has_key('access'): access_value = status_list[0]['access'] if access_value == '-1': msg = "OS not supported" elif access_value == '-2': msg = "Unable to reach IP address" elif access_value == '-3': msg = "Unable to log in with specified userid (ssh login fails)" # elif access_value == '-4': # msg = "Insufficient execution privilege" # elif access_value == '-5': # msg = "Access check in progress" rulestatus = {} rulestatus['rule'] = "" rulestatus['status'] = "COMPLETE" rulestatus['outcome'] = "INACCESSIBLE" rulestatus['console'] = msg rulestatus['profile'] = profilename rulestatus['exemode'] = autoremediate rulestatus['severity'] = "" rulestatus['codeversion'] = codeversion keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) utc = datetime.utcnow() utc_time = datetime.strftime(utc, '%a %b %d %H:%M:%S %Y') keyValueStore.set(ipaddress + "status", "Rules execution completed on : " + utc_time) return else: # Get back the channel for the remote machine outchan = channel.receive() # get stdout piped back print("runrules: runRules: outchan = " + str(outchan)) # outchan.setcallback (lambda data: sys.stdout.write("\n> " + str(data))) outchan.setcallback(lambda data: addConsole(data)) print('runrules: runRules: received print channel and created lambda') rule_list = rules.split(' ') if not rule_list: return -1 for ii in rule_list: if not channel: return -1 i = 'checkRule' + ii[2:] print("runrules: runRules: " + i) rulestatus = {} rulestatus['rule'] = ii rulestatus['status'] = "ABORTED" rulestatus['outcome'] = "UNKNOWN" rulestatus['console'] = consoleLog consoleLog = "" rulestatus['profile'] = profilename rulestatus['exemode'] = autoremediate rulestatus['severity'] = loadrules.getSeverity(ii[2:]) rulestatus['codeversion'] = codeversion print("runrules: runRules: pushing rulestatus") keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) funcs = {} funcsdict = {} funcp = pickle.dumps(inspect.getsource(getattr(ruleset, i))) funcs[0] = 'X' funcs[1] = i funcs[2] = funcp jar = pickle.dumps(funcs) if not channel: continue try: channel.send(jar) except Exception as e: print("runrules: runRules: error sending jar, caught " + str(e.args)) print("runrules: runRules: gatway value is " + str(gw)) return try: retval = channel.receive() except EOFError as connection_lost: rulestatus['status'] = "ABORTED BY RAXAK PROTECT" rulestatus[ 'console'] = "Aborted due to connection to target machine lost." keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) machine_reachable = False break # put retval into database for future use. keyValueStore.rpop(ipaddress) if retval is None: rulestatus['outcome'] = "needs manual intervention" addConsole("Rule: " + ii + " needs manual intervention\n") elif retval == 3: # for manual (N/A) rulestatus['outcome'] = "needs manual intervention (N/A)" addConsole("Rule: " + ii + " needs manual intervention (N/A)\n") elif retval: rulestatus['outcome'] = "successful" addConsole("Rule: " + ii + " successful\n") else: if int(autoremediate): addConsole( "Rule failed, remediating rule automatically:\n") retval = remediateRule(ipaddress, ii[2:], channel) if retval is None: rulestatus['outcome'] = "needs manual intervention" retval = 2 addConsole("Rule: " + ii + " needs manual intervention\n") elif retval: rulestatus['outcome'] = "successfully remediated" addConsole("Rule: " + ii + " Successfully remediated\n") else: rulestatus[ 'outcome'] = "needs manual intervention (remediation failed)" retval = 2 addConsole( "Rule: " + ii + " needs manual intervention (remediation failed)\n" ) else: rulestatus['outcome'] = "failed" addConsole("Rule: " + ii + " failed") rulestatus['status'] = "COMPLETE" addConsole("\n=================================================\n") rulestatus['console'] = consoleLog utf8Str = "" for ruleData in rulestatus: if ruleData == "console": # Spliiting Console Output splitRuleStatus = rulestatus[ruleData].splitlines() for ele in splitRuleStatus: # Converting into unicode types, replacing errors, if any ele = unicode(ele, errors='replace') # Checking and converting all unicode types into srings if isinstance(ele, unicode): ele = ele.encode('ascii', 'ignore') ele = str(ele) utf8Str += ele + "\n" # Replacing converted utf-8 format sring into normal string rulestatus[ruleData] = utf8Str keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) utc = datetime.utcnow() utc_time = datetime.strftime(utc, '%a %b %d %H:%M:%S %Y') if machine_reachable: keyValueStore.set(ipaddress + "status", "Rules execution completed on : " + utc_time) elif machine_reachable == False: keyValueStore.set(ipaddress + "status", "Rules execution aborted by rp on : " + utc_time) gw.exit() return retval
def checkRule(username, ipaddress, rule='V-38443', autoremediate="0", profilename="DemonstrationProfile", hopperip=None): global consoleLog try: keyValueStore = redis.Redis("localhost") codeversion = keyValueStore.get("codeversion") channel = connectGateway(username, ipaddress) # get back the channel for the remote machine if channel is None: return 98 prevConsoleLog = "" dump = keyValueStore.lrange(ipaddress, 0, -1) for item in dump: if rule in item: selected_rule_dict = json.loads(item) if selected_rule_dict.has_key('console'): prevConsoleLog = selected_rule_dict['console'] keyValueStore.lrem(ipaddress, item) break prevConsoleLog = prevConsoleLog.replace( "=================================================", "\n------ Re-checking the failed security rule ------\n") i = 'checkRule' + rule[2:] rulestatus = {} rulestatus['rule'] = rule rulestatus['status'] = "ABORTED" rulestatus['outcome'] = "UNKNOWN" rulestatus['console'] = consoleLog rulestatus['profile'] = profilename rulestatus['exemode'] = autoremediate rulestatus['severity'] = loadrules.getSeverity(rule[2:]) rulestatus['codeversion'] = codeversion consoleLog = "" try: outchan = channel.receive() # get stdout piped back outchan.setcallback(lambda data: addConsole(data)) except EOFError as connection_lost: rulestatus['status'] = "ABORTED BY RAXAK PROTECT" rulestatus[ 'console'] = "Aborted due to connection to target machine lost." keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) return 98 keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) funcs = {} funcsdict = {} funcp = pickle.dumps(inspect.getsource(getattr(ruleset, i))) funcs[0] = 'X' funcs[1] = i funcs[2] = funcp try: jar = pickle.dumps(funcs) channel.send(jar) retval = channel.receive() except EOFError as connection_lost: rulestatus['status'] = "ABORTED BY RAXAK PROTECT" rulestatus[ 'console'] = "Aborted due to connection to target machine lost." keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) return 98 # put retval into database for future use. keyValueStore.rpop(ipaddress) rulestatus['status'] = "COMPLETE" if retval is None: rulestatus['outcome'] = "needs manual intervention" retval = 2 addConsole("Rule: " + rule + " needs manual intervention\n") elif retval == 3: # for manual (N/A) rulestatus['outcome'] = "needs manual intervention (N/A)" retval = 2 # for manual addConsole("Rule: " + rule + " needs manual intervention (N/A)\n") elif retval: retval = 1 rulestatus['outcome'] = "successful" addConsole("Rule: " + rule + " Successful\n") else: retval = 0 rulestatus['outcome'] = "failed" addConsole("Rule: " + rule + " failed\n") addConsole("=================================================\n") if isinstance(prevConsoleLog, unicode): prevConsoleLog = prevConsoleLog.encode('ascii', 'ignore') prevConsoleLog = str(prevConsoleLog) rulestatus['console'] = prevConsoleLog + consoleLog utf8Str = "" for ruleData in rulestatus: if ruleData == "console": # Spliiting Console Output splitRuleStatus = rulestatus[ruleData].splitlines() for ele in splitRuleStatus: # Converting into unicode types, replacing errors, if any ele = unicode(ele, errors='replace') # Checking and converting all unicode types into srings if isinstance(ele, unicode): ele = ele.encode('ascii', 'ignore') ele = str(ele) utf8Str += ele + "\n" # Replacing converted utf-8 format sring into normal string rulestatus[ruleData] = utf8Str keyValueStore.rpush(ipaddress, json.dumps(rulestatus)) return retval except Exception as e: print("runrules: checkRule : Exception " + str(e.args)) return 99
def generateReportPDF(parameter_dict): usernameIP = parameter_dict['usernameIP'] profilename = parameter_dict['profilename'] archieveLogTimestamp = parameter_dict['archieveLogTimestamp'] archieveLogTimestampGmt = parameter_dict['archieveLogTimestampGmt'] archieveLogFirst = parameter_dict['archieveLogFirst'] userid = parameter_dict['userid'] nickname = parameter_dict['getnickname'] userIpDetails = eval(cloudraxak.getIPDetails(usernameIP)) hostname = userIpDetails['hostname'] os = userIpDetails['os'] + ' Release ' + userIpDetails['os_version'] osName = userIpDetails['os'].lower() codeversion = '' if (usernameIP == nickname): servernames = usernameIP else: servernames = nickname + ' ' + '(' + usernameIP + ')' RuleSetList = cloudraxak.defaultdict(dict) latestTimestampProfile = '' latestTimestampExeMode = '' if (archieveLogFirst == 'true'): array_log = [] [ array_log.append(x) for x in cloudraxak.showrun(userid, usernameIP, '') ] latestTimestampRuleSetList = array_log else: latestTimestampRuleSetList = [ x.encode('ascii') for x in cloudraxak.showrun( userid, usernameIP, archieveLogTimestamp) ] manual_low_severity_count = [] manual_medium_severity_count = [] manual_high_severity_count = [] failed_low_severity_count = [] failed_medium_severity_count = [] failed_high_severity_count = [] success_low_severity_count = [] success_medium_severity_count = [] success_high_severity_count = [] get_low_severity = [] get_medium_severity = [] get_high_severity = [] servityExists = True get_rule_name = '' get_severity_list = [] for report in latestTimestampRuleSetList: reportDic = '' reportDic = ast.literal_eval(report) # str to dictionay conversion if ('manual' in reportDic['outcome']): RuleSetList['manual'][reportDic['rule']] = reportDic get_rule_name = reportDic['rule'] rule_num = get_rule_name.replace('V-', '') get_severity = loadrules.getSeverity(rule_num) if "low" in get_severity: manual_low_severity_count.append(get_severity) if 'medium' in get_severity: manual_medium_severity_count.append(get_severity) if 'high' in get_severity: manual_high_severity_count.append(get_severity) elif ('failed' in reportDic['outcome']): get_rule_name = reportDic['rule'] rule_num = get_rule_name.replace('V-', '') get_severity = loadrules.getSeverity(rule_num) RuleSetList['failed'][reportDic['rule']] = reportDic if 'low' in get_severity: failed_low_severity_count.append(get_severity) if 'medium' in get_severity: failed_medium_severity_count.append(get_severity) if 'high' in get_severity: failed_high_severity_count.append(get_severity) elif ('successful' in reportDic['outcome']): RuleSetList['successful'][reportDic['rule']] = reportDic get_rule_name = reportDic['rule'] rule_num = get_rule_name.replace('V-', '') get_severity = loadrules.getSeverity(rule_num) if 'low' in get_severity: success_low_severity_count.append(get_severity) if 'medium' in get_severity: success_medium_severity_count.append(get_severity) if 'high' in get_severity: success_high_severity_count.append(get_severity) else: RuleSetList['unknown'][reportDic['rule']] = reportDic latestTimestampProfile = reportDic['profile'] report_status = reportDic['status'] if 'ABORTED' in report_status: report_check_status = '(' + report_status + ')' else: report_check_status = '' latestTimestampExeMode = reportDic['exemode'] if codeversion == '': if reportDic.has_key('codeversion'): codeversion = (reportDic['codeversion'].strip()).title() else: codeversion = previouscodeversion if get_rule_name != '': manual_low_severity = len(manual_low_severity_count) manual_medium_severity = len(manual_medium_severity_count) manual_high_severity = len(manual_high_severity_count) failed_low_severity = len(failed_low_severity_count) failed_medium_severity = len(failed_medium_severity_count) failed_high_severity = len(failed_high_severity_count) success_low_severity = len(success_low_severity_count) success_medium_severity = len(success_medium_severity_count) success_high_severity = len(success_high_severity_count) manual_total_val = manual_low_severity + manual_medium_severity + manual_high_severity failed_total_val = failed_low_severity + failed_medium_severity + failed_high_severity success_total_val = success_low_severity + success_medium_severity + success_high_severity high_severity_total = manual_high_severity + failed_high_severity + success_high_severity medium_severity_total = manual_medium_severity + failed_medium_severity + success_medium_severity low_severity_total = manual_low_severity + failed_low_severity + success_low_severity success_severity_total_float = float(success_total_val) total_results = high_severity_total + medium_severity_total + low_severity_total success_severity_total_percentage = (success_severity_total_float / total_results * 100) get_success_severity_percentage = str( success_severity_total_percentage)[:9] success_severity_percentage = cloudraxak.check_decimal( get_success_severity_percentage) failed_severity_total_float = float(failed_total_val) failed_severity_total_percentage = (failed_severity_total_float / total_results * 100) get_failed_severity_percentage = str( failed_severity_total_percentage)[:9] failed_severity_percentage = cloudraxak.check_decimal( get_failed_severity_percentage) manual_severity_total_float = float(manual_total_val) manual_severity_total_percentage = (manual_severity_total_float / total_results * 100) get_manual_severity_percentage = str( manual_severity_total_percentage)[:9] manual_severity_percentage = cloudraxak.check_decimal( get_manual_severity_percentage) float_array = [] success_after_decimal = cloudraxak.code_decm( get_success_severity_percentage) failed_after_decimal = cloudraxak.code_decm( get_failed_severity_percentage) manual_after_decimal = cloudraxak.code_decm( get_manual_severity_percentage) if (get_success_severity_percentage == '100.0'): success_after_decimal = '0' if (get_failed_severity_percentage == '100.0'): failed_after_decimal = '0' if (get_manual_severity_percentage == '100.0'): manual_after_decimal = '0' float_array.append(success_after_decimal) float_array.append(failed_after_decimal) float_array.append(manual_after_decimal) get_max_list = max(float_array) get_success_severity_percentage_actual = '' get_manual_severity_percentage_actual = '' get_failed_severity_percentage_actual = '' if int(float_array[0][0]) >= 5 or get_max_list == float_array[0]: if (get_success_severity_percentage == '100.0' or get_success_severity_percentage == '0.0'): get_success_severity_percentage_add = get_success_severity_percentage else: get_success_severity_percentage_add = float( get_success_severity_percentage) + 1 get_success_severity_percentage_actual = str( get_success_severity_percentage_add) get_success_actual_value = get_success_severity_percentage_actual[: get_success_severity_percentage_actual . find( '.' )] else: get_success_severity_percentage_add = float( get_success_severity_percentage) get_success_severity_percentage_actual = str( get_success_severity_percentage_add) get_success_actual_value = get_success_severity_percentage_actual[: get_success_severity_percentage_actual . find( '.' )] if int(float_array[1][0]) >= 5 or get_max_list == float_array[1]: if (get_failed_severity_percentage == "0.0" or get_failed_severity_percentage == "100.0"): get_failed_severity_percentage_add = get_failed_severity_percentage else: get_failed_severity_percentage_add = float( get_failed_severity_percentage) + 1 get_failed_severity_percentage_actual = str( get_failed_severity_percentage_add) get_failed_actual_value = get_failed_severity_percentage_actual[: get_failed_severity_percentage_actual . find( '.' )] else: get_failed_severity_percentage_add = float( get_failed_severity_percentage) get_failed_severity_percentage_actual = str( get_failed_severity_percentage_add) get_failed_actual_value = get_failed_severity_percentage_actual[: get_failed_severity_percentage_actual . find( '.' )] if int(float_array[2][0]) >= 5 or get_max_list == float_array[2]: if (get_manual_severity_percentage == "0.0" or get_manual_severity_percentage == "100.0"): get_manual_severity_percentage_add = get_manual_severity_percentage else: get_manual_severity_percentage_add = float( get_manual_severity_percentage) + 1 get_manual_severity_percentage_actual = str( get_manual_severity_percentage_add) get_manual_actual_value = get_manual_severity_percentage_actual[: get_manual_severity_percentage_actual . find( '.' )] else: get_manual_severity_percentage_add = float( get_manual_severity_percentage) get_manual_severity_percentage_actual = str( get_manual_severity_percentage_add) get_manual_actual_value = get_manual_severity_percentage_actual[: get_manual_severity_percentage_actual . find( '.' )] if (latestTimestampExeMode == '0'): latestTimestampExeMode = 'Manual Remediation' else: latestTimestampExeMode = 'Automatic Remediation' ruleProfileList = cloudraxak.ruleTitleOnly(profilename, osName) gethostname = str(platform.uname()[1]) + "<br/>" + str( platform.dist()[0]) + " " + str(platform.dist()[1]) if (archieveLogTimestampGmt == 'Latest Execution'): report_check_status = ' (<span style="color:orange;">InProgress</span>)' else: report_check_status not_applicable_length = [] if manual_total_val > 0: for rule in sorted(RuleSetList['manual'].itervalues()): rule_id = rule['rule'] rule_num = rule_id.replace('V-', '') disaOsName = cloudraxak.getDisaOsName(osName) rule_fix = loadrules.showFix(rule_num, disaOsName) severity = loadrules.getSeverity(rule_num, disaOsName) rule_console_list = re.split( '\n', rule['console'].replace( "=================================================", '')) rule_console = '' for row in rule_console_list: if row: # rule_console = rule_console+row+"<br/>" rule_console = rule_console + row + '\n' if 'N/A' in rule_console: not_applicable_length.append(rule_console) # manual_rule_line = 'This rule is not applicable.' rule_cons = rule_console.replace('\n', '</p>') rule_status = rule['status'] rule_title = ruleProfileList[rule['rule']] manual_remediation = { 'rule': rule_id, 'severity': severity, 'console': rule_console, 'title': rule_title, 'status': rule_status, 'rulefix': rule_fix, 'os': os } else: manual_remediation = '' if failed_total_val > 0: for rule in sorted(RuleSetList['failed'].itervalues()): rule_id = rule['rule'] rule_num = rule_id.replace('V-', '') disaOsName = cloudraxak.getDisaOsName(osName) rule_fix = loadrules.showFix(rule_num, disaOsName) severity = loadrules.getSeverity(rule_num, disaOsName) rule_console_list = re.split( '\n', rule['console'].replace( "=================================================", '')) for row in rule_console_list: if row: rule_console = rule_console + row + "\n" if 'N/A' in rule_console: failed_rule_line = 'This rule is not applicable.' rule_cons = rule_console.replace("\n", "</p>") rule_status = rule['status'] rule_title = ruleProfileList[rule['rule']] failed_remediation = { 'rule': rule_id, 'severity': severity, 'console': rule_console, 'title': rule_title, 'status': rule_status, 'rulefix': rule_fix, 'os': os } else: failed_remediation = '' if success_total_val > 0: for rule in sorted(RuleSetList['successful'].itervalues()): rule_id = rule['rule'] rule_num = rule_id.replace('V-', '') disaOsName = cloudraxak.getDisaOsName(osName) severity = loadrules.getSeverity(rule_num, disaOsName) rule_console_list = re.split( '\n', rule['console'].replace( "=================================================", '')) for row in rule_console_list: if row: rule_console = rule_console + row + "\n" rule_cons = str(rule_console).replace('\n', '</p><p>') rule_status = rule['status'] rule_title = ruleProfileList[rule['rule']] success_remediation = { 'rule': rule_id, 'severity': severity, 'console': rule_console, 'title': rule_title, 'status': rule_status } else: success_remediation = '' if len(not_applicable_length) > 0: for rule in sorted(RuleSetList['manual'].itervalues()): rule_id = rule['rule'] rule_num = rule_id.replace('V-', '') disaOsName = cloudraxak.getDisaOsName(osName) rule_fix = loadrules.showFix(rule_num, disaOsName) severity = loadrules.getSeverity(rule_num, disaOsName) rule_console_list = re.split( '\n', rule['console'].replace( "=================================================", '')) for row in rule_console_list: if row: # rule_console = rule_console+row+"<br/>" rule_console = rule_console + row + '\n' if 'N/A' in rule_console: manual_rule_line = 'This rule is not applicable.' rule_cons = rule_console.replace('\n', '</p>') rule_status = rule['status'] rule_title = ruleProfileList[rule['rule']] not_applicable = { 'rule': rule_id, 'severity': severity, 'title': rule_title } else: not_applicable = '' cron_list = cloudraxak.getCronJobs(userid) for cron in cron_list: cron_dict = ast.literal_eval(cron) osInfo = { 'servernames': servernames, 'hostname': hostname, 'os': os, 'profile': latestTimestampProfile, 'executed': archieveLogTimestampGmt, 'version': codeversion, 'status': report_check_status, 'mode': latestTimestampExeMode } summary_details = { 'passed': { 'high': success_high_severity, 'low': success_low_severity, 'medium': success_medium_severity, 'total': success_total_val, 'percentage': get_success_actual_value }, 'failed': { 'high': failed_high_severity, 'low': failed_low_severity, 'medium': failed_medium_severity, 'total': failed_total_val, 'percentage': get_failed_actual_value }, 'manual': { 'high': manual_high_severity, 'low': manual_low_severity, 'medium': manual_medium_severity, 'total': manual_total_val, 'percentage': get_manual_actual_value }, 'total': { 'high': high_severity_total, 'medium': medium_severity_total, 'low': low_severity_total, 'totalresult': total_results } } ruleInfo = { 'manual': manual_remediation, 'failed': failed_remediation, 'success': success_remediation, 'notapplicable': not_applicable, 'cron': cron_dict } lastexecutionlog = lastExecution(userid, usernameIP) report_info = { 'osinfo': osInfo, 'severity': summary_details, 'rulesInfo': ruleInfo, 'lastExecution': lastexecutionlog } return report_info