def get_released_findings(project_name: str,
                          attrs: str = '') -> List[Dict[str, FindingType]]:
    """Get all the findings that has been released."""
    key_expression = Key('project_name').eq(project_name.lower())
    filtering_exp = Attr('releaseDate').exists()
    query_attrs = {
        'FilterExpression': filtering_exp,
        'IndexName': 'project_findings',
        'KeyConditionExpression': key_expression
    }
    if attrs and 'releaseDate' not in attrs:
        query_attrs['ProjectionExpression'] = attrs + ', releaseDate'
    if not attrs:
        query_attrs['ProjectionExpression'] = 'finding_id'
    response = FINDINGS_TABLE.query(**query_attrs)
    findings = response.get('Items', [])
    while response.get('LastEvaluatedKey'):
        query_attrs['ExclusiveStartKey'] = response['LastEvaluatedKey']
        response = FINDINGS_TABLE.query(**query_attrs)
        findings += response.get('Items', [])
    findings = [get_finding(finding.get('finding_id')) for finding in findings]
    findings_released = [
        get_finding(finding.get('finding_id')) for finding in findings
        if util.validate_release_date(finding)
    ]
    return findings_released
    def test_create_msj_finding_pending(self):
        not_new_treatment_finding = get_finding('422286126')
        new_treatment_finding = get_finding('436992569')

        test_data = create_msj_finding_pending(not_new_treatment_finding)
        expected_output = ''
        assert test_data == expected_output

        test_data = create_msj_finding_pending(new_treatment_finding)
        expected_output = u'FIN.S.0038. Fuga de información de negocio'
        assert expected_output in test_data
    def test_format_data(self):
        finding_id = '422286126'
        finding_to_test = get_finding(finding_id)
        test_data = list(format_data(finding_to_test).keys())
        expected_keys = [
            'context', 'modifiedSeverityScope', 'availabilityRequirement',
            'evidence', 'releaseDate', 'availabilityImpact', 'exploit',
            'modifiedPrivilegesRequired', 'verificationRequestDate',
            'modifiedAttackVector', 'testType', 'id', 'affectedSystems',
            'attackVectorDesc', 'requirements', 'severity', 'cvssBasescore',
            'userInteraction', 'actor', 'cvssEnv', 'privilegesRequired',
            'interested', 'treatmentJustification', 'treatment', 'projectName',
            'finding', 'confidentialityImpact', 'integrityRequirement',
            'remediationLevel', 'cwe', 'leader',
            'modifiedConfidentialityImpact', 'files',
            'modifiedUserInteraction', 'attackComplexity', 'attackVector',
            'reportConfidence', 'cvssTemporal', 'remediated', 'clientProject',
            'compromisedAttrs', 'findingType', 'exploitable',
            'confidentialityRequirement', 'records', 'recordsNumber',
            'modifiedAttackComplexity', 'treatmentManager', 'severityScope',
            'cvssVersion', 'analyst', 'subscription', 'reportDate',
            'effectSolution', 'reportLevel', 'verificationDate', 'scenario',
            'severityCvss', 'modifiedAvailabilityImpact', 'age',
            'vulnerability', 'findingId', 'threat', 'lastVulnerability',
            'integrityImpact', 'modifiedIntegrityImpact', 'relatedFindings',
            'exploitability'
        ]

        assert True
def get_finding(finding_id: str) -> Dict[str, FindingType]:
    """Retrieves and formats finding attributes"""
    finding = finding_dal.get_finding(finding_id)
    if not finding or not validate_finding(finding=finding):
        raise FindingNotFound()

    return finding_utils.format_data(finding)
