def test_valid_alert(): """Alert Processor Input Validation - Valid Alert Structure""" # Default valid alert to test valid_alert = _get_alert() # Test with a valid alert structure assert_true(validate_alert(valid_alert))
def test_metadata_non_string_type(): """Alert Processor Input Validation - Metadata Non-String""" # Default valid alert to be modified invalid_metadata_non_string = _get_alert() # metadata > non-string value validation invalid_metadata_non_string['log_type'] = 4.5 # Test with invalid metadata non-string value assert_false(validate_alert(invalid_metadata_non_string))
def test_outputs_value_type(): """Alert Processor Input Validation - Metadata Outputs Bad Value Type""" # Default valid alert to be modified invalid_metadata_outputs = _get_alert() # metadata > outputs value validation invalid_metadata_outputs['outputs'] = ['good', 100] # Test with invalid metadata outputs value assert_false(validate_alert(invalid_metadata_outputs))
def test_outputs_type(): """Alert Processor Input Validation - Metadata Outputs Bad Type""" # Default valid alert to be modified invalid_metadata_outputs = _get_alert() # metadata > outputs type validation invalid_metadata_outputs['outputs'] = {'bad': 'value'} # Test with invalid metadata outputs type assert_false(validate_alert(invalid_metadata_outputs))
def test_metadata_source_value(): """Alert Processor Input Validation - Source Entity Value""" # Default valid alert to be modified invalid_metadata_source = _get_alert() # metadata > source value validation invalid_metadata_source['source_entity'] = 100 # Test with invalid metadata source values assert_false(validate_alert(invalid_metadata_source))
def test_invalid_record(): """Alert Processor Input Validation - Invalid Alert Record""" # Default valid alert to be modified invalid_alert = _get_alert() # metadata > source value validation invalid_alert['record'] = 100 # Test with invalid metadata source values assert_false(validate_alert(invalid_alert))
def test_alert_keys(): """Alert Processor Input Validation - Alert Keys Missing""" # Default valid alert to be modified missing_alert_key = _get_alert() # Alter 'metadata' keys to break validation (not all required keys) missing_alert_key.pop('rule_name') # Test with invalid metadata keys assert_false(validate_alert(missing_alert_key))
def run(alert, region, function_name, config): """Send an Alert to its described outputs. Args: alert (dict): dictionary representating an alert with the following structure: { 'record': record, 'rule_name': rule.rule_name, 'rule_description': rule.rule_function.__doc__, 'log_source': str(payload.log_source), 'log_type': payload.type, 'outputs': rule.outputs, 'source_service': payload.service, 'source_entity': payload.entity } region (str): The AWS region of the currently executing Lambda function function_name (str): The name of the lambda function config (dict): The loaded configuration for outputs from conf/outputs.json Yields: (bool, str): Dispatch status and name of the output to the handler """ if not validate_alert(alert): LOGGER.error('Invalid alert format:\n%s', json.dumps(alert, indent=2)) return LOGGER.debug('Sending alert to outputs:\n%s', json.dumps(alert, indent=2)) # strip out unnecessary keys and sort alert = _sort_dict(alert) outputs = alert['outputs'] # Get the output configuration for this rule and send the alert to each for output in set(outputs): try: service, descriptor = output.split(':') except ValueError: LOGGER.error( 'Improperly formatted output [%s]. Outputs for rules must ' 'be declared with both a service and a descriptor for the ' 'integration (ie: \'slack:my_channel\')', output) continue if service not in config or descriptor not in config[service]: LOGGER.error('The output \'%s\' does not exist!', output) continue # Retrieve the proper class to handle dispatching the alerts of this services output_dispatcher = get_output_dispatcher(service, region, function_name, config) if not output_dispatcher: continue LOGGER.debug('Sending alert to %s:%s', service, descriptor) sent = False try: sent = output_dispatcher.dispatch(descriptor=descriptor, rule_name=alert['rule_name'], alert=alert) except Exception as err: # pylint: disable=broad-except LOGGER.exception( 'An error occurred while sending alert ' 'to %s:%s: %s. alert:\n%s', service, descriptor, err, json.dumps(alert, indent=2)) # Yield back the result to the handler yield sent, output
def test_valid_alert_type(): """Alert Processor Input Validation - Invalid Alert Type""" assert_false(validate_alert('not-a-real-alert-object'))
def test_valid_alert(): """Alert Processor Input Validation - Valid Alert Structure""" # Test with a valid alert structure assert_true(validate_alert(get_alert()))