def test_calculate_cvss2_basescore(self):
     severity = {
         'confidentialityImpact': 0,
         'integrityImpact': 0.275,
         'availabilityImpact': 0,
         'accessComplexity': 0.61,
         'authentication': 0.704,
         'accessVector': 1
     }
     cvss_version = '2'
     cvss_basescore = cvss.calculate_cvss_basescore(
         severity, finding_utils.CVSS_PARAMETERS['2'], cvss_version)
     cvss_basescore_test = Decimal(4.3).quantize(Decimal('0.1'))
     assert cvss_basescore == cvss_basescore_test
 def test_calculate_cvss3_scope_unchanged_basescore(self):
     severity = {
         'confidentialityImpact': 0.22,
         'integrityImpact': 0.22,
         'availabilityImpact': 0,
         'severityScope': 0,
         'attackVector': 0.85,
         'attackComplexity': 0.77,
         'privilegesRequired': 0.62,
         'userInteraction': 0.85
     }
     cvss_version = '3.1'
     cvss_basescore = cvss.calculate_cvss_basescore(
         severity, finding_utils.CVSS_PARAMETERS['3.1'], cvss_version)
     cvss_basescore_test = Decimal(5.4).quantize(Decimal('0.1'))
     assert cvss_basescore == cvss_basescore_test
 def test_calculate_cvss2_temporal(self):
     severity = {
         'confidentialityImpact': 0,
         'integrityImpact': 0.275,
         'availabilityImpact': 0,
         'accessComplexity': 0.61,
         'authentication': 0.704,
         'accessVector': 1,
         'exploitability': 0.95,
         'resolutionLevel': 0.95,
         'confidenceLevel': 0.95
     }
     cvss_version = '2'
     cvss_basescore = cvss.calculate_cvss_basescore(
         severity, finding_utils.CVSS_PARAMETERS['2'], cvss_version)
     cvss_temporal = cvss.calculate_cvss_temporal(severity, cvss_basescore,
                                                  cvss_version)
     cvss_temporal_test = Decimal(3.7).quantize(Decimal('0.1'))
     assert cvss_temporal == cvss_temporal_test
 def test_calculate_cvss3_scope_unchanged_temporal(self):
     severity = {
         'confidentialityImpact': 0.22,
         'integrityImpact': 0.22,
         'availabilityImpact': 0,
         'severityScope': 0,
         'attackVector': 0.85,
         'attackComplexity': 0.77,
         'privilegesRequired': 0.62,
         'userInteraction': 0.85,
         'exploitability': 0.97,
         'remediationLevel': 0.97,
         'reportConfidence': 1
     }
     cvss_version = '3.1'
     cvss_basescore = cvss.calculate_cvss_basescore(
         severity, finding_utils.CVSS_PARAMETERS['3.1'], cvss_version)
     cvss_temporal = cvss.calculate_cvss_temporal(severity,
                                                  float(cvss_basescore),
                                                  cvss_version)
     cvss_temporal_test = Decimal(5.1).quantize(Decimal('0.1'))
     assert cvss_temporal == cvss_temporal_test
def format_data(finding: Dict[str, FindingType]) -> Dict[str, FindingType]:
    finding = {
        util.snakecase_to_camelcase(attribute): finding.get(attribute)
        for attribute in finding
    }

    is_draft = 'releaseDate' not in finding
    if is_draft:
        finding['age'] = 0
        finding['cvssVersion'] = finding.get('cvssVersion', '2')
    else:
        finding['age'] = util.calculate_datediff_since(
            cast(datetime, finding['releaseDate'])).days
    finding['exploitable'] = forms_utils.is_exploitable(
        float(str(finding.get('exploitability', ''))), str(finding.get('cvssVersion', ''))) == 'Si'

    historic_verification = cast(List[Dict[str, str]], finding.get('historicVerification', [{}]))
    finding['remediated'] = \
        (historic_verification[-1].get('status') == 'REQUESTED' and
         not historic_verification[-1].get('vulns', []))

    vulns = vuln_dal.get_vulnerabilities(str(finding.get('findingId', '')))
    open_vulns = \
        [vuln for vuln in vulns
         if cast(List[Dict[str, str]], vuln.get('historic_state', [{}]))[-1].get(
             'state') == 'open']
    remediated_vulns = \
        [vuln for vuln in open_vulns
         if cast(List[Dict[str, str]], vuln.get('historic_verification', [{}]))[-1].get(
             'status') == 'REQUESTED']
    finding['newRemediated'] = len(open_vulns) == len(remediated_vulns)
    finding['verified'] = len(remediated_vulns) == 0
    finding_files = cast(List[Dict[str, str]], finding.get('files'))
    finding['evidence'] = {
        'animation': _get_evidence('animation', finding_files),
        'evidence1': _get_evidence('evidence_route_1', finding_files),
        'evidence2': _get_evidence('evidence_route_2', finding_files),
        'evidence3': _get_evidence('evidence_route_3', finding_files),
        'evidence4': _get_evidence('evidence_route_4', finding_files),
        'evidence5': _get_evidence('evidence_route_5', finding_files),
        'exploitation': _get_evidence('exploitation', finding_files)
    }
    finding['compromisedAttrs'] = finding.get('records', '')
    finding['records'] = _get_evidence('fileRecords', finding_files)
    finding['exploit'] = _get_evidence('exploit', finding_files)

    cvss_fields = {
        '2': ['accessComplexity', 'accessVector', 'authentication',
              'availabilityImpact', 'availabilityRequirement',
              'collateralDamagePotential', 'confidenceLevel',
              'confidentialityImpact', 'confidentialityRequirement',
              'exploitability', 'findingDistribution', 'integrityImpact',
              'integrityRequirement', 'resolutionLevel'],
        '3.1': ['attackComplexity', 'attackVector', 'availabilityImpact',
                'availabilityRequirement', 'confidentialityImpact',
                'confidentialityRequirement', 'exploitability',
                'integrityImpact', 'integrityRequirement',
                'modifiedAttackComplexity', 'modifiedAttackVector',
                'modifiedAvailabilityImpact', 'modifiedConfidentialityImpact',
                'modifiedIntegrityImpact', 'modifiedPrivilegesRequired',
                'modifiedUserInteraction', 'modifiedSeverityScope',
                'privilegesRequired', 'remediationLevel', 'reportConfidence',
                'severityScope', 'userInteraction']
    }
    finding['severity'] = {
        field: cast(str, float(str(finding.get(field, 0))))
        for field in cvss_fields[str(finding['cvssVersion'])]
    }
    base_score = cvss.calculate_cvss_basescore(
        cast(Dict[str, float], finding['severity']), CVSS_PARAMETERS[str(finding['cvssVersion'])],
        str(finding['cvssVersion']))
    finding['severityCvss'] = cvss.calculate_cvss_temporal(
        cast(Dict[str, float], finding['severity']), base_score, str(finding['cvssVersion']))

    return finding