def update_treatment_in_vuln(finding_id: str,
                             updated_values: Dict[str, str]) -> bool:
    new_values = cast(
        Dict[str, FindingType], {
            'treatment': updated_values.get('treatment', ''),
            'treatment_justification': updated_values.get('justification'),
            'acceptance_date': updated_values.get('acceptance_date'),
        })
    if new_values['treatment'] == 'NEW':
        new_values['treatment_manager'] = None
    vulns = get_vulnerabilities(finding_id)
    resp = True
    for vuln in vulns:
        if 'treatment_manager' not in [vuln, new_values]:
            new_values[
                'treatment_manager'] = vuln_domain.set_treatment_manager(
                    str(new_values.get('treatment', '')),
                    str(updated_values.get('user', '')),
                    finding_dal.get_finding(finding_id),
                    user_domain.get_data(str(updated_values.get('user')),
                                         'role') == 'customeradmin',
                    str(updated_values.get('user', '')))
        result_update_treatment = \
            vuln_dal.update(finding_id, str(vuln.get('UUID', '')), new_values)
        if not result_update_treatment:
            resp = False
    return resp
def add_vuln_to_dynamo(item: Dict[str, str], specific: str, vuln: str,
                       finding_id: str, info) -> bool:
    """Add vulnerability to dynamo."""
    historic_state = []
    last_finding_state = cast(
        List[Dict[str, str]],
        finding_dal.get_finding(finding_id)['historic_treatment'])[-1]
    where = item.get('where', '')
    vulnerability = cast(
        List[Dict[str, str]],
        vuln_dal.get(finding_id,
                     vuln_type=vuln,
                     where=where,
                     specific=specific))
    response = False
    tzn = pytz.timezone(settings.TIME_ZONE)  # type: ignore
    current_day = datetime.now(tz=tzn).today().strftime('%Y-%m-%d %H:%M:%S')
    user_data = cast(UserType, util.get_jwt_content(info.context))
    email = str(user_data['user_email'])
    if vulnerability:
        response = update_vuln_state(info, vulnerability, item, finding_id,
                                     current_day)
    else:
        data: Dict[str, FindingType] = {}
        data['vuln_type'] = vuln
        data['where'] = where
        data['specific'] = specific
        data['finding_id'] = finding_id
        data['UUID'] = str(uuid.uuid4())
        data['treatment'] = 'NEW'
        if last_finding_state['treatment'] != 'NEW':
            data['treatment_manager'] = last_finding_state.get('user', '')
        if item.get('state'):
            if util.is_api_token(user_data):
                historic_state.append({
                    'date':
                    current_day,
                    'state':
                    item.get('state', ''),
                    'origin':
                    item.get('origin', ''),
                    'approval_status':
                    'PENDING',
                    'analyst':
                    'api-{email}'.format(email=email)
                })
            else:
                historic_state.append({
                    'date': current_day,
                    'state': item.get('state', ''),
                    'analyst': email
                })

            data['historic_state'] = historic_state
            response = vuln_dal.create(data)
        else:
            util.cloudwatch_log(
                info.context,
                'Security: Attempted to add vulnerability without state')
    return response
def validate_finding(finding_id: Union[str, int] = 0,
                     finding: Dict[str, FindingType] = None) -> bool:
    """Validate if a finding is not deleted."""
    if not finding:
        finding = finding_dal.get_finding(str(finding_id))
    historic_state = cast(List[Dict[str, str]],
                          finding.get('historic_state', [{}]))
    return historic_state[-1].get('state', '') != 'DELETED'
 def test_get_by_time_range(self):
     finding = get_finding('422286126')
     first_day = '2019-01-01 12:00:00'
     last_day = '2019-06-30 23:59:59'
     vuln = get_vulnerabilities('422286126')[0]
     test_data = get_by_time_range(
         finding, vuln, first_day, last_day
     )
     expected_output = 1
     assert test_data == expected_output
