def validate_actions(actions, dereferencer, app_name): from walkoff.appgateway import get_app_action from walkoff.appgateway import get_all_actions_for_app defined_actions = get_all_actions_for_app(app_name) seen = set() for action_name, action in actions.items(): if action['run'] not in defined_actions: raise InvalidApi('Action {0} has "run" property {1} ' 'which is not defined in App {2}'.format( action_name, action['run'], app_name)) action = dereferencer(action) action_params = dereferencer(action.get('parameters', [])) event = action.get('event', '') if action_params: validate_action_params(action_params, dereferencer, app_name, action_name, get_app_action(app_name, action['run']), event=event) if 'default_return' in action: if action['default_return'] not in action.get('returns', []): raise InvalidApi( 'Default return {} not in defined return codes {}'.format( action['default_return'], action.get('returns', []).keys())) validate_app_action_return_codes(action.get('returns', []), app_name, action_name) seen.add(action['run']) if seen != set(defined_actions): logger.warning( 'App {0} has defined the following actions which do not have a corresponding API: ' '{1}'.format(app_name, (set(defined_actions) - seen)))
def validate_data_in_param(params, data_in_param_name, message_prefix): data_in_param = next( (param for param in params if param['name'] == data_in_param_name), None) if data_in_param is None: raise InvalidApi('{0} has a data_in param {1} ' 'for which it does not have a ' 'corresponding parameter'.format( message_prefix, data_in_param_name)) elif not data_in_param.get('required', False): raise InvalidApi( '{0} has a data_in param {1} which is not marked as required in the api. ' 'Add "required: true" to parameter specification for {1}'.format( message_prefix, data_in_param_name))
def validate_condition_transform_params(spec, app_name, action_type, defined_actions, dereferencer): from walkoff.appgateway import get_transform from walkoff.appgateway import get_condition seen = set() for action_name, action in spec.items(): action = dereferencer(action) action_params = dereferencer(action.get('parameters', [])) if action['run'] not in defined_actions: raise InvalidApi('{0} action {1} has a "run" param {2} ' 'which is not defined'.format( action_type, action_name, action['run'])) data_in_param_name = action['data_in'] validate_data_in_param( action_params, data_in_param_name, '{0} action {1}'.format(action_type, action_name)) if action_type == 'Condition': function_ = get_condition(app_name, action['run']) else: function_ = get_transform(app_name, action['run']) validate_action_params(action_params, dereferencer, action_type, action_name, function_) seen.add(action['run']) if seen != set(defined_actions): logger.warning( 'Global {0}s have defined the following actions which do not have a corresponding API: ' '{1}'.format(action_type.lower(), (set(defined_actions) - seen)))
def validate_action_params(parameters, dereferencer, app_name, action_name, action_func, event=''): seen = set() for parameter in parameters: parameter = deref(parameter, dereferencer) name = parameter['name'] if name in seen: raise InvalidApi('Duplicate parameter {0} in api for {1} ' 'for action {2}'.format(name, app_name, action_name)) seen.add(name) if hasattr(action_func, '__arg_names'): method_params = list(action_func.__arg_names) else: method_params = get_function_arg_names(action_func) if method_params and method_params[0] == 'self': method_params.pop(0) if event: method_params.pop(0) if action_func.__event_name != event: logger.warning( 'In app {0} action {1}, event documented {2} does not match ' 'event specified {3}'.format(app_name, action_name, event, action_func.__event_name)) if not seen == set(method_params): only_in_api = seen - set(method_params) only_in_definition = set(method_params) - seen message = ( 'Discrepancy between defined parameters in API and in method definition ' 'for app {0} action {1}.'.format(app_name, action_name)) if only_in_api: message += ' Only in API: {0}.'.format(only_in_api) if only_in_definition: message += ' Only in definition: {0}'.format(only_in_definition) raise InvalidApi(message)
def validate_app_action_return_codes(return_codes, app, action): reserved = [ return_code for return_code in return_codes if return_code in reserved_return_codes ] if reserved: message = 'App {0} action {1} has return codes {2} which are reserved'.format( app, action, reserved) logger.error(message) raise InvalidApi(message)
def convert_json(spec, param_in, message_prefix): if 'type' in spec: parameter_type = spec['type'] if parameter_type in TYPE_MAP: try: return convert_primitive_type(param_in, parameter_type) except ValueError: message = ( '{0} has invalid input. ' 'Input {1} could not be converted to type {2}'.format( message_prefix, param_in, parameter_type)) logger.error(message) raise InvalidArgument(message) elif parameter_type == 'array': return convert_array(spec, param_in, message_prefix) elif parameter_type == 'object': return __convert_json(spec, param_in, message_prefix) else: raise InvalidApi('{0} has invalid api'.format(message_prefix)) elif 'schema' in spec: return convert_json(spec['schema'], param_in, message_prefix) else: raise InvalidApi('{0} has invalid api'.format(message_prefix))
def validate_definition(definition, dereferencer, definition_name=None): definition = dereferencer(definition) if 'allOf' in definition: for inner_definition in definition['allOf']: validate_definition(inner_definition, dereferencer) else: required = definition.get('required', []) properties = definition.get('properties', {}).keys() extra_properties = list(set(required) - set(properties)) if extra_properties: raise InvalidApi("Required list of properties for definition " "{0} not defined: {1}".format( definition_name, extra_properties))