def save_severity(finding: Dict[str, FindingType]) -> bool:
    """Organize severity metrics to save in dynamo."""
    cvss_version: str = str(finding.get('cvssVersion', ''))
    cvss_parameters = finding_utils.CVSS_PARAMETERS[cvss_version]
    if cvss_version == '3.1':
        severity_fields = [
            'attackVector', 'attackComplexity', 'privilegesRequired',
            'userInteraction', 'severityScope', 'confidentialityImpact',
            'integrityImpact', 'availabilityImpact', 'exploitability',
            'remediationLevel', 'reportConfidence',
            'confidentialityRequirement', 'integrityRequirement',
            'availabilityRequirement', 'modifiedAttackVector',
            'modifiedAttackComplexity', 'modifiedPrivilegesRequired',
            'modifiedUserInteraction', 'modifiedSeverityScope',
            'modifiedConfidentialityImpact', 'modifiedIntegrityImpact',
            'modifiedAvailabilityImpact'
        ]
        severity: Dict[str, FindingType] = \
            {util.camelcase_to_snakecase(k): Decimal(str(finding.get(k)))
             for k in severity_fields}
        unformatted_severity = {
            k: float(str(finding.get(k)))
            for k in severity_fields
        }
        privileges = cvss.calculate_privileges(
            unformatted_severity['privilegesRequired'],
            unformatted_severity['severityScope'])
        unformatted_severity['privilegesRequired'] = privileges
        severity['privileges_required'] = \
            Decimal(privileges).quantize(Decimal('0.01'))
        modified_priviles = cvss.calculate_privileges(
            unformatted_severity['modifiedPrivilegesRequired'],
            unformatted_severity['modifiedSeverityScope'])
        unformatted_severity['modifiedPrivilegesRequired'] = modified_priviles
        severity['modified_privileges_required'] = \
            Decimal(modified_priviles).quantize(Decimal('0.01'))
    else:
        severity_fields = [
            'accessVector', 'accessComplexity', 'authentication',
            'exploitability', 'confidentialityImpact', 'integrityImpact',
            'availabilityImpact', 'resolutionLevel', 'confidenceLevel',
            'collateralDamagePotential', 'findingDistribution',
            'confidentialityRequirement', 'integrityRequirement',
            'availabilityRequirement'
        ]
        severity = {
            util.camelcase_to_snakecase(k): Decimal(str(finding.get(k)))
            for k in severity_fields
        }
        unformatted_severity = {
            k: float(str(finding.get(k)))
            for k in severity_fields
        }
    severity['cvss_basescore'] = cvss.calculate_cvss_basescore(
        unformatted_severity, cvss_parameters, cvss_version)
    severity['cvss_temporal'] = cvss.calculate_cvss_temporal(
        unformatted_severity, float(cast(Decimal, severity['cvss_basescore'])),
        cvss_version)
    severity['cvss_env'] = cvss.calculate_cvss_environment(
        unformatted_severity, cvss_parameters, cvss_version)
    severity['cvss_version'] = cvss_version
    response = finding_dal.update(str(finding.get('id', '')), severity)
    return response