def request_verification(finding_id: str, user_email: str, user_fullname: str,
                         justification: str, vuln_ids: List[str]) -> bool:
    finding = finding_dal.get_finding(finding_id)
    vulnerabilities = get_by_ids(finding_id, vuln_ids)
    vulnerabilities = [
        validate_requested_verification(vuln) for vuln in vulnerabilities
    ]
    vulnerabilities = [validate_closed(vuln) for vuln in vulnerabilities]
    if not vulnerabilities:
        raise VulnNotFound()
    comment_id = int(round(time() * 1000))
    tzn = pytz.timezone(settings.TIME_ZONE)  # type: ignore
    today = datetime.now(tz=tzn).today().strftime('%Y-%m-%d %H:%M:%S')
    historic_verification = cast(List[Dict[str, Union[str, int, List[str]]]],
                                 finding.get('historic_verification', []))
    historic_verification.append({
        'date': today,
        'user': user_email,
        'status': 'REQUESTED',
        'comment': comment_id,
        'vulns': vuln_ids
    })
    update_finding = finding_dal.update(
        finding_id, {'historic_verification': historic_verification})
    comment_data = {
        'comment_type': 'verification',
        'content': justification,
        'created': today,
        'email': user_email,
        'finding_id': int(finding_id),
        'fullname': user_fullname,
        'modified': today,
        'parent': 0,
    }
    comment_dal.create(comment_id, comment_data)
    update_vulns = [
        vuln_dal.request_verification(vuln) for vuln in vulnerabilities
    ]
    if all(update_vulns) and update_finding:
        finding_utils.send_remediation_email(
            user_email, finding_id, str(finding.get('finding', '')),
            str(finding.get('project_name', '')), justification)
        project_users = project_dal.get_users(
            str(finding.get('project_name', '')))
        notifications.notify_mobile(
            project_users, t('notifications.remediated.title'),
            t('notifications.remediated.content',
              finding=finding.get('finding'),
              project=str(finding.get('project_name', '')).upper()))
    else:
        rollbar.report_message('Error: An error occurred remediating', 'error')

    return all(update_vulns)
def verify_vulnerabilities(finding_id: str, user_email: str,
                           user_fullname: str, info,
                           parameters: Dict[str, FindingType]) -> bool:
    finding = finding_dal.get_finding(finding_id)
    vuln_ids = \
        cast(List[str], parameters.get('open_vulns', [])) + \
        cast(List[str], parameters.get('closed_vulns', []))
    vulnerabilities = get_by_ids(finding_id, vuln_ids)
    vulnerabilities = [validate_verify(vuln) for vuln in vulnerabilities]
    vulnerabilities = [validate_closed(vuln) for vuln in vulnerabilities]
    if not vulnerabilities:
        raise VulnNotFound()
    tzn = pytz.timezone(settings.TIME_ZONE)  # type: ignore
    today = datetime.now(tz=tzn).today().strftime('%Y-%m-%d %H:%M:%S')
    comment_id = int(round(time() * 1000))
    historic_verification = cast(List[Dict[str, Union[str, int, List[str]]]],
                                 finding.get('historic_verification', []))
    historic_verification.append({
        'date': today,
        'user': user_email,
        'status': 'VERIFIED',
        'comment': comment_id,
        'vulns': vuln_ids
    })
    update_finding = finding_dal.update(
        finding_id, {'historic_verification': historic_verification})
    comment_data: comment_dal.CommentType = {
        'comment_type': 'verification',
        'content': parameters.get('justification', ''),
        'created': today,
        'email': user_email,
        'finding_id': int(finding_id),
        'fullname': user_fullname,
        'modified': today,
        'parent': 0,
    }
    comment_dal.create(comment_id, comment_data)
    success = [vuln_dal.verify_vulnerability(vuln) for vuln in vulnerabilities]
    if all(success) and update_finding:
        success = verify(info, finding_id,
                         cast(List[Dict[str, str]], vulnerabilities),
                         cast(List[str], parameters.get('closed_vulns', [])),
                         today)
    else:
        rollbar.report_message('Error: An error occurred verifying', 'error')
    return all(success)
    def test_format_vulnerabilities(self):
        act_finding = get_finding('422286126')
        positive_delta = 1
        neutral_delta = 0
        negative_delta = -1

        test_data = format_vulnerabilities(positive_delta, act_finding)
        expected_output = 'FIN.S.0051. Weak passwords reversed (+1)'
        assert test_data == expected_output

        test_data = format_vulnerabilities(neutral_delta, act_finding)
        expected_output = ''
        assert test_data == expected_output

        test_data = format_vulnerabilities(negative_delta, act_finding)
        expected_output = 'FIN.S.0051. Weak passwords reversed (-1)'
        assert test_data == expected_output
