def _count_subquery(rh_account_id):
     # pylint: disable=singleton-comparison
     return (SystemVulnerabilities.select(
         SystemVulnerabilities.cve_id.alias("cve_id_"),
         fn.Count(SystemVulnerabilities.id).alias("systems_affected_"),
         fn.Sum(
             Case(None, ((SystemVulnerabilities.status_id !=
                          CveAccountData.status_id, 1), ),
                  0)).alias("systems_status_divergent_")
     ).join(
         SystemPlatform,
         on=((SystemVulnerabilities.system_id == SystemPlatform.id) &
             (SystemPlatform.rh_account_id == rh_account_id) &
             (SystemPlatform.opt_out == False) &  # noqa: E712
             (SystemPlatform.stale == False) &  # noqa: E712
             (SystemPlatform.when_deleted.is_null(True)))).join(
                 CveAccountData,
                 JOIN.LEFT_OUTER,
                 on=((SystemVulnerabilities.cve_id == CveAccountData.cve_id)
                     & (CveAccountData.rh_account_id == rh_account_id))).
             where(SystemVulnerabilities.rh_account_id == rh_account_id).
             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))
Example #2
0
 def _build_update_condition(systems, status_cve_list):
     # pylint: disable=singleton-comparison
     return ((SystemVulnerabilities.system_id << systems) &
             (SystemVulnerabilities.cve_id << (CveMetadata.select(
                 CveMetadata.id).where(CveMetadata.cve << status_cve_list)))
             & ((SystemVulnerabilities.mitigation_reason.is_null(True)) |
                (SystemVulnerabilities.rule_id << (InsightsRule.select(
                    InsightsRule.id).where(InsightsRule.active == True)))) &
             ((SystemVulnerabilities.when_mitigated.is_null(True)) |
              (SystemVulnerabilities.rule_id <<
               (InsightsRule.select(InsightsRule.id).where(
                   InsightsRule.active == True)))  # noqa: E712
              ))
 def handle_get(cls, **kwargs):
     try:
         rule_id = InsightsRule.select(InsightsRule.id).where(
             InsightsRule.name == kwargs['rule_id']).get()
     except DoesNotExist:
         return cls.format_exception(
             'Rule %s does not exist' % kwargs['rule_id'], 404)
     data = Playbook.select(
         Playbook.description, Playbook.play,
         Playbook.version).where(Playbook.rule_id == rule_id).dicts()
     return {'data': [playbook for playbook in data]}  # pylint: disable=bad-option-value,unnecessary-comprehension
