def update_requirements(requirements):
    """Syncs requirements in requirements table
    with the parameters that are passed"""
    requirement_ids_to_delete = []
    reqs_to_add = []
    # load requirements saved in dynamodb
    ddb_data = requirements_table.scan_all()
    requirements_from_ddb = {requirement['requirementId']: requirement for requirement in ddb_data}

    for requirement_id in requirements_from_ddb:
        if requirement_id in requirements:
            if requirements_from_ddb[requirement_id] != requirements[requirement_id]:
                reqs_to_add.append(requirements[requirement_id])
        else:
            requirement_ids_to_delete.append(requirement_id)

    for requirement_id in requirements:
        if requirement_id not in requirements_from_ddb:
            reqs_to_add.append(requirements[requirement_id])

    with requirements_table.batch_writer() as batch:
        for requirement_id in requirement_ids_to_delete:
            batch.delete_item(Key={'requirementId': requirement_id})
        for requirement in reqs_to_add:
            batch.put_item(Item=requirement)
    def test_update_requirements(self):
        """Tests for syncing requirements with those present in requirement-table"""
        # create initial requirements
        initial_requirements = {
            '111': {
                'requirementId': '111',
                'attribute': '123'
            },
            '222': {
                'requirementId': '222',
                'attribute': '123'
            },
            '333': {
                'requirementId': '333',
                'attribute': '123'
            },
        }
        load.update_requirements(initial_requirements)

        # confirm requirements we expect are in table
        requirements_in_db = sorted(requirements_table.scan_all(),
                                    key=lambda a: a['requirementId'])
        assert list(initial_requirements.values()) == requirements_in_db

        # update requirements
        updated_requirements = {
            '111': {
                'requirementId': '111',
                'attribute': '444'
            },  # modify
            '222': {
                'requirementId': '222',
                'attribute': '123'
            },  # stays same
            # delete requriement '333'
            '444': {
                'requirementId': '444',
                'attribute': '123'
            },  # new
        }
        load.update_requirements(updated_requirements)

        # confirm requirements we expect are in table
        requirements_in_db = sorted(requirements_table.scan_all(),
                                    key=lambda a: a['requirementId'])
        assert list(updated_requirements.values()) == requirements_in_db
Exemple #3
0
def get_requirements() -> Dict[RequirementId, Dict]:
    """
    Saves requirements into a cache for future use. Returns requirements indexed by requirement_id
    """
    if 'requirements' not in CACHE:
        logger.debug('Getting requirements for cache')
        CACHE['requirements'] = {
            req['requirementId']: req for req in requirements_table.scan_all() if not req.get('ignore', False)
        }
    return CACHE['requirements']
def ncr_handler(event, context):
    scan_id = event['scanId']
    user = event['userRecord']

    multivalue_querystring_parameters = event.get(
        'multiValueQueryStringParameters') or {}
    querystring_parameters = event.get('queryStringParameters') or {}
    account_ids = multivalue_querystring_parameters.get('accountId', [])
    requirement_id = querystring_parameters.get('requirementId', False)
    logger.debug('Account Ids: %s', json.dumps(account_ids, default=str))
    logger.debug('Requirement ID: %s', json.dumps(requirement_id, default=str))
    authz.require_can_read_account(user, account_ids)

    # get requirements
    if requirement_id:
        requirements = {requirement_id: requirements_table.get(requirement_id)}
    else:
        all_requirements = requirements_table.scan_all()
        requirements = {}
        for requirement in all_requirements:
            requirements[requirement['requirementId']] = requirement
    logger.debug('Requirements: %s', json.dumps(requirements, default=str))

    ncr_records, to_parse = [], []
    for account_id in account_ids:
        if isinstance(requirement_id, str):
            to_parse = ncr_table.query_all(
                IndexName='by-scanId',
                KeyConditionExpression=Key('scanId').eq(scan_id)
                & Key('rqrmntId_accntId').eq('{}#{}'.format(
                    requirement_id, account_id)))
        else:
            to_parse = ncr_table.query_all(
                KeyConditionExpression=Key('scanId').eq(scan_id)
                & Key('accntId_rsrceId_rqrmntId').begins_with(account_id))
        logger.debug('To parse: %s', json.dumps(to_parse, default=str))

        for item in to_parse:
            ncr = prepare_allowed_actions_output(
                initialize_output(scan_id, item), item, user, account_id,
                requirements[item['requirementId']])
            ncr_records.append(prepare_resource_output(ncr, item))

    return {'ncrRecords': ncr_records}
"""
Module concerned with calculation of per requirement per account score,
as well as overall account score.
"""
from collections import defaultdict

from boto3.dynamodb.types import Decimal
from boto3.dynamodb.conditions import Key

from lib.dynamodb import account_scores_table, ncr_table, requirements_table, scores_table, accounts_table
from lib.lambda_decorator.decorator import states_decorator

all_requirements = requirements_table.scan_all()


@states_decorator
def score_calc_handler(event, context):
    """
    :param event: {
        scanId: string,
        accountIds: list of accountIds,
    }
    :param context: dict
    :return: None
    """
    scan_id = event['openScan']['scanId']
    account_ids = event['load']['accountIds']
    date = scan_id[0:10]
    all_scores_to_put = []
    all_account_scores = []