def verify(info, finding_id: str, vulnerabilities: List[Dict[str, str]],
           closed_vulns: List[str], date) -> List[bool]:
    finding = finding_dal.get_finding(finding_id)
    success = [
        update_vuln_state(info, [vuln], {'state': 'closed'}, finding_id, date)
        for vuln in vulnerabilities if vuln.get('UUID') in closed_vulns
    ]
    finding_utils.send_finding_verified_email(
        finding_id, str(finding.get('finding', '')),
        str(finding.get('project_name', '')))
    project_users = project_dal.get_users(str(finding.get('project_name', '')))
    notifications.notify_mobile(
        project_users, t('notifications.verified.title'),
        t('notifications.verified.content',
          finding=str(finding.get('finding', '')),
          project=str(finding.get('project_name', '')).upper()))

    return success
def mask_finding(finding_id: str) -> bool:
    finding = finding_dal.get_finding(finding_id)
    finding = finding_utils.format_data(finding)

    attrs_to_mask = [
        'affected_systems', 'attack_vector_desc', 'effect_solution',
        'related_findings', 'risk', 'threat', 'treatment', 'treatment_manager',
        'vulnerability'
    ]
    finding_result = finding_dal.update(
        finding_id, {attr: 'Masked'
                     for attr in attrs_to_mask})

    evidence_prefix = '{}/{}'.format(finding['projectName'], finding_id)
    evidence_result = all([
        finding_dal.remove_evidence(file_name)
        for file_name in finding_dal.search_evidence(evidence_prefix)
    ])
    finding_dal.update(
        finding_id, {
            'files': [{
                'file_url': 'Masked',
                'name': 'Masked',
                'description': 'Masked'
            } for _ in cast(List[Dict[str, str]], finding['evidence'])]
        })

    comments = comment_dal.get_comments('comment', int(finding_id))
    comments_result = all([
        comment_dal.delete(comment['finding_id'], comment['user_id'])
        for comment in comments
    ])

    vulns_result = all([
        vuln_domain.mask_vuln(finding_id, str(vuln['UUID']))
        for vuln in vuln_domain.get_vulnerabilities(finding_id)
    ])

    success = all(
        [finding_result, evidence_result, comments_result, vulns_result])
    util.invalidate_cache(finding_id)

    return success
def update_treatments(vulnerabilities: List[str], finding_id: str,
                      updated_values: Dict[str, FindingType], info,
                      is_customer_admin: bool) -> bool:
    """Update treatments data in vulnerability"""
    user_data = util.get_jwt_content(info.context)
    finding = finding_dal.get_finding(finding_id)
    updated_values['treatment'] = cast(
        List[Dict[str,
                  str]], finding.get('historic_treatment'))[-1]['treatment']
    updated_values['treatment_manager'] = \
        set_treatment_manager(
            str(updated_values.get('treatment', '')),
            str(updated_values.get('treatment_manager', '')),
            finding, is_customer_admin, user_data['user_email'])
    updated_values.pop('external_bts', None)
    updated_values.pop('vulnerabilities', None)
    if updated_values.get('tag') == '':
        updated_values.pop('tag', None)
    return update_treatment_vuln(vulnerabilities, finding_id, updated_values,
                                 info)
 def test_validate_future_releases(self):
     finding_released = get_finding('475041513')
     assert not validate_future_releases(finding_released)
 def test_validate_release_date(self):
     finding = get_finding('422286126')
     assert validate_release_date(finding)
 def test_get_last_vuln(self):
     finding = get_finding('422286126')
     test_data = get_last_vuln(finding)
     expected_output = datetime(2018, 7, 9).date()
     assert test_data == expected_output