Example #4
0
    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))).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))).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])

        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))).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 handle_get(cls, **kwargs):
        # pylint: disable=singleton-comparison, too-many-branches, too-many-statements
        retval = {
            'cves_total': 0,
            'cves_by_severity': {
                '0to3.9': {
                    'percentage': 0,
                    'count': 0,
                    'known_exploits': 0
                },
                '4to7.9': {
                    'percentage': 0,
                    'count': 0,
                    'known_exploits': 0
                },
                '8to10': {
                    'percentage': 0,
                    'count': 0,
                    'known_exploits': 0
                },
                'na': {
                    'percentage': 0,
                    'count': 0,
                    'known_exploits': 0
                }
            },
            'exploited_cves_count': 0,
            'system_count': 0,
            'recent_cves': {
                'last7days': 0,
                'last30days': 0,
                'last90days': 0
            },
            'recent_rules': [],
            'rules_cves_total': 0,
        }

        args_desc = [
            {'arg_name': 'tags', 'convert_func': parse_tags},
            {'arg_name': 'sap_system', 'convert_func': None},
            {'arg_name': 'sap_sids', 'convert_func': None}
        ]
        args = cls._parse_arguments(kwargs, args_desc)
        cyndi_request = is_cyndi_request(args)
        rh_account, cve_cache_from, cve_cache_keepalive = get_account_data(connexion.context['user'])
        retval['system_count'] = get_system_count(rh_account, True, [filter_types.SYSTEM_TAGS, filter_types.SYSTEM_SAP, filter_types.SYSTEM_SAP_SIDS], args)

        # 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 + systems are not filtered + cache exists
        if not DISABLE_ACCOUNT_CACHE and not cyndi_request and cve_cache_from:
            active_cves_subquery = (CveAccountCache
                                    .select(CveAccountCache.cve_id.alias("cve_id_"))
                                    .where(CveAccountCache.rh_account_id == rh_account))
        else:
            active_cves_subquery = (SystemVulnerabilities
                                    .select(fn.Distinct(SystemVulnerabilities.cve_id).alias("cve_id_"))
                                    .join(SystemPlatform, on=((SystemVulnerabilities.system_id == SystemPlatform.id) &
                                                              (SystemPlatform.rh_account_id == rh_account) &
                                                              (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)))
                                    .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)))))
            if cyndi_request:
                active_cves_subquery = cyndi_join(active_cves_subquery)
                active_cves_subquery = apply_filters(active_cves_subquery, args,
                                                     [filter_types.SYSTEM_TAGS, filter_types.SYSTEM_SAP, filter_types.SYSTEM_SAP_SIDS], {})

        query = (CveMetadata
                 .select(CveMetadata.cve,
                         fn.COALESCE(CveMetadata.cvss3_score, CveMetadata.cvss2_score).alias('cvss_score'),
                         CveMetadata.public_date,
                         CveMetadata.id,
                         CveMetadata.exploits)
                 .join(active_cves_subquery, on=(CveMetadata.id == active_cves_subquery.c.cve_id_))
                 .dicts())

        cve_data = [(cve["cvss_score"], cve["public_date"], cve["exploits"]) for cve in query]

        retval["cves_total"] = len(cve_data)
        retval["exploited_cves_count"] = len([row[2] for row in cve_data if row[2] is True])

        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)
        rules_date = today - timedelta(days=CFG.dashboard_rules_age)

        for cvss_score, public_date, exploit in cve_data:
            if cvss_score is None:
                retval["cves_by_severity"]["na"]["count"] += 1
                if exploit:
                    retval["cves_by_severity"]["na"]["known_exploits"] += 1
            elif cvss_score < 4:
                retval["cves_by_severity"]["0to3.9"]["count"] += 1
                if exploit:
                    retval["cves_by_severity"]["0to3.9"]["known_exploits"] += 1
            elif 4 <= cvss_score < 8:
                retval["cves_by_severity"]["4to7.9"]["count"] += 1
                if exploit:
                    retval["cves_by_severity"]["4to7.9"]["known_exploits"] += 1
            elif cvss_score >= 8:
                retval["cves_by_severity"]["8to10"]["count"] += 1
                if exploit:
                    retval["cves_by_severity"]["8to10"]["known_exploits"] += 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

        rounded_percentage = round_to_100_percent([v['count'] for v in retval['cves_by_severity'].values()])

        for indx, keys in enumerate(retval['cves_by_severity']):
            retval['cves_by_severity'][keys]['percentage'] = rounded_percentage[indx]

        if not DISABLE_ACCOUNT_CACHE and not cyndi_request and cve_cache_from:
            rules_breakdown = (CveAccountCache.select(fn.COUNT(fn.Distinct(CveAccountCache.cve_id)).alias("rules_cves_count"))
                               .join(CveRuleMapping, on=(CveAccountCache.cve_id == CveRuleMapping.cve_id))
                               .join(InsightsRule, on=((CveRuleMapping.rule_id == InsightsRule.id) & (InsightsRule.active == True) & (~InsightsRule.rule_only)))
                               .where(CveAccountCache.rh_account_id == rh_account))
        else:
            rules_breakdown = (SystemVulnerabilities.select(fn.COUNT(fn.Distinct(SystemVulnerabilities.cve_id)).alias('rules_cves_count'))
                               .join(CveRuleMapping, on=(SystemVulnerabilities.cve_id == CveRuleMapping.cve_id))
                               .join(InsightsRule, on=((CveRuleMapping.rule_id == InsightsRule.id) & (InsightsRule.active == True) & (~InsightsRule.rule_only)))
                               .join(SystemPlatform, on=((SystemVulnerabilities.system_id == SystemPlatform.id) & (SystemPlatform.rh_account_id == rh_account) &
                                                         (SystemPlatform.when_deleted.is_null(True)) &
                                                         (SystemPlatform.stale == False) & (SystemPlatform.opt_out == False) &  # noqa: E712
                                                         (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))
                               )

            if cyndi_request:
                rules_breakdown = cyndi_join(rules_breakdown)
                rules_breakdown = apply_filters(rules_breakdown, args, [filter_types.SYSTEM_TAGS, filter_types.SYSTEM_SAP, filter_types.SYSTEM_SAP_SIDS], {})
        rules_breakdown = rules_breakdown.first()

        retval['rules_cves_total'] = rules_breakdown.rules_cves_count

        if not DISABLE_ACCOUNT_CACHE and not cyndi_request and cve_cache_from:
            counts_query = (RuleAccountCache.select(RuleAccountCache.rule_id.alias("rule_id_"),
                                                    RuleAccountCache.systems_affected.alias("systems_affected_"))
                                            .where(RuleAccountCache.rh_account_id == rh_account))
        else:
            counts_query = (SystemVulnerabilities
                            .select(SystemVulnerabilities.rule_id.alias("rule_id_"),
                                    fn.Count(fn.Distinct(SystemVulnerabilities.system_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.rule_id << InsightsRule.select(InsightsRule.id).where((InsightsRule.active == True)
                                                                                                                & (~InsightsRule.rule_only)))
                                   & (SystemVulnerabilities.mitigation_reason.is_null(True)))
                            .group_by(SystemVulnerabilities.rule_id))
            if cyndi_request:
                counts_query = cyndi_join(counts_query)
                counts_query = apply_filters(counts_query, args, [filter_types.SYSTEM_TAGS, filter_types.SYSTEM_SAP, filter_types.SYSTEM_SAP_SIDS], {})

        recent_rules = (InsightsRule.select(InsightsRule.description_text.alias('name'),
                                            InsightsRule.summary_text.alias('description'),
                                            counts_query.c.systems_affected_.alias('systems_affected'),
                                            InsightsRule.rule_impact.alias('severity'),
                                            InsightsRule.kbase_node_id.alias('node_id'),
                                            fn.ARRAY_AGG(fn.Distinct(CveMetadata.cve)).alias('associated_cves'),
                                            InsightsRule.name.alias('id'),
                                            InsightsRule.publish_date.alias('public_date'))
                        .join(CveRuleMapping, on=(InsightsRule.id == CveRuleMapping.rule_id))
                        .join(counts_query, on=(InsightsRule.id == counts_query.c.rule_id_))
                        .join(CveMetadata, on=(CveRuleMapping.cve_id == CveMetadata.id))
                        .where((InsightsRule.publish_date >= rules_date) & (InsightsRule.active == True) & (~InsightsRule.rule_only))  # noqa: E712
                        .group_by(InsightsRule.description_text, InsightsRule.publish_date, InsightsRule.rule_impact, InsightsRule.kbase_node_id,
                                  SQL('systems_affected'), InsightsRule.name, InsightsRule.publish_date, InsightsRule.summary_text)
                        .order_by(InsightsRule.publish_date.desc(), InsightsRule.rule_impact, InsightsRule.description_text)
                        .dicts())

        recent_rules = apply_filters(recent_rules, args, [], {"count_subquery": counts_query})

        for rule in recent_rules:
            retval['recent_rules'].append(rule)

        return retval