def handle_get(cls, **kwargs): # pylint: disable=singleton-comparison, too-many-branches, too-many-statements retval = { 'system_count': 0, 'cves_total': 0, 'cves_by_severity': { '0to3.9': { 'percentage': 0, 'count': 0, 'known_exploit_count': 0 }, '4to7.9': { 'percentage': 0, 'count': 0, 'known_exploit_count': 0 }, '8to10': { 'percentage': 0, 'count': 0, 'known_exploit_count': 0 }, 'na': { 'percentage': 0, 'count': 0, 'known_exploit_count': 0 } }, 'recent_cves': { 'last7days': 0, 'last30days': 0, 'last90days': 0 }, 'rules_total': 0, 'rules_by_severity': { 1: { 'rule_count': 0, 'systems_affected': 0 }, 2: { 'rule_count': 0, 'systems_affected': 0 }, 3: { 'rule_count': 0, 'systems_affected': 0 }, 4: { 'rule_count': 0, 'systems_affected': 0 }, }, 'top_cves': [], 'top_rules': [], } rh_account, cve_cache_from, cve_cache_keepalive = get_account_data(connexion.context['user']) if rh_account is None: return retval retval['system_count'] = get_system_count(rh_account) if retval['system_count'] == 0: return retval # API using cache, set keepalive for account to enable maintaining cache update_cve_cache_keepalive(rh_account, cve_cache_keepalive) # Use cache if not disabled + cache exists if not DISABLE_ACCOUNT_CACHE and cve_cache_from: count_query = (CveAccountCache .select(CveAccountCache.cve_id.alias("cve_id_"), CveAccountCache.systems_affected.alias("systems_affected_")) .where(CveAccountCache.rh_account_id == rh_account)) else: count_query = (SystemVulnerabilities .select(SystemVulnerabilities.cve_id.alias("cve_id_"), fn.Count(SystemVulnerabilities.id).alias("systems_affected_")) .join(SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id) & (SystemPlatform.rh_account_id == rh_account) & (SystemPlatform.opt_out == False) & (SystemPlatform.stale == False) & (SystemPlatform.when_deleted.is_null(True)) & (fn.COALESCE(SystemPlatform.host_type, 'null') != HostType.EDGE)) .where(SystemVulnerabilities.rh_account_id == rh_account) .where((SystemVulnerabilities.mitigation_reason.is_null(True)) | (SystemVulnerabilities.rule_id << InsightsRule.select(InsightsRule.id).where( (InsightsRule.active == False) & (~InsightsRule.rule_only)))) .where((SystemVulnerabilities.when_mitigated.is_null(True)) | (SystemVulnerabilities.rule_id << InsightsRule.select(InsightsRule.id).where( (InsightsRule.active == True) & (~InsightsRule.rule_only)))) .group_by(SystemVulnerabilities.cve_id)) count_query = cyndi_join(count_query) cve_query = (CveMetadata .select(CveMetadata.id.alias("cve_id"), fn.COALESCE(CveMetadata.cvss3_score, CveMetadata.cvss2_score).alias('cvss_score'), CveMetadata.public_date, CveMetadata.exploits) .join(count_query, JOIN.INNER, on=(CveMetadata.id == count_query.c.cve_id_)) .dicts()) cve_data = [(cve["cvss_score"], cve["public_date"], cve["exploits"]) for cve in cve_query] cves_total = len(cve_data) if cves_total == 0: return retval retval['cves_total'] = cves_total today = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0) # offset-aware last7 = today - timedelta(days=7) last30 = today - timedelta(days=30) last90 = today - timedelta(days=90) for cvss_score, public_date, exploits in cve_data: if cvss_score is None: retval["cves_by_severity"]["na"]["count"] += 1 if exploits: retval["cves_by_severity"]["na"]["known_exploit_count"] += 1 elif cvss_score < 4: retval["cves_by_severity"]["0to3.9"]["count"] += 1 if exploits: retval["cves_by_severity"]["0to3.9"]["known_exploit_count"] += 1 elif 4 <= cvss_score < 8: retval["cves_by_severity"]["4to7.9"]["count"] += 1 if exploits: retval["cves_by_severity"]["4to7.9"]["known_exploit_count"] += 1 elif cvss_score >= 8: retval["cves_by_severity"]["8to10"]["count"] += 1 if exploits: retval["cves_by_severity"]["8to10"]["known_exploit_count"] += 1 if public_date is not None: if public_date >= last7: retval["recent_cves"]["last7days"] += 1 if public_date >= last30: retval["recent_cves"]["last30days"] += 1 if public_date >= last90: retval["recent_cves"]["last90days"] += 1 cve_count_by_severity = [v['count'] for v in retval['cves_by_severity'].values()] rounded_percentage = round_to_100_percent(cve_count_by_severity) for indx, keys in enumerate(retval['cves_by_severity']): retval['cves_by_severity'][keys]['percentage'] = rounded_percentage[indx] # The algorithm searches for CVEs with cvss score between 8 and 10, and then sort by a number of affected # systems if there are not 3 CVE in the 8 to 10 range, then it looks for CVEs in 4 to 8 range, sorted by a # number of systems affected. The high-end range check is exclusive that is why 11 here. cves_limit = 3 top_cves = cls._get_top_cves_by_cvss(8.0, 11, count_query, limit=cves_limit) cls._build_top_cves(top_cves, retval) cves_count = top_cves.count() if cves_count < cves_limit: next_tier_top = cls._get_top_cves_by_cvss(4.0, 8.0, count_query, limit=cves_limit - cves_count) cls._build_top_cves(next_tier_top, retval) next_cves_count = next_tier_top.count() if next_cves_count < (cves_limit - cves_count): last_tier_top = cls._get_top_cves_by_cvss(0.0, 4.0, count_query, limit=cves_limit - (cves_count + next_cves_count)) cls._build_top_cves(last_tier_top, retval) rules_breakdown = (SystemVulnerabilities.select(fn.COUNT(fn.Distinct(InsightsRule.id)).alias('rule_count'), InsightsRule.rule_impact.alias('severity'), fn.COUNT(fn.Distinct(SystemVulnerabilities.system_id)).alias('systems_affected')) .join(InsightsRule, on=(SystemVulnerabilities.rule_id == InsightsRule.id)) .join(SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id) & (SystemPlatform.rh_account_id == rh_account) & (SystemPlatform.opt_out == False) & (SystemPlatform.stale == False) & (SystemPlatform.when_deleted.is_null(True)) & (SystemPlatform.last_evaluation.is_null(False) | SystemPlatform.advisor_evaluated.is_null(False)) & (fn.COALESCE(SystemPlatform.host_type, 'null') != HostType.EDGE)) .where(SystemVulnerabilities.rh_account_id == rh_account) .where((SystemVulnerabilities.mitigation_reason.is_null(True)) & (SystemVulnerabilities.rule_id << InsightsRule.select(InsightsRule.id).where((InsightsRule.active == True) & (~InsightsRule.rule_only)))) .group_by(InsightsRule.rule_impact) .dicts()) rules_breakdown = cyndi_join(rules_breakdown) for section in rules_breakdown: retval['rules_by_severity'][section['severity']]['rule_count'] = section['rule_count'] retval['rules_by_severity'][section['severity']]['systems_affected'] = section['systems_affected'] retval['rules_total'] = sum([item['rule_count'] for item in rules_breakdown]) if not DISABLE_ACCOUNT_CACHE and cve_cache_from: top_rules = (RuleAccountCache.select(InsightsRule.name.alias('rule_id'), InsightsRule.description_text.alias('name'), InsightsRule.rule_impact.alias('severity'), InsightsRule.summary_text.alias('description'), RuleAccountCache.systems_affected, fn.ARRAY_AGG(fn.Distinct(CveMetadata.cve)).alias('associated_cves')) .join(InsightsRule, on=(RuleAccountCache.rule_id == InsightsRule.id)) .join(CveRuleMapping, on=(InsightsRule.id == CveRuleMapping.rule_id)) .join(CveMetadata, on=(CveRuleMapping.cve_id == CveMetadata.id)) .where(RuleAccountCache.rh_account_id == rh_account) .group_by(InsightsRule.name, InsightsRule.description_text, InsightsRule.rule_impact, InsightsRule.summary_text, RuleAccountCache.systems_affected) .order_by(InsightsRule.rule_impact.desc(), RuleAccountCache.systems_affected.desc(), InsightsRule.description_text, InsightsRule.name) .limit(3) .dicts()) else: top_rules = (SystemVulnerabilities.select(InsightsRule.name.alias('rule_id'), InsightsRule.description_text.alias('name'), InsightsRule.rule_impact.alias('severity'), InsightsRule.summary_text.alias('description'), fn.COUNT(fn.Distinct(SystemVulnerabilities.system_id)).alias('systems_affected'), fn.ARRAY_AGG(fn.Distinct(CveMetadata.cve)).alias('associated_cves')) .join(InsightsRule, on=(SystemVulnerabilities.rule_id == InsightsRule.id)) .join(CveRuleMapping, on=(InsightsRule.id == CveRuleMapping.rule_id)) .join(CveMetadata, on=(CveRuleMapping.cve_id == CveMetadata.id)) .join(SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id) & (SystemPlatform.rh_account_id == rh_account) & (SystemPlatform.opt_out == False) & (SystemPlatform.stale == False) & (SystemPlatform.when_deleted.is_null(True)) & (SystemPlatform.last_evaluation.is_null(False) | SystemPlatform.advisor_evaluated.is_null(False)) & (fn.COALESCE(SystemPlatform.host_type, 'null') != HostType.EDGE)) .where(SystemVulnerabilities.rh_account_id == rh_account) .where((SystemVulnerabilities.mitigation_reason.is_null(True)) & (SystemVulnerabilities.rule_id << InsightsRule.select(InsightsRule.id).where((InsightsRule.active == True) & (~InsightsRule.rule_only)))) .group_by(InsightsRule.name, InsightsRule.description_text, InsightsRule.rule_impact, InsightsRule.summary_text) .order_by(InsightsRule.rule_impact.desc(), SQL('systems_affected desc'), InsightsRule.description_text, InsightsRule.name) .limit(3) .dicts()) top_rules = cyndi_join(top_rules) for top_rule in top_rules: retval['top_rules'].append(top_rule) return retval
def _full_query(rh_account_id, synopsis): # pylint: disable=singleton-comparison selectables = [ fn.COALESCE(CveAccountData.status_id, 0).alias('cve_status_id'), SystemPlatform.inventory_id, SystemPlatform.display_name, SystemPlatform.last_evaluation, SystemPlatform.advisor_evaluated.alias('rules_evaluation'), SystemPlatform.last_upload, SystemPlatform.stale_timestamp, SystemPlatform.stale_warning_timestamp, SystemPlatform.culled_timestamp, Status.id.alias('status_id'), Status.name.alias('status_name'), SystemVulnerabilities.status_text.alias('status_text'), SystemVulnerabilities.rule_hit_details, SystemVulnerabilities.when_mitigated, SystemVulnerabilities.first_reported, InsightsRule.name.alias('rule_id'), InsightsRule.active.alias('rule_active'), InsightsRule.description_text, InsightsRule.reason_text, InsightsRule.resolution_text, InsightsRule.kbase_node_id, InsightsRule.more_info_text, InventoryHosts.tags, InventoryHosts.updated, InventoryHosts.insights_id, OS_INFO_QUERY.alias('os'), fn.COALESCE(SystemVulnerabilities.advisory_available, True).alias('advisory_available'), fn.COALESCE( SystemVulnerabilities.remediation_type_id, remediation.PLAYBOOK.value).alias('remediation_type_id'), ] return (SystemVulnerabilities.select(*selectables).join( SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id)).join( Status, on=(SystemVulnerabilities.status_id == Status.id)).join( CveMetadata, on=(SystemVulnerabilities.cve_id == CveMetadata.id)).join( CveAccountData, JOIN.LEFT_OUTER, on=((CveAccountData.rh_account_id == rh_account_id) & (CveMetadata.id == CveAccountData.cve_id))).join( InsightsRule, JOIN.LEFT_OUTER, on=(InsightsRule.id == SystemVulnerabilities.rule_id)). where(CveMetadata.cve == synopsis).where( SystemVulnerabilities.rh_account_id == rh_account_id). where((SystemVulnerabilities.mitigation_reason.is_null(True)) | (InsightsRule.active == False) & (~InsightsRule.rule_only)).where( (SystemVulnerabilities.when_mitigated.is_null(True)) | (InsightsRule.active == True) & (~InsightsRule.rule_only)).where( (SystemPlatform.opt_out == False) & (SystemPlatform.stale == False) & (SystemPlatform.when_deleted.is_null(True))))
def get_rules_for_cves(cves: list, rh_account=None) -> dict: """Return associated rules for a CVE""" # pylint: disable=singleton-comparison, unsubscriptable-object rules_map = {} rule_cve_mapping = {} rh_account_id = None if rh_account is not None: try: rh_account_id = RHAccount.select( RHAccount.id).where(RHAccount.name == rh_account)[0] except IndexError: pass if rh_account_id is not None: subquery = ( SystemVulnerabilities.select( SystemVulnerabilities.id, SystemVulnerabilities.rule_id, SystemVulnerabilities.cve_id).join( SystemPlatform, on=((SystemVulnerabilities.system_id == SystemPlatform.id) & (SystemPlatform.when_deleted.is_null(True)) & (SystemPlatform.stale == False) & (SystemPlatform.opt_out == False) & (fn.COALESCE(SystemPlatform.host_type, 'null') != HostType.EDGE))) # noqa: E712 .where(SystemVulnerabilities.cve_id.in_(cves)).where( (SystemVulnerabilities.rh_account_id == rh_account_id) & (SystemVulnerabilities.mitigation_reason.is_null(True)))) subquery = cyndi_join(subquery) mapping = (CveRuleMapping.select(CveRuleMapping.cve_id, InsightsRule.name, InsightsRule.description_text, InsightsRule.summary_text, InsightsRule.reboot_required, InsightsRule.playbook_count, InsightsRule.change_risk, InsightsRule.kbase_node_id, InsightsRule.active, CveMetadata.cve, InsightsRule.rule_impact, InsightsRule.publish_date) .join(InsightsRule, on=(CveRuleMapping.rule_id == InsightsRule.id)) .join(CveMetadata, on=(CveRuleMapping.cve_id == CveMetadata.id)) .where((InsightsRule.active == True) & (~InsightsRule.rule_only)) # noqa: E712 .where(CveRuleMapping.rule_id.in_(CveRuleMapping.select(CveRuleMapping.rule_id).where(CveRuleMapping.cve_id.in_(cves)))).dicts()) \ if rh_account_id is None else \ (CveRuleMapping.select(CveRuleMapping.cve_id, InsightsRule.name, InsightsRule.description_text, InsightsRule.summary_text, InsightsRule.reboot_required, InsightsRule.playbook_count, InsightsRule.change_risk, InsightsRule.kbase_node_id, InsightsRule.active, CveMetadata.cve, InsightsRule.rule_impact, InsightsRule.publish_date, fn.COUNT(subquery.c.id).alias('systems_affected')) .join(InsightsRule, on=(CveRuleMapping.rule_id == InsightsRule.id)) .join(CveMetadata, on=(CveRuleMapping.cve_id == CveMetadata.id)) .join(subquery, JOIN.LEFT_OUTER, on=((subquery.c.rule_id == InsightsRule.id) & (subquery.c.cve_id == CveRuleMapping.cve_id))) .where((InsightsRule.active == True) & (~InsightsRule.rule_only)) # noqa: E712 .where(CveRuleMapping.rule_id.in_(CveRuleMapping.select(CveRuleMapping.rule_id).where(CveRuleMapping.cve_id.in_(cves)))) .group_by(CveRuleMapping.cve_id, InsightsRule.name, InsightsRule.description_text, InsightsRule.summary_text, InsightsRule.reboot_required, InsightsRule.playbook_count, InsightsRule.change_risk, InsightsRule.kbase_node_id, InsightsRule.active, CveMetadata.cve, InsightsRule.rule_impact, InsightsRule.publish_date) .dicts()) for row in mapping: rule_cve_mapping.setdefault(row['name'], []).append(row['cve']) for row in mapping: rule_detail = { 'rule_id': row['name'], 'description': row['description_text'], 'summary': row['summary_text'], 'reboot_required': row['reboot_required'], 'playbook_count': row['playbook_count'], 'change_risk': row['change_risk'], 'kbase_node_id': row['kbase_node_id'], 'associated_cves': rule_cve_mapping[row['name']], 'rule_impact': row['rule_impact'], 'publish_date': format_datetime(row['publish_date']) } if rh_account_id is not None: rule_detail['systems_affected'] = row['systems_affected'] rules_map.setdefault(row['cve_id'], []).append(rule_detail) return rules_map
def handle_patch(cls, **kwargs): """Update the 'status' field for a system/cve combination""" # pylint: disable=singleton-comparison data = kwargs['data'] in_inventory_id_list, in_cve_list, status_to_cves_map, status_text_to_cves_map = cls._prepare_data( data) try: rh_account = RHAccount.select(RHAccount.id).where( RHAccount.name == connexion.context['user']) systems = (SystemPlatform.select(SystemPlatform.id).where( SystemPlatform.rh_account_id == rh_account[0].id) ) # noqa: E712 if in_inventory_id_list is not None: systems = systems.where( SystemPlatform.inventory_id << in_inventory_id_list) rows_modified = set() # set statuses and their CVE lists for status_id, status_cve_list in status_to_cves_map.items(): status_id_update = (SystemVulnerabilities.update( status_id=status_id).where( (SystemVulnerabilities.system_id << systems) & (SystemVulnerabilities.cve_id << (CveMetadata.select(CveMetadata.id).where( CveMetadata.cve << status_cve_list)))).returning( SystemVulnerabilities.id)) rows_modified.update([row.id for row in status_id_update]) cls._update_divergent_status_count(in_cve_list, rh_account[0].id) for status_text, status_cve_list in status_text_to_cves_map.items( ): status_text_update = (SystemVulnerabilities.update( status_text=status_text).where( (SystemVulnerabilities.system_id << systems) & (SystemVulnerabilities.cve_id << (CveMetadata.select(CveMetadata.id).where( CveMetadata.cve << status_cve_list)))).returning( SystemVulnerabilities.id)) rows_modified.update([row.id for row in status_text_update]) updated_details = (SystemVulnerabilities.select( SystemPlatform.inventory_id, CveMetadata.cve).join( CveMetadata, on=(SystemVulnerabilities.cve_id == CveMetadata.id)).join( SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform. id)).where(SystemVulnerabilities.id << list( rows_modified)).dicts()) updated = [] for updated_row in updated_details: updated.append({ "inventory_id": updated_row["inventory_id"], "cve": updated_row["cve"] }) if not updated: # sysid/cve/acct combination does not exist return cls.format_exception( 'inventory_id/cve must exist and inventory_id must be visible to user', 404) except (IntegrityError, psycopg2IntegrityError, DataError) as value_error: # usually means bad-status-id LOGGER.error(str(value_error)) DB.rollback() return cls.format_exception( f'status_id={list(status_to_cves_map.keys())} is invalid', 400) except ValueError as value_error: LOGGER.exception('Error during setting status (ValueError):') DB.rollback() return cls.format_exception( f'status_text or other key value is invalid ({value_error})', 400) return {"updated": updated}
def handle_patch(cls, **kwargs): """Set status for a CVE""" data = kwargs['data'] cve_list = data['cve'] if isinstance(cve_list, str): cve_list = [cve_list] values = {} updated = [] if 'status_id' in data: values['status_id'] = data['status_id'] if 'status_text' in data: try: values['status_text'] = data['status_text'].strip() \ if data['status_text'].strip() else None except AttributeError: values['status_text'] = None if not values: return cls.format_exception( 'At least one of the "status_id" or "status_text" parameters is required.', 400) try: to_insert = [] cves = CveMetadata.select( CveMetadata.id, CveMetadata.cve).where(CveMetadata.cve << cve_list) rh_account = get_or_create_account() for cve in cves: updated.append(cve.cve) if 'status_id' in data: # refresh number of divergent statuses in CVE-system pairs # pylint: disable=singleton-comparison query = ( SystemVulnerabilities.select( fn.Count(SystemVulnerabilities.id).alias( 'systems')).join( SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id)).where( SystemPlatform.rh_account_id == rh_account[0].id).where( SystemPlatform.opt_out == False) # noqa: E712 .where(SystemVulnerabilities.cve_id == cve.id).where( SystemVulnerabilities.when_mitigated.is_null(True) ).where(SystemVulnerabilities.status_id != values.get( 'status_id', 0)).dicts()) values['systems_status_divergent'] = query[0]['systems'] to_insert.append( (cve.id, rh_account[0].id, values.get('status_id', 0), values.get('status_text', None), values.get('systems_status_divergent', 0))) if not to_insert: return cls.format_exception( 'At least one given CVE must exist', 404) (CveAccountData.insert_many( to_insert, fields=cls._fields).on_conflict( conflict_target=cls._conflict_target, preserve=[], update=values).execute()) except (IntegrityError, psycopg2IntegrityError, DataError): # usually means bad status LOGGER.exception('Error during setting status (IntegrityError):') DB.rollback() return cls.format_exception( f'status_id=%s is invalid' % data['status_id'], 400) except ValueError as value_error: LOGGER.exception('Error during setting status (ValueError):') DB.rollback() return cls.format_exception( f'status_text or other key value is invalid ({value_error})', 400) return {'updated': updated}
def handle_get(cls, **kwargs): """Gets systems affected by a CVE""" synopsis = kwargs['cve_id'] cls._cve_exists(synopsis) args_desc = [ { 'arg_name': 'status_id', 'convert_func': parse_int_list }, { 'arg_name': 'uuid', 'convert_func': None }, { 'arg_name': 'rule_presence', 'convert_func': unique_bool_list }, { 'arg_name': 'rule_key', 'convert_func': None }, { 'arg_name': 'tags', 'convert_func': parse_tags }, { 'arg_name': 'sap_system', 'convert_func': None }, { 'arg_name': 'show_advisories', 'convert_func': None }, { 'arg_name': 'advisory', 'convert_func': None }, { 'arg_name': 'sap_sids', 'convert_func': None }, { 'arg_name': 'rhel_version', 'convert_func': parse_str_list }, { 'arg_name': 'first_reported_from', 'convert_func': dateutil.parser.parse }, { 'arg_name': 'first_reported_to', 'convert_func': dateutil.parser.parse }, { 'arg_name': 'rule', 'convert_func': None }, { 'arg_name': 'advisory_available', 'convert_func': unique_bool_list }, { 'arg_name': 'remediation', 'convert_func': parse_int_list }, ] args = cls._parse_arguments(kwargs, args_desc) list_arguments = cls._parse_list_arguments(kwargs) # check if advisory parameter comes with show_advisories parameter if 'advisory' in args and args['advisory'] and ( 'show_advisories' not in args or not args['show_advisories']): raise ApplicationException( "Advisory parameter shouldn't be used without show_advisories parameter", 400) rh_account_id, _, _ = get_account_data(connexion.context['user']) system_advisories = {} patch_access = None if 'show_advisories' in args and args[ 'show_advisories'] and 'advisory' in args and args['advisory']: # pylint: disable=singleton-comparison raw_inv_ids = ( SystemVulnerabilities.select(SystemPlatform.inventory_id).join( SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id)). join(CveMetadata, on=(SystemVulnerabilities.cve_id == CveMetadata.id) ).where(CveMetadata.cve == synopsis).where( SystemVulnerabilities.rh_account_id == rh_account_id). where((SystemPlatform.opt_out == False) # noqa: E712 & (SystemPlatform.stale == False) # noqa: E712 & (SystemPlatform.when_deleted.is_null(True)) & (fn.COALESCE(SystemPlatform.host_type, 'null') != HostType.EDGE))).dicts() raw_inv_ids = [inv_id['inventory_id'] for inv_id in raw_inv_ids] # Pass advisory argument for filtering advisories list by advisory to prevent redundant patch requests advisories_list = get_advisories_per_cve_from_db(synopsis) if not has_advisory(args['advisory'], advisories_list): advisories_list = [] # get advisory data from PATCH system_advisories, patch_access = cls._get_advisories_per_system( advisories_list, raw_inv_ids) # Filter systems by advisory system_advisories = filter_by_advisory(args['advisory'], system_advisories) asys_view = cls._DB_View(rh_account_id, synopsis, list_arguments, args, args, connexion.request.path, cls._ids_only, system_advisories) systems = list(asys_view) # execute query elif 'show_advisories' in args and args['show_advisories'] and ( 'advisory' not in args or not args['advisory']): asys_view = cls._DB_View(rh_account_id, synopsis, list_arguments, args, args, connexion.request.path, cls._ids_only) systems = list(asys_view) # execute query inv_ids = [sys['inventory_id'] for sys in systems] # get advisory data from PATCH advisories_list = get_advisories_per_cve_from_db(synopsis) system_advisories, patch_access = cls._get_advisories_per_system( advisories_list, inv_ids) else: asys_view = cls._DB_View(rh_account_id, synopsis, list_arguments, args, args, connexion.request.path, cls._ids_only) systems = list(asys_view) # execute query response = {} result = [] if cls._ids_only: result = systems else: for sys in systems: if 'show_advisories' in args and args['show_advisories']: record = cls._build_attributes( sys, system_advisories.get(sys['inventory_id'], [])) result.append({ 'type': 'system', 'id': sys['inventory_id'], 'attributes': record }) else: record = cls._build_attributes(sys) result.append({ 'type': 'system', 'id': sys['inventory_id'], 'attributes': record }) response['meta'] = asys_view.get_metadata() response['meta'][ 'patch_access'] = patch_access.status if patch_access else None response['links'] = asys_view.get_pagination_links() response['data'] = cls._format_data(list_arguments["data_format"], result, ids_only=cls._ids_only) return response
def _cve_details(cls, synopsis, args): retval = cls._get_cve_details(synopsis, args) cve_details = (CveAccountData.select( BusinessRisk.name.alias('risk'), CveAccountData.business_risk_id.alias('risk_id'), CveAccountData.business_risk_text.alias('risk_text'), Status.name.alias("status"), CveAccountData.status_id.alias("status_id"), CveAccountData.status_text.alias("status_text")).join( BusinessRisk, on=(CveAccountData.business_risk_id == BusinessRisk.id)).join( Status, on=(CveAccountData.status_id == Status.id)).join( CveMetadata, on=(CveAccountData.cve_id == CveMetadata.id)).where( CveAccountData.rh_account_id == ( RHAccount.select(RHAccount.id).where( RHAccount.name == connexion.context['user']))).where( CveMetadata.cve == synopsis)).dicts() if cve_details.count(): retval['business_risk'] = cve_details[0]['risk'] retval['business_risk_id'] = cve_details[0]['risk_id'] retval['business_risk_text'] = cve_details[0]['risk_text'] retval['status'] = cve_details[0]['status'] retval['status_id'] = cve_details[0]['status_id'] retval['status_text'] = cve_details[0]['status_text'] else: retval['business_risk'] = DEFAULT_BUSINESS_RISK retval['business_risk_id'] = 0 retval['business_risk_text'] = None retval['status'] = DEFAULT_STATUS retval['status_id'] = 0 retval['status_text'] = None # add counts of systems with all statuses retval['systems_status_detail'] = {} # pylint: disable=singleton-comparison rh_account_id, _, _ = get_account_data(connexion.context['user']) status_detail = (SystemVulnerabilities.select( SystemVulnerabilities.status_id, fn.Count(SystemVulnerabilities.status_id).alias('systems') ).join(SystemPlatform, on=(SystemVulnerabilities.system_id == SystemPlatform.id)).join( CveMetadata, on=(SystemVulnerabilities.cve_id == CveMetadata.id)).join( InsightsRule, JOIN.LEFT_OUTER, on=(InsightsRule.id == SystemVulnerabilities.rule_id) ).where(CveMetadata.cve == synopsis).where( SystemVulnerabilities.rh_account_id == rh_account_id ).where( (SystemVulnerabilities.mitigation_reason.is_null(True)) | (InsightsRule.active == False) & (~InsightsRule.rule_only)).where( (SystemVulnerabilities.when_mitigated.is_null(True)) | (InsightsRule.active == True) & (~InsightsRule.rule_only)).where( (SystemPlatform.opt_out == False) & (SystemPlatform.stale == False) & (SystemPlatform.when_deleted.is_null(True)) & (fn.COALESCE(SystemPlatform.host_type, 'null') != HostType.EDGE)).group_by( SystemVulnerabilities.status_id).dicts()) divergent_systems = 0 status_detail = cyndi_join(status_detail) for row in status_detail: retval['systems_status_detail'][row['status_id']] = row['systems'] if row['status_id'] != retval['status_id']: divergent_systems += row['systems'] retval['systems_status_divergent'] = divergent_systems return retval